Layered Build and Packaging

Layers are a great way to manage builds, packages, versions, tests, deployment configurations, etc. Like Gradle, using a language that's object oriented and supports components makes project management easier than XML. If you are not comfortable with the Groovy syntax, and prefer Java you can use StrataCode to do the same things. The layered, component framework in StrataCode reduces copying while improving customization potential for your builds. Layers make it easy to define simple modules - organized by file type or dependency rather than using a lot of project scaffolding. Modules are usually already organized by type so why not make them simpler? You'll end up with more modules that can be managed by more people.


Layer's can include maven libraries in one of two ways. Your projects can use maven itself for builds and/or installs of dependencies. You also can use StrataCode's built-in support for the maven system eliminating a lot of code dependencies and improving the customizability of your projects with layers. The layered approach also makes it easier to swap back and forth between source and compiled formats on a component-by-component basis.

To start a new project with most systems, you use a "create project" wizard and it generates a bunch of files from the configuration you specify. It's your job to figure out what it generated and manage those from then on. The next time you upgrade your tool you may be required to manually update those files for your package to even work. With StrataCode, you create a new layer which extends a base-layer to pick up all of the default. You only need to specify files or settings you need to change. This reduces the project configuration and improves the relevance of any configuration that's actually there.


StrataCode has a simple command-line integration with git for managing layers. Using layer definition files, you can easily change how a layer of code is defined - source of binary. You can move layers from one git repository to another, only by updating layer definition files. Because these files are statically typed and support IDE based tooling, everything is easier to manage.

Some branches in git can be avoided by creating layers which patch or replace code, then merged when they no longer are needed. You might copy some files or just add fields and override methods, create new types, etc. It can be a nice way to build a new feature because your changes are kept separate and together for easier navigation. You reduce conflicts with others changing different aspects of the same types - which would mean the same files if you did not use layers.

Use of a layer requires that a particular set of contracts are defined - without saying whether those contracts are delivered in source or binary form. As long as the layer supplies those contracts, upstream code works. When you can isolate how dependencies affect developers or other members of the team, you can optimize workflows - minimizing merge conflicts and making it easier to maintain compatibility over the lifetime of the project.

Options for Module Packaging

In most project and build configurations, each module or project contains a lot of scaffolding - directories (and features) you might not need for any particular type of module: tests, configuration, source, documents, documentation, etc. When a project has lots of files of different types, it makes sense to separate them by type first. It makes things easier to find and reduces the size of your directories.

Other modules may already be organized by their type - tests, documentation, configuration, may be separated from the code according to important "lifecycles". When you combine files with different lifecycles in the same module you run into problems. Perhaps they are managed by different people, released at different times, included in different packages, organized in different source control systems, etc.

For these simpler modules, layers eliminate the scaffolding. Simply extend a layer which defines the context for your source files. It will make sure the files are deployed correctly - i.e. only run in test mode, includes in the test.jar file etc.

Layers support more flexible ways to organize files by their lifecycle, and their dependencies. In this case, you invert the directory structure - so you have test, doc, configuration, etc. groups of layers, each of which contains a simple directory of files. Instead of one module which is tightly coupled, you have lots of modules which are loosely coupled.

When you have simpler and more flexible module structures, you can create projects that are easier to manage, not just for developers but throughout the organization. Everyone contributes their "slices" of the feature set. Framework code controls how those assets are deployed. Static typing and tools keep things structured in the same way a complex object-oriented application is structured. That helps detect conflicts and gives tools for fixing them. This lets developers more flexibly organize source code amongst different git repositories and move back and forth maintaining compatibility with upstream layers.

Layered Dependencies

Anyone who has worked in a big Java application is aware of how difficult it can be to manage dependencies. You have to worry about not only your dependencies but the "transitive dependencies" - dependencies of your dependencies. How do you select compatible versions? How do you pick up the latest versions? How do you understand what's happening and resolve conflicts - to select the right version, even in the common case when you are inheriting conflicting rules for overlapping packages? When a critical security patch comes out, who do you trust to delegate your transitive dependencies so you pick up that patch as soon as necessary?

Maven provides a flexible but intricate system to specify, inherit, exclude and resolve conflicts between the versions you inherit from transitive dependencies. The order in which modules are sorted is determined by the order in which the dependency graph is traversed. That's based on the order of dependencies in the pom.xml file essentially.

Layers do essentially the same thing, but open up a couple of extra design strategies that are interesting. First the stacking order of your layers determines the precedence when there are conflicts. This order is basically what maven would do with the same modules, but there's more flexibility in controlling that order at the framework level. Layers are organized into framework, application, and configuration stacks which are independently sorted and can set priorities and exchange info over init, start, validate cycles to work out the best configuration. It's easy to trace that order in the IDE. If necessary, you just add a new dependencies to change the order of how you include transitive dependencies.

It's also easy to separate the transitive depenencies into a new layer - so you can include a package, but not include it's dependencies. Or switch transitive dependencies by switching a layer. That's a better alternative than excluding dependencies, since who knows when those will actually be required rules on your dependencies. This way, a required dependency is always included but these packages of dependencies can be included optionally. Dependencies are themselves just new, trivial modules without any code. With maven, you need always get the dependencyManagement whether you want it or not.

Read more and see examples in the documentation.