-
Notifications
You must be signed in to change notification settings - Fork 13
Tripod 101
Once you know how Tripod got it's name and how I understand the ideas of dependency & control inversion, the basic structure of the Tripod solution should be a bit more obvious. A Tripod solution is composed of three primary projects:
-
The Application project (MVC, WebAPI, Console Application, etc.)
The purpose of this project is to pass messages back and forth between the user and the domain. It should be kept thin, and should delegate all business code to the domain layer. The responsibilities of this project fall into the communication category, such as dealing with HTTP semantics, accepting user inputs, and returning responses to a user interface.
-
The Services project
The purpose of this project is to house the inversion of control container, implementations of interfaces which are defined in the domain, and boilerplate code for wiring them up. This wiring is more formally known as Root Composition, but you may also hear it referred to as "bootstrapping" code. I often refer to code that exists here as "boring" code. It simply provides infrastructure and low-level services.
-
The Domain project
The purpose of this project is the home of Tripod's interfaces (API) along with all business-related code. This encompasses storage entities, representational views, input validation, commands, queries, events -- anything and everything that crunches business knowledge into code. I often refer to this as "interesting" code. This is the very core of your solution, and tries to take the least number of external dependencies possible to complete its job.
Whenever you write a code artifact in a Tripod solution, it should be obvious which project it belongs in. If it seems like it has responsibilities that span more than one project, go back to the drawing table. Think more critically about the roles it will play, and decompose it into application messaging, business knowledge, and low-level services. Often the solution for me is the introduction of one or more interfaces into the domain along with a new implementation in the services project.
##Going Beyond Three
With Tripod you need at least three projects, but you can have more. For example, the Tripod interfaces that exist in the Domain project could technically be separated out into a separate project which would then serve as the core of your solution. The Domain would then depend on the core, the Services would depend on both the Domain and the core, and the Application would depend on all 3 of them. For small projects this may be overkill, but if it makes sense for the core API to be in its own assembly, do it. There is no reason the API has to be part of the Domain project, I just like to start out simpler, so I keep them together at the beginning.
You can also create additional Services projects, additional Application projects, and perhaps even additional Domain projects in your solution. For example Tripod's Services project houses common root composition code along with interface implementations. These could be split apart, with common root composition code in one project and the interface implementations in another. You could also further break them down by having different projects for different interface implementations. When you start with the basic Tripod solution structure, refactoring one logical layer of the application into multiple assemblies is pretty straightforward.
For larger solutions, you may even want have multiple Domain projects to represent different Bounded Contexts. Business code for one aspect of the solution may be logically and conceptually separate for other aspects, and seem like they don't belong together. For example when I worked on the UCosmic project, we had a core set of data that was reused by many aspects of the solution: Languages, Geography, Establishments and People. Other "modules" of the project all used this core data set, but to deal with different concerns. In a project like that, it could make sense to have one Domain project for dealing with the common core components, and a different Domain project for each of the modules.
You will realize the power of the Tripod design however when you need to add additional Application projects. Say you build an MVC project using this design, and later the business stakeholders decide they want to expose a JSON or XML API of the application's services in order to allow it to integrate with other systems. Or, perhaps they will need it to do some kind of periodic time-based processing like sending out daily or weekly emails. Had you written all of your business and service-related code directly in the MVC project, you would have to either refactor it out or copy and paste it into a new WebAPI or Console / Azure Worker Role project. With the Tripod design, you can simply add a new Application project that reuses the same Domain and Services projects that the MVC project relies on.
Notice however that, with the exception of the project that splits the API interfaces out of the Domain project, all of these additional projects still fall into one of the three categories: Domain, Services, or Application. If your app will need to receive inputs or a different communication channel, then you can add a new Application project. If you want to add new interface implementations, or logically divide your services into more granular assemblies, then you can add Service projects. If your business code base is growing large and becoming unwieldy, you can add new Domain projects. All of your solution projects will still fall into one of these 3 main categories, with one exception: Test Projects.