Tach is fast, but making it effective in larger organizations requires more than just quick execution. These organizations face concrete challenges like:
We recently released support for layers and distributed configuration which specifically address these challenges.
By default, Tach assumes that you will manage all cross-module dependencies explicitly. This is great for smaller projects, since tach.toml
then provides centralized documentation on how modules fit together, but it is untenable for projects with 100s of interdependent modules.
Layers are a lightweight alternative approach. Tach supports an arbitrary number of ‘vertically stacked’ layers, which could be “API”, “Product”, “Platform”, and “Persistence” for example. The only rule in a layered architecture is: dependencies point downward.
This is often a much more practical architecture to adopt, since it requires far less configuration maintenance (no need to tach sync
for every new dependency) and is much easier for developers to reason about if they run into an error in CI.
In most cases, Tach is used with a single tach.toml
file in the root of a project. This file defines all modules, interfaces, layers, and other rules which apply throughout the codebase.
The centralization is useful for smaller projects, since every detail can be seen at-a-glance. When many teams work on the same project though, this model is prone to merge conflicts and configuration drift.
Tach now supports splitting out module and interface configuration into tach.domain.toml
files which live alongside the associated source code. This means teams can use tools like CODEOWNERS to maintain their own Tach configuration. Since these files are also much shorter and have a specific context, they serve as better documentation for other developers.
Taming the complexity of a legacy codebase is daunting, and an incremental approach is often the best option. Tach lets you start with permissive configuration, and gradually ratchet up toward a well-defined modular monolith.