We've inherited a lot of code at Liquidfish. Working with code written by another person years or possibly decades ago is always an interesting view into how diverse solutions can be in software. Occasionally this code can lead to the discovery of a new architectural idea or concept, but it can also reveal just as much about what not to do.
When working with inherited or legacy codebases, one of the key concerns is almost always: how difficult will introducing change to this system be? As I encounter pain points, I continue searching for ways to make change less difficult for myself and anyone else who might work with the code in the future.
One such solution is a common principle called single responsibility. In simple terms this means that each object in code completely encapsulates the responsibility of a part of the whole task. For example, when handling an online order there will exist an object whose sole responsibility it is to create and send an email confirmation to the customer. As with all things development, there are more than a few solutions on accomplishing single responsibility, but an important end goal should be ease of change. In the case of the email confirmation example, a new developer who is tasked with altering the email confirmation to include related products for future purchases would be able to intuitively find the object(s) responsible and make changes confidently.
Command Query Responsibility Segregation, or CQRS, is a relatively simple architectural pattern that is defined by its creator Greg Young as:
"the creation of two objects where there was previously only one. The separation occurs based upon whether the methods are a command or a query"
Commands and queries in this case are analogous to writes and reads. An example of a command might be: "please submit this order with the following payment information", whereas an example of a query might be: "please display my recent orders by date". There are many benefits of this pattern, but perhaps the best one is that it allows for a clear responsibility of objects to tasks. Domain logic and user interface necessities aren't forced to coexist in the same cramped space while constantly stepping on one another's toes. Writes can work with robust ORM backed objects, and reads can work with simple flattened objects uniquely suited to a single page or screen.
CQRS is often correctly linked to Event Sourcing, Domain Driven Design and other patterns, but none are necessary to utilize CQRS. CQRS at its core is probably the simplest architectural pattern that I have encountered. That said, when misunderstood or combined with too many other patterns it can easily lead to overly complex code and/or architecture and may be entirely unnecessary in many simple codebases. I don't expect it to solve all of my problems, but I am enjoying the extensibility of what I've built with it so far.