Skip to content
This repository has been archived by the owner on Aug 18, 2023. It is now read-only.

Latest commit

 

History

History
723 lines (472 loc) · 25.1 KB

Slides.md

File metadata and controls

723 lines (472 loc) · 25.1 KB

class: center, middle

Analysis, Design and Software Architecture

Software Engineering Session 6

Helge Pfeiffer, Assistant Professor,
Research Center for Government IT,
IT University of Copenhagen, Denmark
[email protected]


class: center, middle

Info, Feedback, and Recap


Assignment feedback

  • Due to low attendance, Mikkel will not hold a separate run through of a possible solution to the assignments.
  • However, he will be in the Wednesday exercise session and can show/discuss an exemplary solution on demand.

Assignment 4: Groups Issue

  • How many of you work in groups as in assignment 3?
  • How many of you work in groups as published too late for assignment 4?

Then we do...


Important: Late submissions of assignments

In case you did not yet submit your solution to assignment 02 due to some unfortunate reason, you can do so before this Friday (Oct. 7th) 23:59.

You hand-in your late assignment via LearnIT (https://learnit.itu.dk/mod/assign/view.php?id=164797) by providing a link to your repository and by uploading a PDF file as specified in the original task description (https://github.com/itu-bdsa/assignment-02/blob/main/README.md)

Important, this is the final deadline for late hand-ins of assignment 02. If you do not submit your solution before the deadline, it cannot be approved. Remember approval of mandatory assignments is necessary to be eligible for the exam.

In case you got your assignment 02 already approved on LearnIT, please disregard this message.


class: center, middle

Some leftovers from last week


What is the problem with SOLID Design Principles and Design Smells?

  • Highly subjective
  • Cannot be measured objectively and automatically

--

I am not aware of scientific evidence that application of SOLID principles (or other design principles) in (agile) software engineering leads to more flexible, maintainable, and reusable software.

Some studies in that area that are non-conclusive with regards to the above are:


What is the problem with SOLID Design Principles and Design Smells?

The only thing that we know that matters is size. The smaller the better or the "Worse is better" design principle

Result: None of the 12 investigated smells was significantly associated with increased effort after we adjusted for file size and the number of changes; [...] File size and the number of changes explained almost all of the modeled variation in effort. Conclusion: The effects of the 12 smells on maintenance effort were limited. To reduce maintenance effort, a focus on reducing code size and the work practices that limit the number of changes may be more beneficial than refactoring code smells.

D.I.K. Sjøberg et al. "Quantifying the Effect of Code Smells on Maintenance Effort"

--

Good theses topics!

Studying effectiveness of certain design principles on flexibility, maintainability, or reusability of software are good thesis projects. Talk to me if you are interested.


Hmmm, why apply SOLID then?

This is the state of the art in software engineering.

We do not know better what works and what does not. For example the SOLID design principles are one "bid on" how to adapt object-oriented software for change.

Other people have other opinions on software design principles.

--

You can only criticize what you know and understand...

In the above, I only highlighted our lack of scientific evidence with respect to the effectiveness of SOLID principles.

I did not mean to say that they are thereby irrelevant and that you do not have to know them!


The Unix philosophy

  1. Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new "features".
  2. Expect the output of every program to become the input to another, as yet unknown, program. Don't clutter output with extraneous information. Avoid stringently columnar or binary input formats. Don't insist on interactive input.
  3. Design and build software, even operating systems, to be tried early, ideally within weeks. Don't hesitate to throw away the clumsy parts and rebuild them.
  4. Use tools in preference to unskilled help to lighten a programming task, even if you have to detour to build the tools and expect to throw some of them out after you've finished using them.

https://en.wikipedia.org/wiki/Unix_philosophy


KISS, YAGNI, CUPID, ...

  • Keep It Simple Stupid (KISS) or Keep It Small And Simple

    The principle is best exemplified by the story of Johnson handing a team of design engineers a handful of tools, with the challenge that the jet aircraft they were designing must be repairable by an average mechanic in the field under combat conditions with only these tools. Hence, the "stupid" refers to the relationship between the way things break and the sophistication available to repair them.

    https://en.wikipedia.org/wiki/KISS_principle

--

--

  • CUPID Design Principles
    • Composable: plays well with others
    • Unix philosophy: does one thing well
    • Predictable: does what you expect
    • Idiomatic: feels natural
    • Domain-based: the solution domain models the problem domain in language and structure

    Dan North "CUPID—for joyful coding"


How do tools assess SOLID design?

For example, NDepend is a code quality assessment tool. In a blog post, the company behind the tool explains how to "Use NDepend to Measure How SOLID Your Code Is" via the following static analysis rules:


How do tools assess SOLID design?

Not at all, they focus on other (similar) design principles. For example, BetterCodeHub/Sigrid assess the following ten guidelines via static analysis rules, see J. Visser et al.Building Maintainable Software, C# Edition: Ten Guidelines for Future-Proof Code:

  1. Write Short Units of Code
  2. Write Simple Units of Code
  3. Write Code Once
  4. Keep Unit Interfaces Small
  5. Separate Concerns in Modules
  6. Couple Architecture Components Loosely
  7. Keep Architecture Components Balanced
  8. Keep Your Codebase Small
  9. Automate Tests
  10. Write Clean Code

class: center, middle

Design Patterns


Design Patterns in other domains


Design Patterns in other domains


Inspiration from A Pattern Language

Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice

C. Alexander et al. (1977) A Pattern Language: Towns, Buildings, Construction


Inspiration from A Pattern Language

Pattern 11: Local Transport Areas

Source: C. Alexander et al. (1977) A Pattern Language: Towns, Buildings, Construction.

What are Design Patterns?

Patterns and Pattern Languages are ways to describe best practices, good designs, and capture experience in a way that it is possible for others to reuse this experience.

https://hillside.net/patterns

--


Patterns have made a huge impact on object-oriented software design. As well as being tested solutions to common problems, they have become a vocabulary for talking about a design. You can therefore explain your design by describing the patterns that you have used.

Sommerville "Software Engineering"


Design Patterns in Software Engineering

... are something fairly recent. In 1994, Gamma, Helm, Johnsen, and Vlissides (Gang of Four Book) published their book on Design Patterns in object-oriented software.


What are Design Patterns?

Point of view affects one's interpretation of what is and isn't a pattern. One person's pattern can be another person's primitive building block. For this book we have concentrated on patterns at a certain level of abstraction. Design patterns are not about designs such as linked lists and hash tables that can be encoded in classes and reused as is. Nor are they complex, domain-specific designs for an entire application or subsystem. The design patterns in this book are descriptions of communicating objects and classes that are customized to solve a general design problem in a particular context.

E. Gamma et al. Design Patterns

--


Design of what?

Class structures or behavior of object-oriented systems. Note, still quite fine-grained. Not on architectural level yet. We will talk about patterns of more high-level design next week.

--


Important!

The choice of programming language is important because it influences one's point of view. Our patterns assume Smalltalk/C++-level language features, and that choice determines what can and cannot be implemented easily. If we assumed procedural languages, we might have included design patterns called "Inheritance," "Encapsulation," and "Polymorphism."

E. Gamma et al. Design Patterns


Design Patterns

After looking at principles of good object-oriented design, we are now looking at design patterns.

You read about the following design patterns so far:

  1. Command (APPP)
  2. Active Object (APPP)
  3. Template Method (APPP)
  4. Strategy (APPP)
  5. Facade (APPP)
  6. Mediator (APPP)
  7. Singleton (APPP)
  8. Monostate (APPP)
  9. Null Object (APPP)
  10. Observer (SE)
  11. Service Locator (Fowler)
  12. Dependency Injection (Fowler)

You will read about some more during the fall break.


Gang of Four Book: Design Patterns

Note, not all design patterns originate from the GoF Design Patterns book.

  • Creational Patterns
    1. Singleton
  • Structural Patterns
    1. Facade
  • Behavioral Patterns
    1. Command
    2. Mediator
    3. Strategy
    4. Template Method
    5. Observer

  1. Null Object
  2. Active Object
  3. Monostate
  4. Service Locator
  5. Dependency Injection

Relations of Design Patterns according to GoF


Quiz: Which pattern is this?


Command Pattern

Intent Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

Source: Gamma et al. Design Patterns.


Template Method

Intent Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

Gamma et al. Design Patterns.

Source: Design Patterns: Template Method.


Strategy Pattern

Intent Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Gamma et al. Design Patterns.

Source: Example adapted from Design Patterns in UML.


Facade Pattern: Imposing Policy

Intent Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.

Gamma et al. Design Patterns.


Mediator Pattern

Intent Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

Gamma et al. Design Patterns.

Source: E. Gamma et al. Design Patterns.

Null Object Pattern

By using this pattern, we can ensure that functions always return valid objects, even when they fail. Those objects that represent failure do “nothing.”

Robert C. Martin et al. "Agile Principles, Patterns, and Practices in C#"

Source: Design Patterns: Null Object.

Alternatives to Null Object Pattern in C♯?

List<string> list = null;
int count;
if (list != null)
{
    count = list.Count;
}
else
{
    count = 0;
}
List<string> list = null;
int count = list?.Count ?? 0;
Source: Enterprise Craftsmanship Blog.

Null-object pattern can be seen as a special case of the Strategy pattern

https://en.wikipedia.org/wiki/Null_object_pattern#C#


Observer pattern

Intent Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Gamma et al. Design Patterns.


Observer pattern in C♯/.Net

See https://learn.microsoft.com/en-us/dotnet/standard/events/observer-design-pattern


Composition or delegation over Inheritance???

Inheritance hierarchy of WPF:

Like most brave new worlds, this one turned out to be a bit too starry-eyed. By 1995, it was clear that inheritance was very easy to overuse and that overuse of inheritance was very costly. Gamma, Helm, Johnson, and Vlissides went so far as to stress: “Favor object composition over class inheritance.” So we cut back on our use of inheritance, often replacing it with composition or delegation.

Robert C. Martin et al. "Agile Principles, Patterns, and Practices in C#"

What is the implication of this?


Design Patterns Cheatsheet

<iframe src="http://www.mcdonaldland.info/files/designpatterns/designpatternscard.pdf" width="80%" height=500 scrolling="auto"></iframe>

Scientist's opinion about design patterns

We show that, contrary to popular beliefs, design patterns in practice impact negatively several quality attributes, thus providing concrete evidence against common lore. [...] we bring further evidence that design patterns should be used with caution during development because they may actually impede maintenance and evolution.

F. Khomh et al. "Do Design Patterns Impact Software Quality Positively?"


class: center, middle

Non-OO Design Patterns


Concurrency Patterns (in Go)

Next time with Rasmus, you are going to talk about concurrency.

There exists a plethora of design patterns only for that (might be relevant for your Distributed Systems course).

Source: Visualizing Concurrency in Go.

Concurrency Patterns (in Go)

For example, Pools of Workers in Go:

func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Println("worker", id, "started  job", j)
        time.Sleep(time.Second)
        fmt.Println("worker", id, "finished job", j)
        results <- j * 2
    }
}

func main() {
    const numJobs = 5
    jobs := make(chan int, numJobs)
    results := make(chan int, numJobs)

    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }

    for j := 1; j <= numJobs; j++ {
        jobs <- j
    }
    close(jobs)

    for a := 1; a <= numJobs; a++ {
        <-results
    }
}
Source: Go by Example: Worker Pools.

Composition over Inheritance example in Python

class Logger:
    def __init__(self, filters, handlers):
        self.filters = filters
        self.handlers = handlers

    def log(self, message):
        if all(f.match(message) for f in self.filters):
            for h in self.handlers:
                h.emit(message)

class TextFilter:
    def __init__(self, pattern):
        self.pattern = pattern

    def match(self, text):
        return self.pattern in text

class FileHandler:
    def __init__(self, file):
        self.file = file

    def emit(self, message):
        self.file.write(message + '\n')
        self.file.flush()

class SocketHandler:
    def __init__(self, sock):
        self.sock = sock

    def emit(self, message):
        self.sock.sendall((message + '\n').encode('ascii'))
Source: Python Design Patterns.

Composition over Inheritance example in Ruby

module Debug
  def whoAmI?
    "#{self.type.name} (\##{self.id}): #{self.to_s}"
  end
end
class Phonograph
  include Debug
  # ...
end
class EightTrack
  include Debug
  # ...
end
ph = Phonograph.new("West End Blues")
et = EightTrack.new("Surrealistic Pillow")
ph.whoAmI?  »   "Phonograph (#537766170): West End Blues"
et.whoAmI?  »   "EightTrack (#537765860): Surrealistic Pillow"
Source: Programming Ruby: Modules.

Your turn!

Via LearnIT Hand-in, hand-in a link to the Git repository on GitHub with your solution, at latest on Friday at 10:00.