Title: Separation of Concerns The power of modularity
1Separation of ConcernsThe power of modularity
- Mario Cardinal
- Software Architect
- .Net Expertise
Agile 2008
2Why are we here?What problem do we try to solve?
How to modularize concerns
Reduce Complexity
3Who am I ?
- Independent senior consultant specialized in
software architecture - www.mariocardinal.com
4AgendaHow to reduce complexity?
The real voyage of discovery consists, not in
seeking new landscapes, but in having new
eyes Marcel Proust
5ModularityComplexity
- If ?
- A complex system can no longer be made by a
single person - A very complex system can no longer be
comprehended by a single person - How can we tackle complexity?
6ModularityDivide and conquer
- A complex system is easier to manage if it can be
broken down into modules
7Modularity
Modularity is a particular design structure, in
which parameters and tasks are interdependent
within units (modules) and independent across them
- Increase the range of manageable complexity
- Allow different parts of a large design to be
worked on concurrently - Accommodate uncertainty
- Because of mix-and-match flexibility, it creates
options
8ModularityTurn a problem into a manageable one
- Two watchmakers Tempus and Hora
- Watches consisted of 1000 parts
- Tempus
- If he put it down, it immediately fell to pieces
- Had to be reassembled from scratch
- Very difficult to find enough uninterrupted time
to finish a watch - Hora
- Create stable subassemblies (modules) of about 10
elements - Make it manageable to find enough uninterrupted
time to finish a watch - Herbert Simon, The architecture of Complexity
(1969)
9ModularityWhat is a module?
- A module is a unit whose structural elements are
powerfully connected among themselves and
relatively weakly connected to elements in other
units - Coherent abstraction
- Interdependence within
- Independence across modules
10ModularityAttributes of a module
- Main attributes of a module are
- Role Describe the responsibility it performs
within the system - Interface Possess visible and hidden design
parameters - Module-Level test Can easily determine how well
module works without having to assemble the whole
system
11ModularityModule in programming
Service / Application
Service / Application
Module
Module
Module
Module
Service / Application
Service / Application
Module
Module
Module
Module
- Modules are programming elements which compose a
service or an application
12ModularityWhat programming elements can be
modules?
13ModularityObject
- Object
- Programming element Class
- Role Encapsulate behaviors with the same
concerns - Visible Interface Public signature
- Hidden Module Private implementation
- Module-Level Test Unit test fixture
14ModularityLayer
- Layer
- Programming element Package and Component (1 to
1 relationship) - Role Encapsulate classes with the same concerns
- Visible Interface Public classes
- Hidden Module internal classes
- Module-Level Test Component test fixture
15ModularityLayer
- Physical distribution and layering?
- Try to deploy one layer per component
- This ensure no cycles in the dependency graph
- If you need to split a layer because of physical
distribution, this may implies design smell - Layer should NOT have more than one responsibility
16ModularityTier Layer
Layer (Logical view)
Tier (Physical view)
Layer does not imply physical distribution
Tier imply physical distribution
17ModularityObject and Layer
- Two measures to consider
- Cohesion and coupling
18Cohesion
- How strongly-related and focused are the
responsibilities of a software module
19Cohesion
20Cohesion - Object Single responsibility principle
- Differentiate between problem domain and software
infrastructure behavior
21Cohesion - LayerLayered Architecture
22Coupling
- Breadth and depth to which each module relies on
each one
A
B
C
E
D
23Coupling Layered Architecture
DTO
Service Interface
Security
Persistence
24Coupling Level the dependency tree
Depended-on modules
25Coupling - Object Level the dependency tree
- Differentiate between instantiation and
collaboration dependency
Transfer instantiation" to an external party
Avoid collaboration with concrete class
26Coupling - Object Level the dependency tree
27Depend on Interface
- public class Purchase
-
- public void Ship(Logger logger)
-
- . . .
-
- . . .
-
-
- //Later on, somewhere...
- public class Logger
-
- public void Write(. . .)
-
- . . .
-
Concrete Class
28Depend on Interface
- public class Purchase
-
- public void Ship(ILogger logger)
-
- . . .
-
- . . .
-
- public interface ILogger
-
- public void Write(. . .)
-
-
- //Later on, somewhere...
- public class Logger ILogger
-
- public void Write(. . .)
-
Interface (Abstract Class)
29Coupling - Object Level the dependency tree
30Coupling - Object Level the dependency tree
31Service Locator
- public static class ServiceLocator
-
- private static readonly IDictionaryltType, Typegt
- mappings new DictionaryltType, Typegt()
-
- public static void RegisterltTInterface,
TConcretegt() - where TConcrete TInterface, new()
-
- mappingstypeof(TInterface)
typeof(TConcrete) -
-
- public static T ResolveltTgt()
-
- return (T)Activator.CreateInstance(mappingsty
peof(T)) -
-
- //Register concrete class...
- ServiceLocator.RegisterltILogger, Loggergt()
32Coupling - Object Observations about Service
Locator
- Object must know about Service Locator
- Service Locator must be visible for every objects
- Object have an opaque requirements issue
- Must read the code to discover dependencies
33Coupling - Object Level the dependency tree
Parameterization from above
34Inversion of Control
Dependency Injection
- public class Purchase
-
- public Purchase(ILogger Logger)
-
- . . .
-
- . . .
-
-
- //Register concrete class...
- var container DIContainer().RegisterTypeltILogger
, Loggergt() - //Later on, somewhere...
- container().ResolveltBuyergt()
35Coupling - Object Accidental complexity
- Decoupling every classes is overkill
- Classes is not the appropriate context boundary
for decoupling
36Coupling - Layer Layer Module Injection
Interface
Interface
DTO
Interface
Interface
Service Interface
Interface
Interface
Security
Interface
Persistence
DI Container
37Decouple using Layers
- using System
- using ABC.Persistence
- using ABC.Monitoring
- namespace ABC.Domain.Inventory
-
- public class Buyer
-
- public Buyer(IBuyerRepository BuyerRepository,
ILogger logger) -
- . . .
-
- . . .
-
-
Dependency Injection
38Coupling - Layer Layer Module Injection
- How do we organize classes inside a layer?
Layer
Interfaces
Component tests
Public Classes
Public Stubs
Internal Classes
39Coupling - Layer Domain-Driven Design
- What about coupling between internal objects?
- Thats the goal. We want strong coupling between
internal objects? - Simple OO Design
- We should manage coupling ONLY if there is domain
context boundary - SOA design smell
- New domain context must be transferred in his
own layer (Infrastructure) or service (Business
domain)
40Coupling - Layer Data Transfer Object
- What about Data Transfer Objects (DTO)
- Concrete classes with no behavior
- Data container
- Define in their own layer (.DTO)
- Allow strong coupling with other layers
41Coupling - Layer Enforce layering constraints
42Coupling - Layer Enforce layering constraints
43Coupling - Layer Enforce layering constraints
44Layered Architecture Design
- Which module should we design first?
- Layer
- Bottom-Up or Top-Down?
- Use TDD
- Write component test first
- Design the layer API
- Write Test Stub implementation
- Responder
- Saboteur
- Extract public interface
- Write public classes (with hidden classes)
- Uses sub layer Test Stub for testing
Component Test
Interface
Stub
Interface
45Layered Architecture Component Testing
- We must always test the layers public interface
- Hidden classes will be exercised
- Test coverage should be high
- What about unit testing?
- Class design
Component Test
Interface
Stub
Interface
46Layered Architecture Component Testing
Layer
Interfaces
Component tests
Public Classes
Public Stubs
Internal Classes
Sub Layers
Public Stubs
Public Stubs
Public Stubs
47SummaryHow to reduce complexity?
- Divide into modules
- Enforce one responsibility per module
- Do not mix Domain Logic and Infrastructure
Services - Modularize using a Layered Architecture
- Organize coupling between modules
- Decouple layers using Dependency Injection
- Build and automate component testing (for each
layer)
48SummaryHow to reduce complexity?
Layered Architecture
49SummaryBenefits of a layered architecture
50Do not hesitate to contact me mcardinal_at_mariocardi
nal.com