Intro to Software Architecture and Design

Presented by Raman But-Husaim

Agenda

  • Who Is This Guy?
  • Architecture...what?
  • Layers, tiers, layers...
  • S.O.L.I.D.
  • Q&A

Who is this guy?

Lead Software Engineer at

12+ years of programming

7+ years in production

 

Master's Degree in Software Engineering

 

Microsoft Certified Specialist

Raman But-Husaim

Software Architecture

Software Architecture

Definition

Software application architecture is the process of defining a structured solution that meets all of the technical and operational requirements, while optimizing common quality attributes such as performance, security, and manageability.

by some guy at Microsoft

Software Architecture

Importance

  • Communication among stakeholders.
  • Early design decisions.
  • Transferable abstraction of a system.

Software Architecture

Goals

Software Architecture

Goals

  • Expose the structure of the system but hide the implementation details.
  • Realize all of the use cases and scenarios.
  • Try to address the requirements of various stakeholders.
  • Handle both functional and quality requirements.

Software Architecture

* Architecture

  • Client-server architecture
  • Data-centric architecture
  • Monolithic architecture
  • Event-driven architecture
  • Microservice architecture
  • Service-oriented architecture
  • Shared-nothing architecture
  • ...

Software Architecture

Typical project

Monolith

Microservices

Software Architecture

Difficulties

n-tier/n-layer architecture

Source: http://www.myrecipes.com/recipe/rainbow-layer-cake

n-tiers

Tier refers to physical distribution patterns

n-tiers

Benefits

  • Maintainability
  • Scalability
  • Flexibility
  • Availability

n-layers

Layers are concerned with the logical division of components and functionality

  • presentation layer
  • business layer
  • data layer
  • ...

n-layers

Concepts

Layer interaction rules

  • top-down interaction
  • strict interaction
  • loose interaction

Layer interfaces

  • abstract interface
  • dependency inversion
  • message-based

n-layers

Benefits

  • Abstraction
  • Isolation
  • Manageability
  • Performance
  • Reusability
  • Testability

S.O.L.I.D.

Source: http://mixedsign.com/tag/concept-art-world/page/5/

S.O.L.I.D.

  • S - Single Responsibility Principle (SRP)
  • O - Open-Closed Principle
  • L - Liskov Substitution Principle
  • I - Interface Segregation Principle
  • D - Dependency Inversion Principle (DIP)

Source: Telegram Great Minds sticker pack

S.O.L.I.D.

Single Responsibility Principle

A class should have only one reason to change.

Gather together the things that change for the same reasons. Separate those things that change for different reasons.

by Robert C. Martin

OR

S.O.L.I.D.

Single Responsibility Principle

Source: https://vikingmarine.ie/products/victorinox-skipper-mutli-tool

S.O.L.I.D.

Single Responsibility Principle

public sealed class Page
{
    private readonly Book book;

    public Page(Book book)
    {
        this.book = book;
    }

    public string Content => "something";

    public override string ToString()
    {
        return Content;
    }
}
public sealed class Book
{
    public string Title => "Hyperion";

    public string Author => "Dan Simmons";

    public Page GetCurrentPage()
    {
        return new Page(this);
    }

    public void PrintCurrentPage()
    {
        Console.WriteLine(GetCurrentPage());
    }
}

Source: Telegram Great Minds sticker pack

S.O.L.I.D.

Single Responsibility Principle

public sealed class Book
{
    public string Title => "Hyperion";

    public string Author => "Dan Simmons";

    public Page GetCurrentPage()
    {
        return new Page(this);
    }
}

public interface IPagePrinter
{
    void PrintPage(Page page);
}

Source: Telegram Great Minds sticker pack

public class TextPagePrinter : IPagePrinter
{
    public void PrintPage(Page page)
    {
        Console.WriteLine(page.ToString());
    }
}

public class HtmlPagePrinter : IPagePrinter
{
    public void PrintPage(Page page)
    {
        var content = $"<div>" +
                      $"{page.Content}" +
                      $"</div>";

        Console.WriteLine(content);
    }
}

S.O.L.I.D.

Open-Closed Principle

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

by Bertrand Mayer

S.O.L.I.D.

Open-Closed Principle

public abstract class Shape
{
}

public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }
}

public class Circle : Shape
{
    public double Radius { get; set; }
}
public class AreaCalculator
{
    public double CalculateArea(Shape[] shapes)
    {
        double area = 0;

        foreach (var shape in shapes)
        {
            if (shape is Rectangle)
            {
                Rectangle rectangle = (Rectangle) shape;
                area += rectangle.Width * rectangle.Height;
            }
            else
            {
                Circle circle = (Circle) shape;
                area += circle.Radius 
                        * circle.Radius 
                        * Math.PI;
            }
        }

        return area;
    }
}

Source: Telegram Great Minds sticker pack

S.O.L.I.D.

Open-Closed Principle

public abstract class Shape
{
    public abstract double CalculateArea();
}

public class Rectangle : Shape
{
    public double Width { get; set; }
    public double Height { get; set; }

    public override double CalculateArea()
    {
        return Width * Height;
    }
}

public class Circle : Shape
{
    public double Radius { get; set; }

    public override double CalculateArea()
    {
        return Radius * Radius * Math.PI;
    }
}
public class AreaCalculator
{
    public double CalculateArea(Shape[] shapes)
    {
        double area = 0;
        foreach (var shape in shapes)
        {
            area += shape.CalculateArea();
        }

        return area;
    }
}

Source: Telegram Great Minds sticker pack

S.O.L.I.D.

Liskov Substitution Principle

Derived class objects must be substitutable for the base class objects. That means objects of the derived class must behave in a manner consistent with the promises made in the base class' contract.

from http://wiki.c2.com/?LiskovSubstitutionPrinciple

S.O.L.I.D.

Liskov Substitution Principle

Source: Telegram Great Minds sticker pack

public class Rectangle
{
    public virtual double Width { get; set; }

    public virtual double Height { get; set; }
}

public class Square : Rectangle
{
    private double width;
    private double height;

    public override double Width
    {
        get => width;
        set
        {
            width = value;
            height = value;
        }
    }

    ...
    public override double Height
    {
        get => height;
        set
        {
            width = value;
            height = value;
        }
    }
}

public sealed class Client
{
    public void VerifyArea(Rectangle rect)
    {
        rect.Width = 20;
        rect.Height = 4;

        // expected area - 80
        // actual - 16
    }
}

S.O.L.I.D.

Liskov Substitution Principle

  1. Preconditions cannot be strengthened in a subtype.
  2. Postconditions cannot be weakened in a subtype.
  3. Invariants of the supertype must be preserved in a subtype.
  4. No new exceptions should be thrown by methods of the subtype, except where those exceptions are themselves subtypes of exceptions thrown by the methods of the supertype.

S.O.L.I.D.

Interface Segregation Principle

Clients should not be forced to depend on methods that they do not use.

by Robert C. Martin

S.O.L.I.D.

public interface ILogger
{
    void Log(string message);

    void OpenConnection();

    void CloseConnection();

}

public class DBLogger : ILog
{
    public void Log(string message)
    {
        ...
    }

    public void OpenConnection()
    {
        ...
    }

    public void CloseConnection()
    {
        ...
    }
}

Interface Segregation Principle

public class FileLogger : ILog
{
    public void Log(string message)
    {

        ...          
    }
}

Source: Telegram Great Minds sticker pack

S.O.L.I.D.

public interface ILogger
{
    void Log(string message);
}

public interface IDBLog: ILog
{
    void OpenConnection();

    void CloseConnection();
}

public interface IFileLog: ILog
{
    long GetFileSize();
}

Interface Segregation Principle

Source: Telegram Great Minds sticker pack

S.O.L.I.D.

Dependency Inversion Principle

High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend upon details. Details should depend upon abstractions.

by Robert C. Martin

S.O.L.I.D.

Dependency Inversion Principle

Example: С. Тепляков "Паттерны проектирования на платформе .NET"

S.O.L.I.D.

Dependency Inversion Principle

public interface IReportFormatter
{
    string FormatReport(Report report);
}

public class Reporter
{
    private readonly IReportFormatter formatter;

    public Reporter(IReportFormatter formatter)
    {
        this.formatter = formatter;
    }

    public void SendReport(Report report)
    {
        var formattedReport = this.formatter.FormatReport(report);
        SendFormattedReport(formattedReport);
    }

    private void SendFormattedReport(string formattedReport)
    {}
}

Example: С. Тепляков "Паттерны проектирования на платформе .NET"

S.O.L.I.D.

Dependency Inversion Principle

class XlsFormatter : IReportFormatter
{
    public string FormatReport(Report report)
    {
    }
}

class Application
{
    public void Run()
    {
        var reporter = new Reporter(new XlsFormatter());
        reporter.SendReport(GenerateReport());
    }
}

Example: С. Тепляков "Паттерны проектирования на платформе .NET"

S.O.L.I.D.

DIP vs IoC vs DI

  1. Dependency Injection (DI) -  is about how one object knows about another, dependent object.
  2. Inversion of Control (IoC) - is about who initiates messages.
  3. Dependency Inversion Principle (DIP) - is about the shape of the object upon which the code depends.

S.O.L.I.D.

Inversion of Control

S.O.L.I.D.

Dependency Injection

Source: http://brandonclapp.com/what-is-dependency-injection-and-why-is-it-useful/

S.O.L.I.D.

Dependency Injection

Dependency Injection is a set of software design principles and patterns
that enable us to develop loosely coupled code.

by Mark Seemann

S.O.L.I.D.

Dependency Injection

When you go and get things out of the refrigerator for yourself, you can cause problems. You might leave the door open, you might get something Mommy or Daddy doesn’t want you to have. You might even be looking for something we don’t even have or which has expired.


What you should be doing is stating a need, “I need something to drink with lunch,” and then we will make sure you have something when you sit down to eat.

by John Munch

S.O.L.I.D.

Dependency Injection

Benefits of DI

  1. Late Binding - Services can be swapped with other services.
  2. Extensibility - Code can be extended and reused in ways not explicitly planned for.
  3. Parallel development - Code can be developed in parallel.
  4. Maintainability - Classes with clearly defined responsibilities are easier to maintain.
  5. Testability - Classes can be unit tested.

S.O.L.I.D.

Dependency Injection

Stable Dependencies - challenge DI

  1. The class or module already exists.
  2. You expect that new versions won’t contain breaking changes.
  3. The types in question contain deterministic algorithms.
  4. You never expect to have to replace the class or module with another.

S.O.L.I.D.

Dependency Injection

Volatile Dependencies - use DI

  1. The dependency is in development.
  2. The dependency isn’t installed on all machines in the development organization.
  3. The dependency contains nondeterministic behavior.

S.O.L.I.D.

DI Pattern: Constructor Injection

public interface IWeapon
{
    void Hit(string target);
}

public sealed class Samurai
{
    private readonly IWeapon weapon;

    public Samurai(IWeapon weapon) 
    {
        this.weapon = weapon;
    }

    public void Attack(string target) 
    {
        this.weapon.Hit(target);
    }
}

Source: https://softwareengineering.stackexchange.com/a/177661

Constructor should be your default choice for DI. It addresses the most
common scenario where a class requires one or more dependencies, and no reasonable
local defaults are available.

S.O.L.I.D.

DI Pattern: Property Injection

public interface IDependency
{
}

internal class DefaultDependency : IDependency
{ }

public class CustomService
{
     public CustomService()
     {
         Dependency = new DefaultDependency();
     }

     public IDependency Dependency { get; set; }
}

Source: http://sergeyteplyakov.blogspot.de/2013/01/di-property-injection.html

Should only be used when the class you’re developing has a good
local default and you still want to enable callers to provide different implementations
of the class’s dependency.

S.O.L.I.D.

DI Pattern: Method Injection

public string DoStuff(SomeValue value, ISomeContext context)
{
    if (context == null)
    {
        throw new ArgumentNullException(nameof(context));
    }

    return context.Name;
}

Source: http://sergeyteplyakov.blogspot.de/2013/02/di-method-injection.html

 Best used when the dependency can vary with each method call.
This can be the case when the dependency itself represents a value.

S.O.L.I.D.

DI Anti-Patterns

  1. Control freak
  2. Bastard injection
  3. Constrained construction
  4. Service locator

Source: Telegram Great Minds sticker pack

S.O.L.I.D.

Code Example

Source: Telegram Great Minds sticker pack

Q&A

Source: https://www.amazon.com/Piece-Sleeping-Bubble-Cartoon-Sticker/dp/9099000626

Useful materials

Thanks!

Source: Telegram Great Minds sticker pack

Godel Mastery: Intro to Architecture

By Raman But-Husaim

Godel Mastery: Intro to Architecture

A basic introduction to software architecture.

  • 715