MVC and Descartes

One of the first software development books I ever read was on iOS development. In this book(I long ago threw it in the trash), I learned about the MVC design pattern. I was quite excited about this pattern as it would give me a more elegant way to structure my code. I didn’t realize it at the time, but the book errored when it explained the Controller’s role in this pattern. In short, I wound up with the false understanding that the Controller should contain an application’s domain logic. A couple of years and a few applications later, I picked up another book, Cocoa Design Patterns. It was from this book that I came to realize I had been implementing the pattern incorrectly. Thus began a two-year expedition to refactor and correct the projects I had worked on where I had incorrectly implemented the MVC pattern. (Now you know why I threw the book away)

MVC as defined in Cocoa Design Patterns

  • Model – Models contain all of the rules for processing application data. The Model is the key subsystem that makes an application valuable. It’s critically important that the Model subsystem is able to stand alone without dependencies on either the View or the Controller subsystems.
  • View – The View subsystem presents information gathered from the Model and provides a way for users to interact with information.
  • Controller – The purpose of the Controller is to decouple the Model from the Views. The Controller also handles translation and formatting for presentation to the user.

Fast forward a few years… 

I recently read René Descartes’ Rules for the Direction of the Mind. In this work, Descartes lays down various rules for conducting one’s thoughts and for finding solutions to problems.

Let’s take a look at Rule 2:

  • Only those objects should engage our attention, to the sure and indubitable knowledge of which our mental powers seem to be adequate.

I conjecture that the author of the iOS development book may not have possessed the adequate mental powers needed to write the book. Admittedly, this realization isn’t always an easy thing for people to grasp or admit to, but doing so has the potential of saving yourself and others much sorrow.

Let us continue reading rule 2:

  • …Further, because they have believed that it was unbecoming for a man of education to confess ignorance on any point, they have so accustomed themselves to trick out their fabricated explanations that they have ended by gradually imposing on themselves and thus have issued them to the public as genuine…

Well, that’s a fine kettle of fish, isn’t it? I conjecture that the author of the iOS development book could either be the source of this error or perhaps was a receiver of this error from someone else. Obviously, I definitely received the error since I included it in my code.

Are there any other possibilities? I’m sure there are, how about this one?

I conjecture I did not have enough programming background when I read the iOS book and misunderstood its meaning. I have to consider this conjecture since I have forgotten the title and don’t recall the exact language it used to describe MVC. However, I don’t think this is the case, but I need to entertain the possibility that I could be wrong.

There are also, of course, perhaps other possibilities…

Reflection: As I continue to think back on what went wrong in my understanding of MVC, it may be what wasn’t said about the Model in the iOS book that was the most profound cause of my confusion. The iOS book, as I recall, placed the greatest emphasis on the Controller but put less emphasis on the Model, whereas the Cocoa Design Patterns book placed a great deal of emphasis on the importance of the Model.

Reflection: When I learned this pattern, I shared it with at least one colleague. I remember they were just a bit skeptical when I explained the controller portion to them, but since I had read it in a book, they passed it off and didn’t question it any further. 

Reflection:  I should have consulted other sources as the consequences for getting something like this wrong are far-reaching.

Reflection: I wish I had read Descartes as well as a few other authors when I was younger.

Reflection: Why don’t schools teach the trivium and introduce young minds to authors like Descartes? The author of Weapons of Mass Instruction thinks he knows why.

Reflection: I forgive the author of the iOS book. If this is you, and if you haven’t done so already, please pick up a copy of Rules for the Direction of the Mind.

Functional Workflow in C#

A colleague of mine called me over to his desk one day and asked me to help him refactor and clean up his code. He was working on a solution that involved the execution of various email tasks. His code worked but was quite difficult to reason about.

What we needed to do was more thoroughly decompose the problem and compose a more comprehendible solution.

In addition to decomposing the problem into smaller pieces, it was also necessary to handle errors, write the results of operations to a log, and compose multiple Task like operations together into some type of workflow.

It happened to be that during this time, I was reading Functional Programming in C# by Enrico Buonanno. Being already very excited about what I had read and learned from Enrico’s book, this seemed to be the perfect opportunity to put some of it into practice.

I’ve put together a demo that demonstrates some of what we implemented into our solution.  If you are at a minimum comfortable using C# and LINQ, I think you’ll be able to follow and understand the code.  There may be a few constructs you aren’t familiar with, such as the Either type, but I think you’ll understand what it does when you see it in context.

To better understand the demo and how it’s put together, you may want to study it from the bottom-up so to speak in the following order.

  1. Tasks.Runner
  2. Tasks.Services
  3. Persistence.Services
  4. Logging.Models
  5. Logging.Services
  6. Domain.Models
  7. Domain.Interfaces
  8. Common.Services

The benefits of employing functional programming in my solutions have been numerous. After putting together this solution, two key things stuck out to me:

  1. FP has built-in constructs for composing functions together to create a workflow.
  2. FP has built-in types for handling errors such as the Either type without the need to throw exceptions.

If you would like to know more about Functional programming, I highly recommend you pick up a copy of Enrico’s book. It’s one of the best I’ve read on the subject. In addition to this, check out the C# Language Ext library.

Reflection: The solution my colleague was working on is a “small” and non-mission-critical application. This being the case, it represented a low-risk way to try out a more functional approach to solving problems.

Reflection: The demo is a bit contrived because it wouldn’t make much sense to download emails and attachments separately.  It does however, I think demonstrate how you can compose multiple tasks together with a functional workflow.

Reflection: I debated using delegates, interfaces, or funcs for dependency injection. I ultimately settled on delegate instead of func because it could be declared once. I chose delegates over Interfaces so that I could just call a function instead of InterfaceName.Function.

Reflection: I considered putting CreateFolder inside the save method of the Attachment and Mail repository as I did with PathReader.Read, but part of the reason for creating the demo was to allow me to experiment with a more functional workflow and compose operations together via Map and Bind with the Either type.

Reflection: I considered making this demo part of a larger solution. I was particularly concerned about the Domain and how people might misunderstand or misuse what is illustrated in the demo in their own solution. For the demo, the domain is the Eagetmail Mail and Attachment classes, as well as the classes defined in the Domain layer. In a larger solution, these wouldn’t necessarily be the domain, that solution may have another domain problem it’s trying to solve. Here’s an example of how the demo projects might appear in a larger solution.

  • Presentation
    • YourSolution.Presentation.Site
  • Application
    • YourSolution.Application.Models
    • YourSolution.Application.Services
  • Domain
    • YourSolution.Domain.Models
    • YourSolution.Domain.Interfaces
    • YourSolution.Domain.Services
  • Infrastructure
    • Persistence
      • YourSolution.Infrastructure.Persistence.Services
    • Email
      • YourSolution.Infrastructure.Email.Models
      • YourSolution.Infrastructure.Email.Interfaces
      • YourSolution.Infrastructure.Email.Services
    • Tasks
      • YourSolution.Infrastructure.Tasks.Services
      • YourSolution.Infrastructure.Tasks.Runner
    • Logging
      • YourSolution.Infrastructure.Logging.Models
      • YourSolution.Infrastructure.Logging.Services
  • Tests
    • YourSolution…

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.

Note: You will need to change the mail server settings in App.config and perhaps the IsIncluded predicate in the domain to run the program without receiving errors.

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.

Functional Origami

I just released a FREE course on Udemy titled Functional Programming with Origami. The course utilizes Origami and C# to teach elemental constructs of Functional Programming.

A description of the course is given below. You can enroll in the course by clicking here. You can download the source code for this course by clicking here.

  • I took my inspiration for creating this course by remembering how one learns as a child. Whether it was learning to count on your fingers or the realization of symmetry, one comes to by building things with toy blocks.
  • The origami examples in this course are designed to help you understand what is being demonstrated via the code examples both visually and tactilely.
  • There are many code examples in this course written in C#, with each module’s examples building on the previous.
  • The core of this course centers around the types List, Option, and Either; you’ll learn what these types model and how they add an “effect” to other types.
  • The functions Return, Map and Bind are demonstrated in numerous code examples, and you’ll see how they can be “composed” and used together.
  • You’ll learn the difference between Total and Partial Functions and how to turn Partial Functions into Total Functions.
  • At the crescendo of this course, the “patterns” Functor and Monad are unveiled and explained in simple and easy-to-understand terms.
  • Toward the end of the course, you’ll be given links to several resources to help you continue your functional programming journey.

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.