Software Development Principles & Patterns

Who even gives a ****?

  • I do.

My Software Development Principles

  • Unit Testing / Test Driven Development / Behaviour Driven Development
  • CQRS
    • Command and Query Responsibility Separation
  • SOLID
    • Single Responsibility Principle
    • Open/Closed Principle
    • Liskov’s Substitution Principle
    • Interface Segregation Principle
    • Dependency Inversion Principle
  • AOP
    • Aspect-Oriented Programming

Unit Testing

  • A unit as the smallest testable part of an application.
  • In object-oriented programming, a unit is often an entire interface, such as a class, but could be an individual method.
  • Unit tests are short code fragments created by programmers during the development process.
  • Ideally, each test case is independent from the others. Substitutes such as method stubs, mock objects, fakes, and test harnesses can be used to assist testing a module in isolation.
  • Unit tests are typically written and run by software developers to ensure that code meets its design and behaves as intended.

CQRS

  • Command and Query Responsibility Segregation
    • Segregate operations that read data from operations that update data by using separate interfaces.
    • This can maximize performance, scalability, and security.
    • Supports the evolution of the system over time through higher flexibility, and prevents update commands from causing merge conflicts at the domain level.

SOLID

  • Single responsibility principle
    • A class should have only a single responsibility (i.e. changes to only one part of the software’s specification should be able to affect the specification of the class).
  • Open/closed principle
    • Software entities should be open for extension, but closed for modification.
  • Liskov’s substitution principle
    • Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.
  • Interface segregation principle
    • Many client-specific interfaces are better than one general-purpose interface.
  • Dependency inversion principle
    • Depend upon abstractions, not concretions.

AOP

  • Aspect-oriented programming
    • Aims to encapsulate cross-cutting concerns into aspects to retain modularity.
    • Allows for the clean isolation and reuse of code addressing the cross-cutting concern.
    • By basing designs on cross-cutting concerns, software engineering benefits can include modularity and simplified maintenance.
  • The Decorator Pattern
    • In object-oriented programming, the decorator pattern is a design pattern that allows behaviour to be added to an individual object, dynamically, without affecting the behaviour of other objects from the same class. 
    • Often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern. 

Sidebar: The Decorator Pattern

IAmADrink drink = new Coffee();
drink = new AddCreamDecorator(drink);
drink = new AddSugarDecorator(drink);
drink.Make();

public interface IAmADrink
{
    void Make();
}

public class Coffee : IAmADrink
{
    public void Make()
    {
        Console.Clear();
        Console.WriteLine("Coffee granules and hot water");
    }
}

public class AddCreamDecorator : IAmADrink
{
    private readonly IAmADrink decoratee;

    public AddCreamDecorator(IAmADrink decoratee)
    {
        this.decoratee = decoratee;
    }

    public void Make()
    {
        this.decoratee.Make();
        Console.WriteLine("Add a splash of cream");
    }
}

public class AddSugarDecorator : IAmADrink
{
    private readonly IAmADrink decoratee;

    public AddSugarDecorator(IAmADrink decoratee)
    {
        this.decoratee = decoratee;
    }

    public void Make()
    {
        this.decoratee.Make();
        Console.WriteLine("Add a cube of sugar");
    }
}

Sidebar: Generics

  • Generics refers to the technique of writing the code for a class without specifying the data type(s) that the class works on.
  • You specify the data type when you declare an instance of a generic class. This allows a generic class to be specialized for many different data types while only having to write the class once
  • A great example are the many collection classes in .NET. Each collection class has it’s own implementation of how the collection is created and managed. But they use generics to allow their class to work with collections of any type.
IList<string> strings = new List<string>();
strings.Add("abc");
IList<Client> clients = new List<Client>();
clients.Add(new Client());

One Interface For All Commands & Queries

Command Handler:

public interface ICommandHandler<TCommand> where TCommand
{
    void Execute(TCommand command);
}

Query Handler:

public interface IQueryHandler<TQuery, TResult> where TQuery : IReturn<TResult>
{
    TResult Execute(TQuery query);
} 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.