5. Decomposition
• Decomposing the multiplication of arrays to simpler contituents can result to a 30x speedup in
real-world applications*.
• Decomposing a system to smaller and simpler units can render it faster, more robust, more
scalable and easier to understand.
• Let the system be a mathematical construct, a software system, or a mechanical one.
• The principles come from Systems, not Software Engineering and can be applied to any man-
made system.
(*): Handbook of Robust Low-Rank and Sparse Matrix Decomposition, page: 181
8. Do we have small enough entropy to make an
accurate model of this?
9. What small entropy means?
• We have sufficient information for the system.
• If S = 0, we know absolutely everything for the system (from how
many molecules it consists, where every molecule is at every given
moment, it's temperature in picoKelvin, etc.).
• If S >>> 0 we know nothing for the system.
10. What it practically means for us?
• To successfully decompose a software system, we need to learn as
much as possible about it.
• Internal structure (employed architecture, layers, components,
classes, modules, etc.).
• Communication interfaces (between the layers, the components and
between the system and ist environment).
• Performance characteristis (speed, throughput, space, latency, etc.).
11. Preparation can make all the difference in a
re-architecting effort
Please do your homework before you start.
14. What about software decomposition?
We can decompose:
• Algorithms
• Software systems
• An object hierarchy
• A set of functional relationships
15. Algorithm decomposition
• The basic analysis tool for structured programming (what you were
doing when you were 16).
• Coming from the prehistoric times (COBOL & Algol-60).
• The main principle is to break down long sequences of spaghetti code
to a structured set of subroutines, blocks and loops.
• Its basis is the Böhm-Jacopini theorem.
16. What did Böhm and Jacopini said in 1966
A class of control-flow graphs cam compute any computable function if
it combines subprograms in only three specific ways (else control
structures):
• Execute subprograms in a sequential order.
• Execute one of two subprograms according to the value of a boolean
expression (selection).
• Execute a subprogram until a boolean expression is true (iteration).
17. Implications Böhm and Jacopini
• Software became more sane.
• A massive flame war started between academics on the degree it
should be adopted.
• It bootstrapped many other engineering methods which we use until
today.
18. Like Harlan Mill's COBOL Structuring Facility
1. Identify the basic blocks in the basic blocks in the basic blocks in the procedure.
2. Assign a unique label to each block's entry path, and label each block's exit paths with the labels of the
entry paths they connect to. Use 0 for return from the procedure and 1 for the procedure's entry label to
each block's entry path, and label each block's exit paths with the labels of the entry paths they connect
to. Use 0 for return from the procedure and 1 for the procedure's entry label to each block's entry path,
and label each block's exit paths with the labels of the entry paths they connect to. Use 0 for return from
the procedure and 1 for the procedure's entry path.
3. Break the procedure into its basic blocks.
4. For each block that is the destination of only one exit path, reconnect that block to that exit path.
5. Declare a new variable in the procedure (called L for reference).
6. On each remaining unconnected exit path, add a statement that sets L to the label value on that path.
7. Combine the resulting programs into a selection statement that executes the program with the entry path
label indicated by L
8. Construct a loop that executes this selection statement as long as L is not 0.
9. Construct a sequence that initializes L to 1 and executes the loop.
20. Take away
• Complicated logic can (nearly) always be decomposed to simpler
elements.
• Simplifying control structures is always a good idea.
• Stick to simple constructs, everybody knows how smart you are.
• Read Knuth's 'Art of Computer Programming'.
21. Why bother with all these old-fashioned
stuff?
• Because monoliths contain long, messy snippets of code most of the
time.
• Breaking up a monolith to microservices is an excellent opportunity to
get rid off technical debt.
• You will get increased complexity and LoCs due to the need for
more communication interfaces. Try to offset it with cleaner and
leaner business logic.
22. Software System decomposition
(Structured Analysis)
• Invented in computings prehistoric times (1960s), became popular during
the bronze age (1980s).
• A tool which analyses the system's concept into system functions and data
entities, which reproduce the system's desired functionality.
• Super useful for decomposing complicated monoliths to smaller entities
(micro-services) which satisfy the same set of business requirements with
the monolith.
• De Marco's "Structured Analysis and System Specification" is one of the
best resources on the subject.
23. Aspects to analyze
• Structural units (top-down perspective, from the very generic to the
very specific).
• Code (classes, objects, modules, interface) and data
(primitives, collections, types, class members) entities.
• External (system to human users and other systems) and internal
(component to component) communication interfaces
• Data flows
30. Points of criticism
• Selecting entities properly (especially for data flow diagrams).
• Knowing in which level of abstraction to stop the analysis.
• Sizable amount of documentation may be needed to explain the diagrams.
• Prone to frequent changes, need to be maintained.
• Difficult to follow for non-techies.
31. Object-Oriented decomposition
• Object-Oriented programming inherently leads to modular code,
encapsulated in classes.
• Object-Oriented decomposition breaks up a system in a set of smaller
classes and objects which are modelling a specific entity or part of the
problem domain (or otherwise concerns).
• Very handy when composing microservices, since they naturally result
from concerns covered by a set of classes representing a specific
concern.
32. Vertical Decomposition
• The classes that consist a system that solves a business problem can
be vertically separated by the concerns they are satisfying.
• The level of abstraction of the concerns can depend on the size of the
application and technical aspects like:
• complexity of the business logic
• performance of specific code sections
• service tenancy model
• network performance characteristics
• hardware specifications and characteristics
34. Functional decomposition
• Another perspective which can be used in place of the Object-Oriented
decomposition in case you are using a functional programming language.
• It can also be used in tandem with the OO-decomposition and offer a
better description of the systems functional It can also be used in tandem
with the OO-decomposition and offer a better description of the systems
functional It can also be used in tandem with the OO-decomposition and
offer a better description of the systems functional behavior.
• The main idea is to describe the system by the set of functions as
prescribed by the requirements, decompose them in simpler constituents
and finally recostruct the wished behavior with function composition.
35. What is function composition?
• The application of one function to the result of another function
to produce another function.
(g ∘ f )(c) = #
Diagram source: Wikipedia
36. What is function composition? (cont.)
• Higher order functions as described by Lambda calculus (functions that take functions as
parameters).
>>> def twice(function):
... return lambda x: function(function(x))
>>> def f(x):
... return x + 3
>>> g = twice(f)
>>> print g(7)
13
37. Can we build our system only in terms of
functions?
• Yes!
• It has been done for decades with Lisp, Erlang and Haskell based
systems.
40. A monolith can be teared in many ways
• You will need to consider many factors, which will affect the resulting
microservice-based system.
• Communication: Asychronous, message based or synchronous, RESTful or RMI-
based?
• Data Persistence: Single data depot or polyglot persistence?
• Deployment scenarios: Single service per host or multiple services per host?
• Resource discovery: Client or server side discovery?
45. Scale Cube – Axes (cont.)
• Can we combine the aspects?
• Yes, but with a lot of caution, it is easy to come up with something
extremely complicated which will negate all benefits of
decomposition.
• Imagine having microservices responsible for different shards of the
dataset.
46. Customers
Information (H-Z)
Recommender
Engine
Application UI
Combining axes of the Scale Cube
• Apply Y-axis and Z-axis, scaling each service independently.
Application UI
Customers
Information
(A-G)
Application UI
Recommender
Engine
Billing Service
Partner UI
Customers
Information (H-Z)
48. A list of good advices
https://www.cycligent.com/blog/10-practical-tips-for-making-the-transition-to-microservices/
49. Tip #1: Break things off one at a time. Don’t try to componentize the
whole application at once.
50. Tip #2: Start with a component that is already not heavily dependent
on the rest of the application. The first break should be simple and a
way to ease into the process.
51. Tip #3: Try to find components of the application that only serve one
function. The simpler the service, the easier it will be to maintain.
52. Tip #4: Create teams around a component of the application before it
gets broken off into a separate service. Once in place, they can then
work towards segmentation of their component into a microservice.
53. Tip #5: Do daily scrum meetings discussions, and then have a weekly
scrum meeting to get updates on the major aspects of the
development process. Once transitioned into microservices, the weekly
meetings can be on an as needed basis.
54. Tip #6: Automate and document the build, test, and deployment
process so that it can scale with the microservices architecture with
ease.
55. Tip #7: Invest in tools such as Cycligent that will automate or simplify
things for the development team, so they can focus on application
development and less about the complexity of microservices.
56. Tip #8: Create company-wide processes that requires developers to talk
to managers about introducing new technologies.
57. Tip #9: Ensure that there are multiple developers that are trained in
any new technologies introduced into the application. If a developer
goes on vacation, you will want to make sure someone else can quickly
and effectively fix any issues that may come about.
58. Tip #10: Carefully evaluate uncommon or more obscure technologies.
With the added complexity of a microservices architecture, the last
thing to worry about is whether or not there are any hidden issues as a
result of a new technology.