class: center, middle
Helge Pfeiffer, Assistant Professor,
Research Center for Government IT,
IT University of Copenhagen, Denmark
[email protected]
class: center, middle
- 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.
- 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...
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
- 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:
- Measuring Impact of Dependency Injection on Software Maintainability
- H.K. Jun et al. Evaluating the Impact of Design Patterns on Software Maintainability: An Empirical Evaluation
- J. Bräuer et al. Measuring object-oriented design principles: The results of focus group-based research
- G. Samarthyam et al. MIDAS: A design quality assessment method for industrial software
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"
--
Studying effectiveness of certain design principles on flexibility, maintainability, or reusability of software are good thesis projects. Talk to me if you are interested.
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.
--
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!
- Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new "features".
- 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.
- 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.
- 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.
- 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.
--
-
You Aren't Gonna Need It (YAGNI)
a principle which arose from extreme programming (XP) that states a programmer should not add functionality until deemed necessary.
--
- 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
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:
- Avoid Types Too Big (SRP)
- Avoid Types With Too Many Methods (SRP)
- Avoid Types With Too Many Fields (SRP)
- Avoid Methods That Are Too Big and Too Complex (SRP)
- Avoid Methods With Too Many Parameters (SRP)
- Avoid Methods With Too Many Local Variables (SRP)
- Base class should not use derivatives (OCP)
- Do implement methods that throw NotImplementedException (LSP)
- Avoid interfaces too big (ISP)
- Higher cohesion - lower coupling (DIP)
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:
- Write Short Units of Code
- Write Simple Units of Code
- Write Code Once
- Keep Unit Interfaces Small
- Separate Concerns in Modules
- Couple Architecture Components Loosely
- Keep Architecture Components Balanced
- Keep Your Codebase Small
- Automate Tests
- Write Clean Code
class: center, middle
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
Pattern 11: Local Transport Areas
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.
--
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"
... 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.
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
--
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.
--
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
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:
- Command (APPP)
- Active Object (APPP)
- Template Method (APPP)
- Strategy (APPP)
- Facade (APPP)
- Mediator (APPP)
- Singleton (APPP)
- Monostate (APPP)
- Null Object (APPP)
- Observer (SE)
- Service Locator (Fowler)
- Dependency Injection (Fowler)
You will read about some more during the fall break.
Note, not all design patterns originate from the GoF Design Patterns book.
- Creational Patterns
- Singleton
- Structural Patterns
- Facade
- Behavioral Patterns
- Command
- Mediator
- Strategy
- Template Method
- Observer
- Null Object
- Active Object
- Monostate
- Service Locator
- Dependency Injection
- Navigate to https://menti.com
- Login to quiz with code: 6224 2647
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.
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.
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.
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.
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: Design Patterns: Null Object.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#"
List<string> list = null;
int count;
if (list != null)
{
count = list.Count;
}
else
{
count = 0;
}
List<string> list = null;
int count = list?.Count ?? 0;
Null-object pattern can be seen as a special case of the Strategy 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.
See https://learn.microsoft.com/en-us/dotnet/standard/events/observer-design-pattern
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?
<iframe src="http://www.mcdonaldland.info/files/designpatterns/designpatternscard.pdf" width="80%" height=500 scrolling="auto"></iframe>
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
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.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
}
}
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'))
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"
- Go to the exercise session.
- Work in your assignment triplet, see https://github.com/itu-bdsa/assignment-04/README_GROUPS.md
- Work on the exercises of the assignment, see https://github.com/itu-bdsa/assignment-04/README.md
Via LearnIT Hand-in, hand-in a link to the Git repository on GitHub with your solution, at latest on Friday at 10:00.