Enterprise Software Patterns: Part 2

Jacob Taylor
CodeX
Published in
7 min readMay 4, 2021

Welcome back to our series on enterprise coding patterns! There is so much nuance in the world of software these days. If you’re a new developer, it can be overwhelming to understand how to fit things together when you get your first job. With so many people going through boot camps and other rapid training courses, some of the most important things are left out. In this next edition, we are going to do a deep dive on some of the most common components of a business layer: services, factories, commands, queries, validators, and orchestrators.

Pleased to be of Service

Services are one of the most foundational aspects of any application. Why? Because they are so versatile! Granted, they sometimes end up serving as a catch-all type component for vaguely related functionality but often that’s what makes them so great. If you’re dealing with lots of common, complicated logic around a tightly scoped domain area, a service component might be just the thing. You will also often see services in places that abstract or wrap external functionality. Regardless of whether the functionality lives inside your application or not, you will want to make sure that the interface used to interact with it is generic — you might find that, even if you start with that functionality in your system, it might make more sense to move it out as the rest of the application grows.

Lets look at an example focused around PDF manipulation. There are various web services out there that you can provide the PDF to along with the necessary instructions and they can do simple things like merging, splitting, etc. There are also libraries for just about every language that provide similar functionality without needing to make a web call. Depending on the nature of your application, one might be preferable. This would be a good time to create an IPdfService interface that is generic enough so that you could easily swap the underlying implementation. The other aspect here that differentiates something like this into a service is that generally (though not always), services do not do direct data access, but rather simply provide a black-box style service to the rest of the application.

I Made One!

Have you ever found yourself writing the same object initialization code over and over again? Or creating multiple different objects all derived from the same interface? Then you might want to consider a factory. Just like a real-world factory, they are meant to help ease the creation/initialization of objects. Let’s look at an example around automobiles.

A simple automobile-focused example

So we have an IAutomobile interface that is implemented by 3 different types: SportsCar, Sedan, and Truck. Now, all three of these instances share a lot of common components probably, right? The specifics of each might be different, but at a high level, each of them has 4 wheels, windows, doors, an engine, a transmission, etc. To make it easier to construct these in code, we’d use something like an AutomobileFactory that we could provide some specifics to in order to simplify a lot of the shared code between creating these. The second best part? You won’t ever need to go searching for all of the places you create an instance of a sedan, because it’s all centralized into one place.

Go and Get It

Commands and Queries are typically seen as part of a broader concept called CQRS which stands for Command Query Responsibility Segregation. We’ll explore the broader concept more in a future article, but for now, just understand that these two components are the main focus. Neither is terribly complex on their own — commands are used to do and queries are used to get. Said differently, if you need to perform an action, you’d write a command to make it happen; alternatively, if you need to retrieve some data from the system, you’d write a query. As the pattern name implies, it is desirable to keep these two things isolated i.e. don’t call commands from queries and vice versa.

Continuing with the theme of our automobile factory, some of the things you might see in the command/query world might look like this: RegisterCarCommand, GetCarRegistrationQuery, CreateCarCommand (which would likely use the IAutomobileFactory from earlier) and many more. Notice that these are also generally as focused as possible and typically only do one thing, to help cut down overhead — this isn’t a requirement, just a best practice, however.

Am I Doing This Right?

Validation is an important part of any application — not only does it help ensure data integrity, but it also helps enforce certain requirements and expectations that your application has. You might also see validation happening at multiple layers within an application, often both at the web/presentation layer and again somewhere in the business layer. In this case, you might see very high-level validation occurring at the API level just to ensure that the data is good enough to come into the system. After further manipulation, you’d want to again validate somewhere along the path in the business layers to ensure that your requirements are still being met. In some instances, the validation being performed might be the same at both the API and business layer for the exact same data — this is a good practice in case you end up calling certain methods from different places, even if it feels redundant down certain paths. Validation might also happen much closer to the data layer as well, but that’s less common and usually only seen in extremely complicated, data-source-specific scenarios.

Jumping back to our automotive theme, let’s assume there is an API to create a new car that accepts very basic items like type, trim, interior color, and exterior color. Your API would first want to validate that the supplied options are even available. For instance, let’s say you only have black and beige for interior color options and the request asks for a red interior — you’d want to let the user know that red is not an available option (usually via a 400 status code, if using HTTP, but that is beyond the scope of this article). Next, assuming the parameters supplied are all valid at the top-most level and the car has made it through a few additional stages, you’d probably also want to validate that the rest of the necessary components & paperwork exists. Picturing that this all looks like an assembly line and you have a final BuildCarCommand, that command would validate that you have a valid registration, all the available parts and anything else you need to ensure before you actually build the vehicle.

How To Put It Together

By now you’re probably wondering how all of this stuff works together. Now, there are multiple ways to do this, but one of the more common practices is the Orchestrator pattern. Orchestrate means to put things together in a specific order, which is exactly what an Orchestrator-type class does in software. You might use it to string multiple chains of validation together, or call a few services in a specific order. It might even be more complicated than that and, since building a car is a fairly complicated scenario, an orchestrator would help out tremendously here.

Automobile Orchestration Sequence Diagram

As we can see in the diagram above, the orchestrator is taking care of the majority of the work and the rest of the components are very focused on doing one specific thing — the orchestrator is too, it’s focus, however, is organizing rather than doing. First off, the orchestrator is invoked by the API. Next, like we discussed earlier, we will want to validate the initial supplied values using the AutomobileBasicValidator to check for colors, trim, etc. Assuming all of that passes, we’ll want to make sure we can register the automobile, so we’ll call the AutomobileRegistrationService to do that. Next up, we want to ensure we have all the parts necessary to actually produce the desired automobile, so we call the AutomobilePreBuildValidator to check for parts, a successful registration, etc. Lastly, we call the AutomobileFactory to actually produce the car. There could also be additional steps here afterwards that might include more validation or installing options, among other things. Hopefully by now, you can see how important the role that the orchestrator plays in the big picture is.

Summary

We explored a variety of business components including services, factories, commands, queries, validators, and orchestrators. We learned about what differentiates a service component from others, when factories are used and how to do validation. We also touched on commands and queries from CQRS as well as the orchestrator pattern to tie it all together.

What’s next?

Up next, we will dig into some of the concepts we’ve highlighted here as well as dig into other, more advanced topics.

Want to see something specific? Leave a comment!

--

--

Jacob Taylor
CodeX
Writer for

Passionate Agile leader. Innovative developer. Creative software architect.