Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
REAL 
LIFE
CLEAN ARCHITECTURE
@BattistonMattia
ABOUT ME
●  from Verona, Italy
●  software dev & continuous improvement
●  Kanban, Lean, Agile “helper”
●  Sky Network Ser...
DISCLAIMER #1
MICROSERVICES
“Normal” apps
DISCLAIMER #2
THE ONE WAY
Our experience
(pragmatism, tradeoffs)
Infrequent
deploys
COMMON PROBLEMS
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
around
frame...
“
The center of your application
is not the database. Nor is it
one or more of the frameworks
you may be using. 
The cente...
CLEAN ARCHITECTURE
Source: The Clean Architecture
THANK YOU!
THE END
Just Kidding,
The fun is about to
start :-)
EXAMPLE PROJECT
https://github.com/mattia-battiston/clean-architecture-example
EXAMPLE DOMAIN: ISP
Entity:
Telephone 
Exchange
Entity:
Broadband 
Access Device
Use case: 
Get Capacity
“Have we got spac...
OUR CLEAN ARCHITECTURE
ENTITIES
USE CASES
REST APIs
JOBS
DATABASE
FILE SYSTEM
NETWORK
DEVICES
DB
I
...
...
CONFIGURATION
c...
A.k.a (unclebob’s style)
Entities
Use Cases
Configuration
+
 Core: business logic
Entrypoints: access
to the application
D...
PROJECT STRUCTURE
ENTITY
ENTITIES
USE CASES
REST APIs
JOBS
DATABASE
FILE SYSTEM
NETWORK
DEVICES
DB
I
...
...
CONFIGURATION
coreentrypoints d...
ENTITY
ENTITY
public class Exchange {

private final String code;
private final String name;
private final String postCode;

publ...
ENTITY
public class BroadbandAccessDevice {

private Exchange exchange;

private String hostname;
private String serialNum...
ENTITY
●  Domain objects
e.g. “Exchange”, “Broadband Access Device”
●  Entity-specific business rules
e.g. hostname format...
USE CASE
ENTITIES
USE CASES
REST APIs
JOBS
DATABASE
FILE SYSTEM
NETWORK
DEVICES
DB
I
...
...
CONFIGURATION
coreentrypoints...
USE CASE
USE CASE
public class GetCapacityForExchangeUseCase {

private DoesExchangeExist dataProvider1; 
private GetAvailablePorts...
USE CASE
public interface DoesExchangeExist {
boolean doesExchangeExist(String exchange);
}

public interface GetAvailable...
USE CASE
●  Pure business logic
e.g. algorithm to calculate capacity
●  Defines Interfaces for the data that it requires
e...
DATA PROVIDER
ENTITIES
USE CASES
REST APIs
JOBS
DATABASE
FILE SYSTEM
NETWORK
DEVICES
DB
I
...
...
CONFIGURATION
coreentryp...
DATA PROVIDER
DATA PROVIDER
public class BroadbandAccessDeviceDatabaseDataProvider 
implements GetAllDeviceHostnames, GetSerialNumberFro...
DATA PROVIDER
public class BroadbandAccessDeviceNetworkDataProvider 
implements GetSerialNumberFromReality {

private Devi...
DATA PROVIDER
●  Implements Interfaces defined by use case
e.g. retrieving serial number of a device
●  Hides all details ...
ENTRYPOINT
ENTITIES
USE CASES
REST APIs
JOBS
DATABASE
FILE SYSTEM
NETWORK
DEVICES
DB
I
...
...
CONFIGURATION
coreentrypoin...
ENTRYPOINT
ENTRYPOINT
@RestController
public class GetCapacityForExchangeEndpoint {

public static final String API_PATH = "/exchange...
ENTRYPOINT
public class ReconcileBroadbandAccessDeviceJob implements ScheduledJob {

private ReconcileBroadbandAccessDevic...
ENTRYPOINT
●  Fires up a use case
●  Has no business logic
●  Has conversion logic 
e.g. uses DTOs to return result to WEB...
CONFIGURATION
ENTITIES
USE CASES
REST APIs
JOBS
DATABASE
FILE SYSTEM
NETWORK
DEVICES
DB
I
...
...
CONFIGURATION
coreentryp...
CONFIGURATION
CONFIGURATION
@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = "com.clean.example.configuration")
pub...
CONFIGURATION
●  Wires everything together
e.g. using Spring or simply initialising objects
●  Isolates and hides framewor...
EXAMPLE: GET CAPACITY
Rest 
Entrypoint
Client
Use 
Case
Data 
Provider
GET /exchange/CHELSEA/capacity
useCase.getCapacity(...
EXAMPLE: RECONCILE DEVICES
Use Case
Job
Entrypoint
Data Provider:
DB
Data Provider:
Network Device
useCase.reconcile(...);...
Coverage
TESTING STRATEGY
Unit Tests - TDD
Acceptance Tests - BDD
Integration Tests
End-to-end Tests
Manual Exploratory
Te...
UNIT TESTS
ENTITIES
USE CASES
REST APIs
JOBS
DATABASE
FILE SYSTEM
NETWORK
DEVICES
DB
I
...
...
CONFIGURATION
coreentrypoin...
UNIT TESTS
// …

GetCapacityForExchangeEndpoint endpoint = // class under test
GetCapacityForExchangeUseCase useCase = // ...
UNIT TESTS
●  TDD
A.k.a. Tests first, to drive design
●  Cover every little detail
A.k.a. Aim for 100% coverage
●  “Dev to...
ACCEPTANCE TESTS
ENTITIES
USE CASES
REST APIs
JOBS
DATABASE
FILE SYSTEM
NETWORK
DEVICES
DB
I
...
...
CONFIGURATION
coreent...
ACCEPTANCE TESTS
@Notes("Calculates the remaining capacity in an exchange...")
@LinkingNote(message = "End to End test: %s...
ACCEPTANCE TESTS
ACCEPTANCE TESTS
●  BDD
A.k.a. Conversations with the business
●  Demonstrate business requirements
A.k.a. Aim to cover bu...
http
INTEGRATION TESTS
ENTITIES
USE CASES
REST APIs
JOBS
DATABASE
FILE SYSTEM
NETWORK
DEVICES
DB
I
...
...
CONFIGURATION
c...
INTEGRATION TESTS
●  Test integration with slow parts
e.g. Http, database
●  “Dev” documentation
A.k.a. Does this work as ...
END-TO-END TESTS
ENTITIES
USE CASES
REST APIs
JOBS
DATABASE
FILE SYSTEM
NETWORK
DEVICES
DB
I
...
...
CONFIGURATION
coreent...
END-TO-END TESTS
●  Test only the critical journeys
e.g. most common happy path
●  Demonstrate “business” end-to-end requi...
PRO: TESTING STRATEGY
EFFECTIVE
TESTING STRATEGY
Infrequent
deploys
PROBLEMS? FIX!
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
around
framew...
PRO: FRAMEWORKS
FRAMEWORKS ARE
ISOLATED
easy(er) to
change our mind
PRO: FRAMEWORKS
ENTITIES
USE CASES
REST APIs
JOBS
DATABASE
FILE SYSTEM
NETWORK
DEVICES
DB
I
...
...
CONFIGURATION
coreentr...
Infrequent
deploys
PROBLEMS? FIX!
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
around
framew...
PRO: DATABASE
INDEPENDENT
FROM DATABASE
PRO: DATABASE
●  No CRUD!
●  RESTful style for reading information
GET /exchange/{exchangeCode}
GET /exchange/{exchangeCod...
Infrequent
deploys
PROBLEMS? FIX!
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
around
framew...
PRO: SCREAMING ARCHITECTURE
SCREAMS THE
INTENDED USAGE
PRO: SCREAMING ARCHITECTURE
Infrequent
deploys
PROBLEMS? FIX!
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
around
framew...
PRO: EASY TO FIND THINGS
ALL BUSINESS
LOGIC IS IN 
USE CASE
Infrequent
deploys
PROBLEMS? FIX!
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
around
framew...
PRO: MODULES
HARD TO DO THE
WRONG THING
Infrequent
deploys
PROBLEMS? FIX!
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
around
framew...
PRO: ALWAYS READY
ALWAYS READY TO
DEPLOY
real continuous
integration
Infrequent
deploys
PROBLEMS? FIX!
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
around
framew...
PRO: SWARMING
PARALLELISE
WORK
multiple pairs on
the same story
Infrequent
deploys
PROBLEMS? FIX!
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
around
framew...
PRO: NICE MONOLITH
GOOD MONOLITH 
TO START WITH
clear boundaries
to break on
Infrequent
deploys
PROBLEMS? FIX!
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
around
framew...
CON: DUPLICATION
PERCEIVED
DUPLICATION OF
CODE
be pragmatic
Infrequent
deploys
PROBLEMS? FIX!
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
around
framew...
CON: IT NEEDS LOGIC
YOU NEED
INTERESTING
BUSINESS LOGIC
CON: IT NEEDS LOGIC
ENDPOINT
// … 
@RequestMapping(value = API_PATH, method = GET)
public BroadbandAccessDeviceDto getDeta...
Infrequent
deploys
Always
Ready
PROBLEMS? FIX!
Decisions
taken
too early
Hard to
change
Centered
around
database
Centered
...
KEY TAKEAWAY
“
The center of your application is the
use cases of your application
Unclebob
RESOURCES
Example Project (with all code shown in the presentation)
●  Clean Architecture Example 
https://github.com/matt...
really, really appreciated! Help me improve
@BattistonMattia 
mattia.battiston@gmail.com
mattia-battiston
THANK YOU!
Upcoming SlideShare
Loading in …5
×

Real Life Clean Architecture

16,370 views

Published on

We like the architecture of our applications to revolve around the business logic, not around technical details (and especially not around the database).

In my team at Sky Network Services we use the Clean Architecture and it has given us a great deal of benefits: the business logic is explicit, we are free to change our technical decisions, the app is easy to test, working on it is faster and scalable, it’s hard to do the wrong thing, and many more.

But it comes at a cost, of course. In this talk I’ll tell you the story of our experience with Clean Architecture and give you some tips to get the most out of it.

Example Project
https://github.com/mattia-battiston/clean-architecture-example

Downloads
Online: https://goo.gl/DTxftJ
PDF: https://goo.gl/ZAtdBN
Powerpoint: https://goo.gl/D54wdZ (but you need to install these fonts to see it properly: https://goo.gl/iH8SO5)

Published in: Software
  • Discover a WEIRD trick I use to make over $3500 per month taking paid surveys online. read more... ★★★ http://ishbv.com/surveys6/pdf
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Good presentation, thanks for that!I asked Uncle Bob more than once about the separation between 'Frameworks and Drivers' and 'Interface Adapters' and it is still not clear to me how we could make it happen. Databases and data access layers using ORM frameworks, for example: if they are not together, dependency rule is broken. Same to views + controllers + presenters, where we'll need/use frameworks to build it. I mean: in the real world, how would we be able to fully implement the Clean Architecture? Do you see any chance to achieve it, giving the premise that we will never own the code of databases, browser engines, etc etc?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Hi @Philip Schwarz Sorry I only noticed the comment now. Like Eduardo and Oleg mentioned, what I mean is that you have an object in the database layer with the ORM annotations, and a different object in your use case representing your domain, and sometimes even another object in the REST layer to use as a DTO to convert to Json. Sometimes this is perceived as "duplication", for the benefit of decoupling and isolating concerns. When I say "be pragmatic" I mean that sometimes when the objects that you need are exactly the same, maybe you can get away with using the same object instead of having 3 flavours of it, as long as you're not breaking the principles of the architecture. I hope this clarifies it!
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • @Eduardo Ferrari Copat The code is not duplicated, it has another reasons to change. Thus for example to ORM model class may contain database specific annotations and fields like the "id" field. The DTO class may contain library specific annotations like @JsonProperty. If you e.g. want to switch to another dto serialization library, you would need to touch only the dto but keep the rest.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • @Philip Schwarz Hi, I think this is related to the duplication of the Entities and the DTOs on the Rest Entrypoint. In this case, you are isolating concepts through separation of concerns, at the cost of "duplicating" code
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Real Life Clean Architecture

  1. 1. REAL LIFE CLEAN ARCHITECTURE @BattistonMattia
  2. 2. ABOUT ME ●  from Verona, Italy ●  software dev & continuous improvement ●  Kanban, Lean, Agile “helper” ●  Sky Network Services Mattia Battiston @BattistonMattia mattia.battiston@gmail.com mattia-battiston
  3. 3. DISCLAIMER #1 MICROSERVICES “Normal” apps
  4. 4. DISCLAIMER #2 THE ONE WAY Our experience (pragmatism, tradeoffs)
  5. 5. Infrequent deploys COMMON PROBLEMS Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things
  6. 6. “ The center of your application is not the database. Nor is it one or more of the frameworks you may be using. The center of your application is the use cases of your application Unclebob Source: NODB
  7. 7. CLEAN ARCHITECTURE Source: The Clean Architecture
  8. 8. THANK YOU! THE END Just Kidding, The fun is about to start :-)
  9. 9. EXAMPLE PROJECT https://github.com/mattia-battiston/clean-architecture-example
  10. 10. EXAMPLE DOMAIN: ISP Entity: Telephone Exchange Entity: Broadband Access Device Use case: Get Capacity “Have we got space for more customers? Can we sell more broadband?” Use case: Reconcile “Has any physical device changed? (e.g. new serial number)” Use case: Get Details “Details of a particular device?”
  11. 11. OUR CLEAN ARCHITECTURE ENTITIES USE CASES REST APIs JOBS DATABASE FILE SYSTEM NETWORK DEVICES DB I ... ... CONFIGURATION coreentrypoints dataproviders
  12. 12. A.k.a (unclebob’s style) Entities Use Cases Configuration + Core: business logic Entrypoints: access to the application Data Providers: retrieve and store information ... Configuration: wires everything together * arrows represent dependency
  13. 13. PROJECT STRUCTURE
  14. 14. ENTITY ENTITIES USE CASES REST APIs JOBS DATABASE FILE SYSTEM NETWORK DEVICES DB I ... ... CONFIGURATION coreentrypoints dataproviderscore ENTITIES
  15. 15. ENTITY
  16. 16. ENTITY public class Exchange { private final String code; private final String name; private final String postCode; public Exchange(String code, String name, String postCode) { this.code = code; this.name = name; this.postCode = postCode; } // … getters @Override public String toString() { return ...; } }
  17. 17. ENTITY public class BroadbandAccessDevice { private Exchange exchange; private String hostname; private String serialNumber; private DeviceType type; private int availablePorts; public BroadbandAccessDevice(String hostname, ...) { this.hostname = hostname; this.serialNumber = serialNumber; this.type = type; } // … (getters, some setters) @Override public String toString() { return ...; } }
  18. 18. ENTITY ●  Domain objects e.g. “Exchange”, “Broadband Access Device” ●  Entity-specific business rules e.g. hostname format ●  Tiny Types are useful e.g. Hostname instead of String ●  No Frameworks
  19. 19. USE CASE ENTITIES USE CASES REST APIs JOBS DATABASE FILE SYSTEM NETWORK DEVICES DB I ... ... CONFIGURATION coreentrypoints dataproviders USE CASES I core
  20. 20. USE CASE
  21. 21. USE CASE public class GetCapacityForExchangeUseCase { private DoesExchangeExist dataProvider1; private GetAvailablePortsOfAllDevicesInExchange dataProvider2; // … public Capacity getCapacity(String exchangeCode) { failIfExchangeDoesNotExist(exchangeCode); List<BroadbandAccessDevice> devices = dataProvider2 .getAvailablePortsOfAllDevicesInExchange(exchangeCode); boolean hasAdslCapacity = hasCapacityFor(devices, DeviceType.ADSL); boolean hasFibreCapacity = hasCapacityFor(devices, DeviceType.FIBRE); return new Capacity(hasAdslCapacity, hasFibreCapacity); } // … private void failIfExchangeDoesNotExist(String exchangeCode) { boolean exchangeExists = dataProvider1.doesExchangeExist(exchangeCode); if(!exchangeExists) throw new ExchangeNotFoundException(); } }
  22. 22. USE CASE public interface DoesExchangeExist { boolean doesExchangeExist(String exchange); } public interface GetAvailablePortsOfAllDevicesInExchange { List<BroadbandAccessDevice> getAvailablePortsOfAllDevicesInExchange(String exchangeCode); } public class ExchangeNotFoundException extends RuntimeException { }
  23. 23. USE CASE ●  Pure business logic e.g. algorithm to calculate capacity ●  Defines Interfaces for the data that it requires e.g. getAvailablePorts ●  Uses entities and dataproviders ●  Throws business-specific exceptions ●  Not affected by changes in database or presentation ●  Plain Java (no frameworks) ●  We like single-method interfaces A.k.a. Interface Segregation
  24. 24. DATA PROVIDER ENTITIES USE CASES REST APIs JOBS DATABASE FILE SYSTEM NETWORK DEVICES DB I ... ... CONFIGURATION coreentrypoints dataproviders DATABASE FILE SYSTEM NETWORK DEVICES DB ... dataproviders
  25. 25. DATA PROVIDER
  26. 26. DATA PROVIDER public class BroadbandAccessDeviceDatabaseDataProvider implements GetAllDeviceHostnames, GetSerialNumberFromModel, ... { private JdbcTemplate jdbcTemplate; @Override public List<String> getAllDeviceHostnames() { return jdbcTemplate.queryForList( "SELECT hostname FROM clean_architecture.bb_access_device", String.class); } @Override public String getSerialNumber(String hostname) { try { return jdbcTemplate.queryForObject( "SELECT serial_number FROM clean_architecture.bb_access_device WHERE hostname = ?", String.class, hostname); } catch (IncorrectResultSizeDataAccessException e) { return null; } } // …
  27. 27. DATA PROVIDER public class BroadbandAccessDeviceNetworkDataProvider implements GetSerialNumberFromReality { private DeviceClient deviceClient; // … @Override public String getSerialNumber(String hostname) { try { return deviceClient.getSerialNumber(hostname); } catch (DeviceConnectionTimeoutException e) { return null; } } }
  28. 28. DATA PROVIDER ●  Implements Interfaces defined by use case e.g. retrieving serial number of a device ●  Hides all details about where the data is from ●  Could have multiple implementations e.g. from DB or from File System ●  Uses whatever framework/library is appropriate e.g. spring-jdbc, hibernate, snmp4j, etc. ●  If using ORM, you’d have a new set of entities A.k.a. decoupled from business entities
  29. 29. ENTRYPOINT ENTITIES USE CASES REST APIs JOBS DATABASE FILE SYSTEM NETWORK DEVICES DB I ... ... CONFIGURATION coreentrypoints dataproviders REST APIs JOBS ... entrypoints
  30. 30. ENTRYPOINT
  31. 31. ENTRYPOINT @RestController public class GetCapacityForExchangeEndpoint { public static final String API_PATH = "/exchange/{exchangeCode}/capacity"; private GetCapacityForExchangeUseCase getCapacityForExchangeUseCase; // … @RequestMapping(value = API_PATH, method = GET) public CapacityDto getCapacity(@PathVariable String exchangeCode) { try { Capacity capacity = getCapacityForExchangeUseCase.getCapacity(exchangeCode); return toDto(capacity); } catch (ExchangeNotFoundException e) { LOGGER.info("Exchange not found: {}", exchangeCode); throw new NotFoundException(); } } private CapacityDto toDto(Capacity capacity) { return new CapacityDto( capacity.hasAdslCapacity(), capacity.hasFibreCapacity()); } }
  32. 32. ENTRYPOINT public class ReconcileBroadbandAccessDeviceJob implements ScheduledJob { private ReconcileBroadbandAccessDevicesUseCase useCase; private final JobResults jobResults; // … @Override public String getName() { return "..."; } @Override public long getInitialDelay() { return 0; } @Override public long getPeriod() { return 5; } @Override public TimeUnit getTimeUnit() { return TimeUnit.SECONDS; } @Override public void run() { LOGGER.info("Job Starting: {}...", getName()); JobResultsCount jobResultsCount = jobResults.createJobResultsCount(); OnSuccess success = jobResultsCount::success; OnFailure failure = jobResultsCount::failure; reconcileBroadbandAccessDevicesUseCase.reconcile(success, failure); jobResults.recordJobResults(this, jobResultsCount); LOGGER.info("Job Completed: {}", getName()); } }
  33. 33. ENTRYPOINT ●  Fires up a use case ●  Has no business logic ●  Has conversion logic e.g. uses DTOs to return result to WEB ●  Hides all details about delivery mechanism ●  GUI would be an entrypoint e.g. controllers would start use cases ●  Uses whatever framework/library is appropriate e.g. spring-mvc, jersey, quartz, etc.
  34. 34. CONFIGURATION ENTITIES USE CASES REST APIs JOBS DATABASE FILE SYSTEM NETWORK DEVICES DB I ... ... CONFIGURATION coreentrypoints dataproviders CONFIGURATION
  35. 35. CONFIGURATION
  36. 36. CONFIGURATION @Configuration @EnableAutoConfiguration @ComponentScan(basePackages = "com.clean.example.configuration") public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } @Configuration public class EndpointConfiguration { @Bean public GetBroadbandAccessDeviceEndpoint getBroadbandAccessDeviceEndpoint() { return new GetBroadbandAccessDeviceEndpoint(...); } // …other endpoints… } @Configuration public class WebServerConfiguration { // …wires web server with framework… }
  37. 37. CONFIGURATION ●  Wires everything together e.g. using Spring or simply initialising objects ●  Isolates and hides frameworks e.g. Spring is only here ●  Has the “dirty” details to make things work e.g. initialise datasource, setup web server, etc.
  38. 38. EXAMPLE: GET CAPACITY Rest Entrypoint Client Use Case Data Provider GET /exchange/CHELSEA/capacity useCase.getCapacity(“CHELSEA”); dataProvider .getAvailablePortsOfAllDevicesInExchange (”CHELSEA”); SELECT … WHERE code = “CHELSEA” return broadbandAccessDevices; countAvailablePortsOfEachType(); decideIfThereIsCapacity(); return capacity; convertToDto(capacity); return dto; Status Code: 200 OK {"hasADSLCapacity":true, "hasFibreCapacity":true}
  39. 39. EXAMPLE: RECONCILE DEVICES Use Case Job Entrypoint Data Provider: DB Data Provider: Network Device useCase.reconcile(...); getAllDeviceHostnames() "SELECT hostname...” // For each device: getSerialNumberFromModel(hostname) getSerialNumberFromReality(hostname) "SELECT serial_number...” SNMPGET … if(serialNumberIsDifferent()) { updateSerialNumber(); success(); } auditResults();
  40. 40. Coverage TESTING STRATEGY Unit Tests - TDD Acceptance Tests - BDD Integration Tests End-to-end Tests Manual Exploratory Tests Cost
  41. 41. UNIT TESTS ENTITIES USE CASES REST APIs JOBS DATABASE FILE SYSTEM NETWORK DEVICES DB I ... ... CONFIGURATION coreentrypoints dataproviders UNIT TESTs UNIT TESTs UNIT TESTs UNIT TESTs UNIT TESTs UNIT TESTs
  42. 42. UNIT TESTS // … GetCapacityForExchangeEndpoint endpoint = // class under test GetCapacityForExchangeUseCase useCase = // mock @Test public void returnsTheCapacityForAnExchange() throws Exception { givenThereIsCapacityForAnExchange(); CapacityDto capacity = endpoint.getCapacity(EXCHANGE_CODE); assertThat(capacity.getHasADSLCapacity()).isTrue(); assertThat(capacity.getHasFibreCapacity()).isTrue(); } private void givenThereIsCapacityForAnExchange() { when(useCase.getCapacity(EXCHANGE_CODE)) .thenReturn(new Capacity(true, true)); } // …
  43. 43. UNIT TESTS ●  TDD A.k.a. Tests first, to drive design ●  Cover every little detail A.k.a. Aim for 100% coverage ●  “Dev to dev” documentation A.k.a. What should this class do? ●  Test individual classes in isolation, very fast
  44. 44. ACCEPTANCE TESTS ENTITIES USE CASES REST APIs JOBS DATABASE FILE SYSTEM NETWORK DEVICES DB I ... ... CONFIGURATION coreentrypoints dataproviders ACC. TESTs (BUS. REQ.)
  45. 45. ACCEPTANCE TESTS @Notes("Calculates the remaining capacity in an exchange...") @LinkingNote(message = "End to End test: %s", links = {GetCapacityForExchangeEndToEndTest.class}) public class GetCapacityForExchangeAcceptanceTest extends YatspecTest { // …mock the dependencies of the use case… GetCapacityForExchangeUseCase useCase = // …my use case @Test public void hasAdslCapacityWhenThereAreAtLeast5AdslPortsAvailableAcrossAllDevices() { givenSomeAdslDevicesInTheExchangeWithMoreThan5AdslPortsAvailable(); whenTheCapacityForTheExchangeIsRequested(); thenThereIsAdslCapacity(); } // … }
  46. 46. ACCEPTANCE TESTS
  47. 47. ACCEPTANCE TESTS ●  BDD A.k.a. Conversations with the business ●  Demonstrate business requirements A.k.a. Aim to cover business scenarios ●  “Business” documentation A.k.a. What does the system do? ●  Test use case in isolation, very fast A.k.a. No GUI, no DB, etc. ●  Use your favourite BDD framework We use Yatspec
  48. 48. http INTEGRATION TESTS ENTITIES USE CASES REST APIs JOBS DATABASE FILE SYSTEM NETWORK DEVICES DB I ... ... CONFIGURATION coreentrypoints dataproviders INTEGRATION TESTs INTEGRATION TESTs
  49. 49. INTEGRATION TESTS ●  Test integration with slow parts e.g. Http, database ●  “Dev” documentation A.k.a. Does this work as expected? ●  Test one layer in isolation e.g. only rest endpoint, or only data provider ●  Use whatever library makes it easy e.g. Spring MockMVC; in-memory db
  50. 50. END-TO-END TESTS ENTITIES USE CASES REST APIs JOBS DATABASE FILE SYSTEM NETWORK DEVICES DB I ... ... CONFIGURATION coreentrypoints dataproviders http END-TO-END TESTs
  51. 51. END-TO-END TESTS ●  Test only the critical journeys e.g. most common happy path ●  Demonstrate “business” end-to-end requirement ●  Start the whole app, very slow A.k.a. keep these to a minimum
  52. 52. PRO: TESTING STRATEGY EFFECTIVE TESTING STRATEGY
  53. 53. Infrequent deploys PROBLEMS? FIX! Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things Effective Testing Pyramid
  54. 54. PRO: FRAMEWORKS FRAMEWORKS ARE ISOLATED easy(er) to change our mind
  55. 55. PRO: FRAMEWORKS ENTITIES USE CASES REST APIs JOBS DATABASE FILE SYSTEM NETWORK DEVICES DB I ... ... CONFIGURATION coreentrypoints dataproviders Spring WEB Spring boot Spring jdbc snmp4j quartz
  56. 56. Infrequent deploys PROBLEMS? FIX! Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things Effective Testing Pyramid frameworks are Isolated
  57. 57. PRO: DATABASE INDEPENDENT FROM DATABASE
  58. 58. PRO: DATABASE ●  No CRUD! ●  RESTful style for reading information GET /exchange/{exchangeCode} GET /exchange/{exchangeCode}/capacity GET /broadbandAccessDevice/{hostname} ●  Custom endpoints for business actions POST /broadbandAccessDevice/{hostname}/makeLive PUT /exchange/{exchangeCode}/increaseCapacity
  59. 59. Infrequent deploys PROBLEMS? FIX! Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things Effective Testing Pyramid Independent from Database frameworks are Isolated
  60. 60. PRO: SCREAMING ARCHITECTURE SCREAMS THE INTENDED USAGE
  61. 61. PRO: SCREAMING ARCHITECTURE
  62. 62. Infrequent deploys PROBLEMS? FIX! Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things Effective Testing Pyramid Independent from Database Screaming Architecture frameworks are Isolated
  63. 63. PRO: EASY TO FIND THINGS ALL BUSINESS LOGIC IS IN USE CASE
  64. 64. Infrequent deploys PROBLEMS? FIX! Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things Effective Testing Pyramid Independent from Database Screaming ArchitectureAll business logic in use cases frameworks are Isolated
  65. 65. PRO: MODULES HARD TO DO THE WRONG THING
  66. 66. Infrequent deploys PROBLEMS? FIX! Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things Effective Testing Pyramid Independent from Database Screaming ArchitectureAll business logic in use cases Modules isolate changes frameworks are Isolated
  67. 67. PRO: ALWAYS READY ALWAYS READY TO DEPLOY real continuous integration
  68. 68. Infrequent deploys PROBLEMS? FIX! Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things Effective Testing Pyramid Independent from Database Screaming ArchitectureAll business logic in use cases Modules isolate changes Always Ready frameworks are Isolated
  69. 69. PRO: SWARMING PARALLELISE WORK multiple pairs on the same story
  70. 70. Infrequent deploys PROBLEMS? FIX! Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things Effective Testing Pyramid Independent from Database Screaming ArchitectureAll business logic in use cases Modules isolate changes Always Ready Swarming frameworks are Isolated
  71. 71. PRO: NICE MONOLITH GOOD MONOLITH TO START WITH clear boundaries to break on
  72. 72. Infrequent deploys PROBLEMS? FIX! Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things Effective Testing Pyramid Independent from Database Screaming ArchitectureAll business logic in use cases Modules isolate changes Always Ready Swarming frameworks are Isolated Nice Monolith
  73. 73. CON: DUPLICATION PERCEIVED DUPLICATION OF CODE be pragmatic
  74. 74. Infrequent deploys PROBLEMS? FIX! Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things Effective Testing Pyramid Independent from Database Screaming ArchitectureAll business logic in use cases Modules isolate changes Always Ready Swarming frameworks are Isolated Nice Monolith Duplication
  75. 75. CON: IT NEEDS LOGIC YOU NEED INTERESTING BUSINESS LOGIC
  76. 76. CON: IT NEEDS LOGIC ENDPOINT // … @RequestMapping(value = API_PATH, method = GET) public BroadbandAccessDeviceDto getDetails(@PathVariable String hostname) { try { BroadbandAccessDevice deviceDetails = useCase.getDeviceDetails(hostname); return toDto(deviceDetails); } catch (DeviceNotFoundException e) { throw new NotFoundException(); } } // … USE CASE // … public BroadbandAccessDevice getDeviceDetails(String hostname) { BroadbandAccessDevice device = dataProvider.getDetails(hostname); return device; } // … DATA PROVIDER // … return "SELECT ...";
  77. 77. Infrequent deploys Always Ready PROBLEMS? FIX! Decisions taken too early Hard to change Centered around database Centered around frameworks Business logic is spread everywhere Focused on technical aspects Slow, heavy tests Hard to find things Effective Testing Pyramid frameworks are Isolated Independent from Database Screaming ArchitectureAll business logic in use cases Modules isolate changes Nice Monolith Swarming Duplication Needs Interesting Logic
  78. 78. KEY TAKEAWAY “ The center of your application is the use cases of your application Unclebob
  79. 79. RESOURCES Example Project (with all code shown in the presentation) ●  Clean Architecture Example https://github.com/mattia-battiston/clean-architecture-example Blogs & Articles ●  The Clean Architecture https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html ●  Screaming Architecture http://blog.8thlight.com/uncle-bob/2011/09/30/Screaming-Architecture.html ●  NODB https://blog.8thlight.com/uncle-bob/2012/05/15/NODB.html ●  Hexagonal Architecture http://alistair.cockburn.us/Hexagonal+architecture Videos & Presentations ●  Clean Coders ep. 7: Architecture, Use Cases, and High Level Design https://cleancoders.com/episode/clean-code-episode-7/show ●  Robert C. Martin - Clean Architecture https://vimeo.com/43612849 ●  Robert C. Martin - Clean Architecture and Design https://www.youtube.com/watch?v=Nsjsiz2A9mg
  80. 80. really, really appreciated! Help me improve @BattistonMattia mattia.battiston@gmail.com mattia-battiston THANK YOU!

×