At this point, the temptation is to just jump in and start coding, especially if the project is personal (not derived from one or more external stakeholders) and scratches a big, immediate itch. In my case, I have been trying to find a good PM solution that doesn’t burden me if umpteen keypresses to log tickets and has a real ability to workflow items. Many do not fit the bill, and my workload isn’t getting any leaner.
But, instead of jumping right in, we’ll pause for just a little while, and gather up some key concepts we want to put in play in this project. There are a lot of choices to make when you develop a web application. There are concerns over technologies (ex: databasing both relational or KV store, code repositories, etc.), libraries (ex: ORMs, serializers, etc.), platforms (ex: ASP.NET MVC 2), frameworks (ex: jQuery, Sharp Architecture, etc.), development methodologies (ex: TDD, BDD), management approaches (ex: Scrum, XP), architecture concepts and patterns (ex: CQRS, DDD), amongst many others. While each one of these items, like CQRS, is often the subject of multiple blog posts, but I will attempt to cover the salient items with respect to this project within a couple of posts.
In this project, we will cover:
- Domain-Driven Design (DDD): Domain-driven design has been around for a decade or two, but has really taken off in the last few years, as more developers start tackling software of growing complexity. DDD is a methodology (as in “a framework that is used to structure, plan, and control the process of developing an information system”) that addresses the broad topic of researching, understanding and then designing the conceptual part of whole systems. DDD makes the developer focus on the core functionality by isolating it into a domain model, separate from other concerns, and also by bringing the developer closer to the business user’s language. It does this through the core concepts of “ubiquitous language” and “bounded contexts”, which we will discuss in a later article. The goal of DDD is to create a set of techniques, concepts, patterns and language that directs you to focus on the domain, on the concepts of the system, rather than on the underlying technologies. Said differently, if you want to produce good software, it is more critical that you understand what an Order is and does logically, rather than decide which NoSQL store du jour to use. The latter is often more exciting to technologists, and is also a case of putting the cart before the horse. DDD will help not only build better software through better focus, but also help us do simple things like give us direction in project structure.
- Command Query Responsibility Segregation (CQRS): This is actually a simple architectural concept or pattern, rather than a comprehensive, technology-specific framework or methodology. The goal is implied in the name itself. The idea is that commands/actions that tell a system what to do and that change the state of the system are segregated, at least logically, from the act of querying the state of the system. Reads and writes frequently contend in busy systems. CQRS is an approach to mitigate that reality of system design. Again, we’ll explore this in its own article soon.
- Event-Based Architecture (EDA): The ever-present question in any developer’s mind at work is “Where should this block of code go? How should I organize my code?” We want the end-product of our craft to be easy to write, easy to read and easy to change. These needs are encapsulated by a lot of acronyms: DRY, GRASP, SOLID, etc. In very general terms, the main goal is low coupling (low dependencies between functional sections of code, classes or otherwise) and high cohesion (breaking down code into functional sections that are very focused in purpose). Of course, as you break down your code into focused chunks that are independent of each other, the question becomes how do you get them to work together? In comes messaging. These blocks of code coordinate and affect each other via messages. One block of code raises an event (a message) that it did its thing and changed the system, and then interested listeners pick up the message and do what they were created to do in response.
- Dependency Injection (DI): When we create blocks of independent code, oftentimes there is the need (or temptation) to have one block use another block directly. And so, we pull a direct reference or link to that code; we new up what we need. In so doing, we have increasing the amount of coupling in the system. DI is a way to reduce this coupling. For example, if we implement an EDA-based system, almost every block of code needs to publish their event messages into a system that can then distribute it out to interested listeners. We don’t want to have that code in multiple places; that breaks DRY. We also don’t want to put that code in its own block, and then have every other block link to it; that ruins low coupling. Instead, we use the DI pattern. This allows us to register the event system, and its various parts, in a container or directory that any other part of the system can see and use. That code doesn’t get repeated and the indirect nature of the link allows looser coupling. So, when one block of code needs an event publisher in our EDA system, it calls for one generically (“Hey I need an object that has a way to let me publish an event into the message bus!”) and gets whatever is registered in the system (“Here’s an concrete object for you to do this. It has the method you need.”). Basically, you let a specific part of the system focus on managing dependencies, instead of the immediate code doing it for itself. That makes it easy to change parts. Is your custom-built publish-subscribe code not robust enough? Well, plug in NServiceBus. Built right, with the blocks of code offering up the same interface to achieve the same functions, you should be able to swap systems out.
- Aspect-Oriented Programming (AOP): AOP is a programming paradigm, a style of coding. The keyword, aspect, describes a focused functional block of code that has a high amount of reuse throughout a system. Aspects are these blocks that are cross-cutting concerns because they “cut across” (a.k.a. “are used in”) many different blocks of unrelated code in the system. A classic example of an aspect is the need for a logging subsystem in an application to support debugging efforts. In a way, whereas DI is a passive way to allow one block of code to use another, AOP is much more active and/or broad-stroked. AOP prescribes a way to apply a block of code (a.k.a. advice, ex: “run this aspect before the block”) across some or all blocks of code (a.k.a. cut points, ex: “all methods in namespace X.Y.Z”). Aspects are a great way to keep such code in one place for maintainability, but effectively apply it where necessary with low cohesion, since the affected block is effectively oblivious to its presence.
We’ll explore a lot of these concepts in detail in subsequent articles. And, I reserve the right to expand this overview list as I discover more topics that deserve an “executive summary” for those fresh to the series. For example, I have not covered testing, continuous integration, and other more technical items that add to our ability to deliver good software. If you think we should cover anything else, feel free to chime in.