Solution Summary

Not so very long ago, I was asked to give a summary on a solution our team had written to another development team. I had never met these people before, nor were they familiar with any of our work. I reviewed with them the overall design, methodologies employed, and the logic behind various programming decisions. At the close of the meeting, I left them with some documentation, as well as the following summary.

Summary Notes

I find it useful when reviewing software solutions to discover as much as I can about the author(s). If I can learn what methodologies they employed, and what literature they referred to, I can better ascertain why they did what they did and more fully understand their work.

I start from the premise that the product they produced was their best effort and that each detail reveals some intent and tells me something about their thought processes of the time. Sometimes I find that nothing could be further from the truth, and instead of order and intent, I find chaos and the arbitrary.

Below are a few resources and explanations that encapsulate the author(s) overall development methodology and thought processes.

I would characterize our development strategy as employing the following:

  • Domain-Driven Design – The solution’s primary focus is on the domain and its logic. This differs from a solution that focuses on a particular technology or implementation.
  • Object-Oriented Programming – A programming paradigm whose structures combine Data and Behavior. The mutation of data is a hallmark of this paradigm while being sure to keep the structure in a valid state.
    • In general, we tend to favor objects that have a non-default constructor, which avoids temporal coupling and helps ensure they can be used after instantiation without resulting in errors.
    • We prefer methods that, when changing the state of an object, protect its invariants, and keep it in a valid state.
  • Functional Programming – A programming paradigm that separates data and behavior. The emphasis is on the evaluation of expressions to values, function composition, and immutable data.
      • Elements of functional programming are present throughout the solution, typically in the form of LINQ queries, and Lambda expressions.
  • SOLID
    • Single Responsibility – A class should have only a single responsibility.
    • Open Closed – Software entities should be open for extension but closed for modification.
    • Liskov Substitution Principle – Clients should be able to consume any given implementation of an interface without violating the correctness of the system.
    • Interface Segregation – Many client-specific interfaces are better than one general-purpose interface.
    • Dependency Inversion – High-level modules should not depend on low-level modules; they should both depend on abstractions.
  • Unit Testing – Unit tests, as devised throughout the solution, are tests that focus on a particular behavior and don’t rely on external dependencies such as a database, web service, etc.
  • Waterfall / Agile – We find it useful to switch between and combine elements of both of these development processes depending on the context of the problem and what is being requested by the customer.

Reflection: I hope the summary I provided to that team gave useful insight into the solution’s design and into my team’s development process. I also hope that they benefit from the list of educational resources that were included and can incorporate their lessons into their solutions.

SOLID Principles

In object-oriented programming, SOLID principles are key to making software designs more understandable, flexible, and maintainable. What are the SOLID principles you ask?

  • Single Responsibility – A class should have only a single responsibility.
  • Open Closed –   Software entities should be open for extension, but closed for modification.
  • Liskov Substitution – Clients should be able to consume any given implementation of an interface without violating the correctness of the system.
  • Interface Segregation – Many client specific interfaces are better than one general purpose interface.
  • Dependency Inversion – High level modules should not depend on low level modules, they should both depend on abstractions.

Now that we have those formal definitions out of the way, what SOLID is and how you apply, it may not be clear. You also might be asking, do I really need to know this? The answer is emphatically Yes! You may work in the same software code base for months, even years. Do you want that time to be pleasant or a constant frustration?

Keeping your software code SOLID will help make your work and that of your colleagues much simpler and more productive in the weeks, months, and years ahead. Just ask anyone who has had to maintain clunky, monolithic, spaghetti code!

Below is an example of a Repository class. This class has a problem, though; it has two responsibilities. It enforces Domain Rules and has persistence concerns.

CustomerRepository

Here is a revised version of the CustomerRepository class; it now has only one responsibility that of persistence.

CustomerRepository

Below I’ve added a RulesCustomerRepository class that handles the Domain Rules. Now each class has its own responsibility. (The RulesCustomerRepository class is an example of the Decorator pattern from the GOF Design Patterns book.) Not only that, but I can now write unit tests for the domain rules in isolation without being encumbered by the database.

RulesCustomerRepository

Still not convinced of the benefits? Consider the size of the Customer Repository as the persistence logic becomes more complex, and more domain rules are added over time. You also cannot write effective unit tests on the Domain Rules with the persistence concerns in the way.

If you would like to learn more about SOLID, I highly recommend Mark Seemann’s excellent course on Encapsulation and SOLID available on Pluralsight.

Reflection:  One might argue, the sample code violates the interface segregation principle. Should these principles be practiced with strict adherence? Perhaps the level of adherence varies with context? I’ll leave it to the reader to decide.

Disclaimer: The code sample should be considered a toy whose purpose is primarily pedagogical. I endeavor to make code samples just real enough to be interesting but not so complex that they overwhelm.