Bring it all together

Let’s take a look at an example Polylith workspace, so you can start to understand the benefits of dividing your codebase this way:

We can see that the codebase contains almost 9000 lines of source code and around 7700 lines of test code (7093 + 619). The first table shows our projects, including the single development environment, and the second table lists all the components (in green) and bases (in blue) and in which projects they are used (the s and t flags show that the brick's source and test directories are included in the project).

This codebase is divided into 29 bricks (27 components and 2 bases). That's 310 lines of code per brick on average. Most bricks are shared across several projects, which are used to build various deployable artifacts. The dev column represents the single development project. The poly project is used to build the poly command-line tool from which the diagram above is created. The api project is used to build the code as a library, and finally, the deployer project is used by the tool itself in the CI build.

9000 lines of code isn't much and it's not uncommon for non-Polylith services, tools, or libraries, to be a lot bigger. However, the problem with storing something that big as one piece in a single place instead of dividing it into 29 (or more) smaller pieces, is not only that the code can't be easily reused, but also that it makes it harder to reason about the code.

In a Polylith codebase, we can make each brick tiny, making it easy to work with the code and allowing us to focus on one part of the code at a time. The structure also encourages us to divide the bricks into even smaller pieces, using namespaces. To give an example, this is how the creator component looks:

It's pretty easy to reason about this code. It lives in the components directory, under the creator directory, indicating that this component can create things. Based on the namespace names, it looks like it can create components, bases, projects, and workspaces.

When we look at the function names in the component's interface, it turns out that we guessed right! By giving the namespaces and functions good and explanatory names, and by keeping them small, we lay the foundation for a healthy codebase that is easy to reason about, compose, and change!

Last updated