Introduction

Krypton was inspired partially by the way assembly lines in manufacturing work to decompose a production process into the smallest possible parts, and then assemble the product from those parts. This article discusses what aspects of Krypton’s paradigm have been drawn from assembly line production. You don't need to read this article to know how to use Krypton, but it might give you a better understanding of the ideas that went into the tool.

This article will give you a flavour of how Krypton works. If you’d like to find out more about Krypton, you could read the How Krypton Works or Trying Krypton articles.

Assembly Lines

Assembly lines are based on the age-old principal of Divide et Imperia (divide and conquer). The production of a complex product, such as a car, is decomposed down to the level of individual parts, such as bolts and hubcaps. Each of these parts needs to be produced, or perhaps acquired from an external source, but the process for producing a part such as a hubcap is much simpler than the process for producing a car. The production processes for these individual parts are relatively easy to define. As parts are produced or acquired externally, they can begin to be assembled up into components. Assembled components may in turn be combined to create other components. Eventually when we have put together enough parts and components, we have the finished product.

Dividing the production process into small sub-processes focused on a specific part also makes it easier to automate them. It’s much easier to create a robot that creates a table-leg than it is to create a robot that creates a whole table in one go. Automation results in faster production and a more consistent level of quality.

How Krypton Uses the Assembly Line Paradigm

Krypton applies the assembly line model we’ve just discussed to the software build process. Krypton decomposes a build into the production of individual parts, which are combined together in ever-more complex arrangements until eventually the final product is assembled.

Just like an assembly line building a car, a Krypton build process takes in raw materials (source files), externally sourced artifacts, and produces parts. Parts (we call them artifacts in Krypton) can be combined to produce new more complex parts.

Krypton differs from tools including Ant and Maven in that it focuses on the parts being produced and assembled while those other tools focus on the process for producing the parts. You can see this focus in the names given to Maven goals (for example "compile") or the targets found in a typical Ant script (for example: "init", "compile", "copy-resources"). In Krypton you will find build targets (referred to as artifact's in Krypton) such as "corejar", "website", "classtree". Note that it is possible to construct Ant scripts that place a similar focus on artifacts. We discuss such an approach in our article "Artifact-Oriented Ant".

A Brief Overview of Krypton

A Krypton build process is defined simply by declaring the artifacts that are to come out of the build. This includes the final product(s), and also the intermediate artifacts. Each artifact declaration includes the name of the producer that will be responsible for producing that artifact. Producers are the industrial robots in the Krypton assembly line. Each producer has certain inputs through which materials required for production can be supplied. For example, the classtree producer has inputs for java source code, JARs to be used during compilation and additional pre-compile classes or files to import into the classtree.

These inputs are called dependencies in Krypton, because they can define a relationship between two artifacts, and because in Krypton, sources files are also treated as dependencies. In other words, to use some body of source code in your build, you declare it as a dependency of an artifact. Dependencies are typed so that when you declare that something is a dependency of something else, you must also specify how it a dependency.

The following diagram shows an example of a Krypton build declaration. The trapezoidal shapes represent different types of source code, the rectangular shapes show artifacts, and the arrows show dependencies. Where a dependency enters an artifact, the blue label shows the type of the dependency.

Starting with the j2ee_jar and log4j_jar artifacts: these are both "built" by the SimpleMaven1RepoArtifact artifact producer. These particular artifacts don’t have any dependencies, but in their declarations settings are provided that enable the producer to work out which JAR we want.

The Classtree artifact has three dependency types:

  • java - Java source code
  • importclasses - pre-built classes or other files to be included in the classtree
  • compilejars – The JAR files that the Java source code should be compiled against.

For the java and importclasses dependencies, we are just linking in some source code. For the compilejars dependency, we link in both the j2ee_jar and log4j_jar artifacts. A artifact dependency can include many sources, artifacts or a mixture of both.

The corejar artifact is built by the Jar artifact producer. This producer has a single dependency which is the classtree that we want to package up as a JAR. The Jar artifact producer has settings that allow us to specify the filename of the JAR that is built.

The final artifact, coreapp, is produced by the App artifact producer. That producer has dependencies for the elements that are commonly found in a Java application:

  • etc – Normal files that just get placed into the root directory of the assembled application
  • classes – Class files, or other files you want to have in the classes directory such as log4j.properties
  • lib – JAR files that are used by the application at runtime.

We are providing sources as dependencies for the etc and classes dependencies. We are also linking the log4j_jar in as a lib dependency of our application.

The XML describing this Krypton build declaration looks like this:

<krypton name="Example Projekt">

    <artifacts>

        <artifact name="j2ee_jar"
            type="SimpleMaven1RepoArtifact">
            <setting name="artifactId" value="j2ee" />
            <setting name="version" value="1.4" />
            <setting name="type" value="jar" />
        </artifact>

        <artifact name="log4j_jar"
            type="SimpleMaven1RepoArtifact">
            <setting name="artifactId" value="log4j" />
            <setting name="version" value="1.2.8" />
            <setting name="type" value="jar" />
        </artifact>

        <artifact name="coreclasstree"
            type="Classtree">
            <dependency name="java">
                <item type="source" name="java" />
            </dependency>
            <dependency name="compilejars">
                <item type="artifact" name="j2ee_jar" />
                <item type="artifact" name="log4j_jar" />
            </dependency>
            <dependency name="importclasses">
                <item type="source" name="resources" />
            </dependency>
        </artifact>

        <artifact name="corejar" type="Jar">
            <setting name="jarFilename" value="myapp.jar" />
            <dependency name="classtree">
                <item type="artifact" name="coreclasstree" />
            </dependency>
        </artifact>

        <artifact name="coreapp" type="App">
            <dependency name="lib">
                <item type="artifact" name="log4j_jar" />
                <item type="artifact" name="corejar" />
            </dependency>
            <dependency name="classes">
                <item type="artifact" name="config" />
            </dependency>
            <dependency name="etc">
                <item type="source" name="etc" />
            </dependency>
        </artifact>

    </artifacts>

</krypton>

The concepts of Artifacts and Dependencies are the core of the Krypton model. The ancillary elements of Krypton’s model are:

  • Meta Data - A mechanism for retrieving and deriving data about the artifacts being produced, such as product names or version numbers that might be applied to artifacts in the form of filenames or injected into files such as manifests.
  • Operations - Used to perform actions against produced artifacts, such as "execute", "upload", or "publishtomaven". Operations can also be performed against the source tree.

You can learn more about these other features in the How Krypton Works article.

Benefit: Production Isolation

In an assembly line, it would be unacceptable for a configuration change to the wheel-nut-tightening robot to have an effect on how the spray-painting robot works. Each stage must be isolated from the others, with the relationship between production stages being the artifacts that are fed between them.

Krypton produces each artifact in an isolated environment containing only the meta information properties, classes and build resources that are relevant to the production of that artifact. Isolating artifact production this way means that changing the way an artifact is produced does not affect other stages in the build.

Contrast this to Ant, where properties are global and immutable, and once created persist for the life of the build. Or Maven where the build process is driven by a set of global properties. In these types of arrangements, changing a global property for one part of the build process can have an unexpected impact elsewhere in the build.

Build isolation also means that different stages of the build process are now able to use very different build environments. This can be important when supporting legacy code while at the same time building new features based on newer technologies. For example, the following diagram shows a single build process where different artifacts are built using different JDK and Ant versions.

Benefit: Build Process Rewiring

In process-oriented tools like Ant and Maven, changing the relationships between artifacts means changing the build process itself, which means lots of work. When you flip the paradigm around to focus on artifacts, and make the process secondary, changing the relationships between artifacts requires a simple "re-wiring" of the dependencies between the artifacts.

Lets look again at our previous example:

In this build declaration, we are importing some hand-maintained Java source code. Let's say now that we have decided to port our middle-tier to be built as EJBs, and have decided to use XDoclet to generate source. If our build was based on Ant, this would require some heavy duty re-writing of our build script. If we were using Maven, we'd have to find a plugin, figure out where it fits in the build lifecycle, and debug it's integration. Using Krypton, all we need to do is declare a new artifact for the code generated by XDoclet, and wire that in to the flow with the right dependencies.

Benefit: Producer Re-use

Often when writing Ant build scripts, you find yourself putting the same bunch of tasks together to do some particular job. Ant doesn't provide very strong mechansims for re-use, so what tends to happen is that these chunks of Ant code get copied and pasted across build scripts.

As we've discussed, Krypton focuses on artifacts rather than processes – what rather than how – and build processes are extracted out and encapsulated as Producers. This encourages you to either re-use an existing producer, or write a new re-usable producer. Note Krypton still offers the flexibility to write a one-off piece of Ant code for a projekt via the AntProjekt producer.

Benefit: All Artifacts Are Created Equal

Ivy, Maven and other efforts have developed very valuable resources for the Java community in the form of repositories of JAR artifacts and the mechanisms to retrieve those in very clever ways, including resolving transitive dependencies. Build tools can retrieve artifacts from these repositories based on meta information describing the artifacts, and incorporate those into the build. But these tools give special status to JAR files, and focus on building repositories of those to the neglect of other types of files.

Dependencies are key to the way Krypton works, and are not restricted to JAR files. Under Krypton, all artifacts are created equal: all can have dependencies, and all can be dependencies for other artifacts.

This model allows for opens up some interesting possibilities and opportunities to extend your build automation to include automated integration of a variety of artifact types. For example:

  • log4j.properties - If your dev shop always uses the same log4j.properties file, that file could be published to a central location.
  • Web Skins - Web front ends are often problematic to maintain and version because they involve so many CSS, image and HTML files, and because those files are complex anyway. By managing your web skin as a separate projekt with it’s own version lifecycle, and importing the published skin into your projekt, you begin to manage the way skins are applied to your web applications. You also remove the tempation for the web app developers to make changes to the skin because they only have access to the published artifact and not the original sources.

    The Krypton standard library's Site producer retrieves it's skin from a Maven repositiory.

Conclusion

Krypton borrows ideas from manufacturing to create a software build paradigm that is focused on artifacts rather than processes. This leads to more controlled management of each stage of the build, while at the same providing a model that is more flexible and adaptable than older tools.

Contents

Other Pages