Gergő Pintér, PhD
gergo.pinter@uni-corvinus.hu
a paradigm principle example in functional programming, in addition to OOP’s from week 4
a paradigm principle example in functional programming, in addition to OOP’s from week 4
creational
structural
behavioral
read about the design patterns in details, for example at refactoring.guru
The bridge pattern lets you split a large class or a set of closely related classes into two separate hierarchies.
more at: refactoring.guru / Observer
class Observable:
def __init__(self):
self.subscribers = []
def subscribe(self, subscriber):
self.subscribers.append(subscriber)
def notify(self, data):
for subscriber in self.subscribers:
subscriber.update(data)
class Subscriber: # aka Observer
def __init__(self, name):
self.name = name
def update(self, data):
print(f"{self.name} received data: {data}")class TemperatureSensor(Observable):
def __init__(self):
super().__init__()
def change_temperature(self, temp):
print(f"Temperature changed to: {temp}")
self.notify(temp)
class DisplayUnit(Subscriber):
def update(self, temp):
print(f"{self.name} updated with temperature: {temp}")sensor = TemperatureSensor() # create observable
display1 = DisplayUnit("Display 1") # create observer
display2 = DisplayUnit("Display 2") # create observer
sensor.subscribe(display1)
sensor.subscribe(display2)
sensor.change_temperature(25) # change valueTemperature changed to: 25
Display 1 updated with temperature: 25
Display 2 updated with temperature: 25
example code is based on: Observer Pattern in Functional Reactive Programming (FRP)
| OO pattern | FP pattern |
|---|---|
| factory pattern | function |
| strategy pattern | function |
| decorator pattern | function |
| visitor pattern | function |
| … | … |
Peter Norvig demonstrated that 16 out of the 23 patterns are simplified or eliminated by language features in Lisp or Dylan (1998) [3]
more about it from Scott Wlaschin [4]
some FP design patterns
map
apply a function to each item and produce a new collection
filter
filter the collection to include only those elements that evaluate to true using the provided function
reduce
distill the collection down into a single value
examples and definitions are from Elixir School by Sean Callan
Always implement things when you actually need them, never when you just foresee that you need them.
extreme programming
SOLID is a mnemonic acronym for five design principles intended to make object-oriented designs more understandable, flexible, and maintainable [5]
a class should do one thing and therefore it should have only a single reason to change
Unix philosophy
Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new “features”.
advantages
classes should be open for extension and closed to modification
class Shape:
pass
class Square(Shape):
def __init__(self, width: float):
self.width = width
class Circle(Shape):
def __init__(self, radius: float):
self.radius = radius
class AreaCalculator:
def sum(self, shapes: list[Shape]) -> float:
result = 0
for shape in shapes:
if isinstance(shape, Square):
result += shape.width**2
elif isinstance(shape, Circle):
result += shape.radius**2 * math.pi
return round(result, 2)example based on [6]
class Shape:
pass
class AreaInterface:
def area(shape: Shape) -> float:
pass
class Square(Shape, AreaInterface):
def __init__(self, width: float):
self.width = width
def area(self) -> float:
return self.width**2
class Circle(Shape, AreaInterface):
def __init__(self, radius: float):
self.radius = radius
def area(self) -> float:
return round(self.radius**2 * math.pi, 2)
class AreaCalculator:
def sum(self, shapes: list[Shape]) -> float:
return sum([i.area() for i in shapes])example based on [6]
if class A is a subtype of class B, B should be able to replaced with A without disrupting the behavior of the program [7]
class Rectangle:
def __init__(self, width: int, height: int):
self.__width = width
self.__height = height
def setWidth(self, width: int):
self.__width = width
def setHeight(self, height: int):
self.__height = height
def getWidth(self):
return self.__width
def getHeight(self):
return self.__height
def getArea(self):
return self.__width * self.__heightcode is based on [10]
def getAreaTest(r: Rectangle):
width = r.getWidth() # width is 2
r.setHeight(10)
return f"Expected area of {width * 10}, got {r.getArea()}">>> r = Rectangle(2, 3)
>>> print(r.getArea())
6
>>> s = Square(2)
>>> print(s.getArea())
4
>>> print(getAreaTest(r)) # rectangle
Expected area of 20, got 20
>>> print(getAreaTest(s)) # square
Expected area of 20, got 100this example violates the Liskov substitution principle
code is based on [10]
states that many client-specific interfaces are better than one general-purpose interface. Clients should not be forced to implement a function they do no need.
example based on [6]
Dependency inversion principle says that modules should depend upon interfaces or abstract classes, not concrete classes. It’s an inversion because implementations depend upon abstractions and not the other way round. [7]
increases reusability
don’t call us, we’ll call you
based on [11], Three Design Patterns That Use Inversion of Control by Alejandro Gervasio
In the social sciences, unintended consequences (more colloquially called knock-on effects) are outcomes of a purposeful action that are not intended or foreseen. [13]
source: Laws of Software Engineering / Law of Unintended Consequences by Dr. Milan Milanović
An object should only interact with its immediate friends, not strangers.
– Ian Holland et al. (1987) [14]
source: Laws of Software Engineering / Law of Demeter by Dr. Milan Milanović
source: Laws of Software Engineering / Law of Demeter by Dr. Milan Milanović
source: Layers in software architecture by Sagar Hudge [15]
source: Layers in software architecture by Sagar Hudge [15]
source: Layers in software architecture by Sagar Hudge [15]
source: Layers in software architecture by Sagar Hudge [15]
source: Layers in software architecture by Sagar Hudge [15]
source: Layers in software architecture by Sagar Hudge [15]
models
delivery guaranties
number of layers in a layered architecture is not set to a specific number
advantages
disadvantages
based on [20]
based on [21]
based on [17]
based on [17]
can be extend without changing the business logic
it is very similar to the onion and (the clean architecture [23])
based on [17]
ASP.NET, Django (Python), Ruby on Rails, Laravel (PHP)
Windows Forms, Java Swing
WPF, AngularJS
figures based on [25]
other alternatives: Alternatives To MVC - by Anthony Ferrara
tight coupling between layers
source: Layers in software architecture by Sagar Hudge [15]
source: Layers in software architecture by Sagar Hudge [15]
source: Layers in software architecture by Sagar Hudge [15]
All non-trivial abstractions, to some degree, are leaky.
– Joel Spolsky
source: Wikipedia / Leaky abstraction [26]
as a user I want to see my activity to see my progress
send everything to the UI
in this case the UI has to calculate the daily activity
send only the aggregated data
data collector still has the whole user data but that aligns with its purpose
data aggregator calculates everything and the UI only displays it
UI might be on a client
different code base, different language
make the database aggregate the data
on the other hand, most of these are present in all the three architectures!
Architecture represents the significant design decisions that shape a system, where significant is measured by cost of change. – Grady Booch
Developers working on that project have a shared understanding of the system design. […] This understanding includes how the system is divided into components and how the components interact through interfaces. – Ralph Johnson
# Title
## Status
What is the status, such as proposed, accepted, rejected, deprecated, superseded, etc.?
## Context
What is the issue that we're seeing that is motivating this decision or change?
## Decision
What is the change that we're proposing and/or doing?
## Consequences
What becomes easier or more difficult to do because of this change?ADR template by Michael Nygard from Documenting architecture decisions, where each architecture decision record have these sections.
based on Why Write ADRs by Eli Perkins
| architectural patterns | model-view-controller, MVP, MVVM |
| architectural styles | layered, onion, hexagonal, clear, client-server |
| architectural principles | coupling & cohesion |
| design patterns | GOF, map-filter-reduce |
| desing principles | SOLID, DRY, YAGNI, hollywood principle |