Service Tech DomainEverything that is not business,
can be seen as your tech service, it is also app infrastructure. Typical samples are
- HTTP, you wrap your HTTP client library here
- Logging, setting up log levels
- Environments, wrap your ENVs, calculate URLs for back end
- I18N, translation logic
- DateTime, wrap external lib's like moment.js
- Routing of the application, wrap standard routing into methods
I consciously don't want to start a puristic discussion here, to let the architecture and the rules be simple. Let it be just business domain and tech domain.
Global State ManagementIf you have a mid size react app with nothing special you should be fine using just
the context api, that comes out of the box with react. You can see a
good intro here on how to do it.
Important is to understand that
- you can use the context from everywhere as long as you structure your service methods as hooks
- if you don't need a service method to be a hook, than make it a simple function, this makes the usage of it more flexible and simpler
- ideally you have your context only in the business ui domain and your business domain, but this is not always possible
- I wrote complete projects with this architecture completely avoiding a global state in the system, try to delay the introduction of global state to the latest, but if you know you need it, clearly define where it will be used
Directed dependency flowYou see the dependencies direction in the diagram. Its mostly unidirectional top down, same es it would be in the back end as well. Obviously tech services don't know about the ui and business domain. The business domain picks things out of the system that it needs, so it is referencing the tech services from all levels always in one direction. Of course can a tech service also reference another service, like HTTP service can reference the EnvService to figure out the URL it needs to use. Tech service though can never reference higher layers, like the business or the UI. Specifically its forbidden to mix up objects from different layers in the signature of the methods. Like passing around HTTP domain specific object types to other domains.
Service ObjectsThe first thing that surprised me a lot in the JavaScript projects, is the sloppy way of handling the visibility of methods, just everything is exported any variable and any method. Additionally this exports are mostly placed in single files! Not only you pollute the code name space you also have thousands of single files. I understand the original motivation behind it, its
tree shaking. This is all fine if you import
lodash and just want to use a single method from it, but why would you be willing to tree shake your own methods, if your service is just having 5 of them, which is a tiny size and you have all of them used in your application? Will the little tree shaking of own methods decrease your bundle size so much that you need to build your whole repo that way? I really don't think so, this is not where you should be optimizing your bundles.
To fix that I came up with the object service pattern, so if I have some domain logic, instead of a single exported method you create a service that will potentially hold all logic of this type.