Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[buckminster-dev] Introduction and Buckminster walkthrough

Everyone,

Presumably this is the first post to the buckminster-dev mailing list. I welcome you all who have signed up so far, and hope that you will have patience while we
work towards a first publically available prototype.

In response to a separate discussion originating on the eclipse.tools.jdt
newsgroup ('Public versus internal interfaces'), we thought it prudent to start off with some description of what Buckminster intends/does. So, please find a
longish tale below!

Regards,

ken1

(Kenneth Olwing)

==========================

A walkthrough of Buckminster (somewhat simplistically):

Buckminster is basically about recognizing that software are commonly
constructed out of many separate 'components'. We feel a perennial problem is to
manage the common confusion of 'how to know what versions works together'.
Ideally, we envision that a project lead only need to say to a new hire to the dev dept: 'you should work on the com.somedomain.product project', and all the dev has to do is enter 'com.somedomain.product' in their Eclipse and a suitable,
working workspace will result, even if the product is built up of
dozens/hundreds/lots of components. A 'no confusion, quickly get up to speed'
scenario.

The primary focus of Buckminster for the moment is to help the user to populate
a workspace with a suitable 'configuration' of such components (i.e. which
components, what version of said components - but also selecting different
representations of the component based on user intentions/needs/capabilities
etc). A somewhat crude analogy might be to support development of 'things' (e.g.
typically Eclipse plugins but also other component types) as conveniently as
Eclipse manages plugins/features in very dynamic manner. Note that Buckminster
not only aims at Java development, but other types as well.

There is generally no problem if you work with a monolithic codebase; just check out a single toplevel directory (which is typically trivial in most CM systems),
and off you go. This essentially applies even if the codebase is well
modularized/componentized - you still check out 'everything' every time.
This can have detrimental effects though: one problem can be that the codebase
gets so large that doing a clean build takes 'forever' (and where even an
incremental build can take a long time - probably most visible in classic
makefile scenarios). Another problem can be in the simple usecase that the
software (and development team) is roughly divided in 'framework' vs
'application' levels. Framework developers (producers) sometimes tend to have a wish to 'move on'. This can lead to changing interfaces which directly impacts the app developers (consumers) since their stuff no longer works. In a worst- case scenario the app devs have to play catch-up all the time (we call this the
consumer/producer problem).

The above problems definitively have their solutions. For example, a common
approach is to build the lower levels into libraries/jars, and check them in for
use by the higher levels. But this also carries with it management issues of
their own. There can also be difficulties with succinctly describing the
configuration. And what happens when some component owners want to do
exploratory work that shouldn't impact app devs at all at this stage (this is
particularly prevalent at the end of a release cycle when the framework is
basically frozen)? The consumer/producer issue is about letting the consumer
choose the timing of seeing change rather than having it foisted on them at
inconvenient times.

In any case, expand the monolithic case into a situation where components are
truly stored in 'different' locations - this can be as 'simple' as having a
single CVS repository with hundreds of top-level modules where valid
configurations each contains only subsets of them all. Thus, it's impractical to check out *all* modules just to work with a certain subset. But also consider
that a number of components going into a certain product may also come from
various open source projects. For best CM tracking you might want to get those
from their real repositories (which may include other CM systems such as
Subversion, Perforce...or simply just FTP sites that allows downloading of fresh
releases).

The plot thickens. In larger efforts it quickly becomes impossible for each
individual to know where all these things come from, especially given transitive
dependencies - after all, an app dev really only cares about the 'framework
component', (s)he's not really interested in the dozens of components that make up the 'frameworx component'. To top it all off, all those components come in
many versions...which one is correct?

Buckminster wants to help with this type of scenario - each component declares its dependencies and Buckminster helps extract and/or bind them together in a
workspace. It will follow dependencies and try to make sure it garners a
workspace that is 'correct' (i.e. it's the same for all involved developers,
avoiding the 'it works on my machine' syndrome).
To do this dependencies can be specified with not just a component name. It may
also involve a version selector. In the simplest case there is none, and a
typical mapping would then be to get the HEAD version. This obviously devolves to something that will not be consistent over time, but may be appropriate in certain stages of development. To be more consistent, the dependency could state '1.2.3' which (assuming the CM system is trusted) should always produce the same
thing. This is not unlike how Eclipse plugins can be matched at
deployment/runtime.

A concept of a 'resolver' is inserted 'between' abstract component names and
version selectors. It makes use of a 'resolver map' (xml) to map component names onto repository providers/locations (typically several possibilities, including
already present in the workspace, present as a plugin in the running Eclipse
instance, or something else).
A simple reason for this is where a given repository, say a CVS repo, should be accessed differently by different users - for user A, the CVSROOT should be just
a 'local' reference, while user B needs to access it using a 'pserver'
reference. In resolver parlance, they belong to different 'sites', which helps
abstract out differences between them.

There are other more advanced reasons; early on it was stated that Buckminster
would aid in selecting different component representations based on user
intentions. This is where match/source/mutability rules come in. Imagine that the developers of 'the framework component' have specified that component FOO,
version 1.2.3 is a dependency. Normally, the app dev 'framework' doesn't
care/know about this. By default, they should get a representation of FOO-1.2.3 that best matches their needs. In their case, the best match is (typically) a prebuilt library, no need to have source, and no need for it to be mutable. The resolver will start looking and try to select the representation with the best
fit. If it indeed finds such a representation on a convenient FTP server, it
will be selected as the representation to be downloaded and bound to the
workspace/component. But it can also happen that no such lib is prepared
yet...so they will get the only possible representation - the tagged source from
the repository.

OTOH, the framework dev knows FOO well and may even need to have the source
available for changing - so (s)he needs the flexibility to essentially say 'give
me the work branch 1.2.x of FOO, with source and mutable'.
In such cases, the resolver will probably find that, yes, a representation of FOO is available on the FTP ...but while it has source, it is immutable and thus
not a good fit for the query. So it goes on through the resolution and
eventually comes back to the last possibility: the actual repository source
representation.

It is here that the resolver needs to be able to peek into possible
representations and actually understand the underlying repository in order to
map version selectors properly. It's also to figure out what the component
contains so it can use the match rules correctly. Finally, it's important to
extract the dependency information so that a user can make an informed choice (interactively through a wizard) - e.g. 'if you choose v1 of component A, you
will need B and C but if you choose v2 you will also need D'.

This has been a whirlwind tour about Buckminster - no doubt I've forgotten some important points, and likely raised more questions than answered any...:-). Please
don't hesitate to ask about the murky areas.

There are other possible focus areas for Buckminster, such as having a framework that can provide help with process issues such as work cycle support; e.g. based on a given set a of known good configuration with fixed component baselines, set up work branches for a few of them, help sandbox it all, prompt to selectively rebase and then subsequently help deliver changes back to involved CM systems in
an as atomic operation as possible. But this is for
later...




Back to the top