Upgrade to Pro — share decks privately, control downloads, hide ads and more …

On the criteria for decomposing systems into microservices

Adrian Colyer
November 07, 2016

On the criteria for decomposing systems into microservices

Mucon 2016 keynote, 7 November

Adrian Colyer

November 07, 2016

More Decks by Adrian Colyer

Other Decks in Technology


  1. Adrian Colyer | @adriancolyer On the criteria to be used

    in decomposing systems into microservices
  2. Copyright: Maxim Popov, 123RF Stock Photo What does it take

    to succeed with microservices? 1 2 System design Platform & processes 3 Culture
  3. A module is a unit of work assignment Copyright: Maxim

    Popov, 123RF Stock Photo 1. Shorten development time 2. Improve system flexibility 3. Improve understandability -> better overall design 4. Independent deployment 5. Fine-grained scaling 6. Fault isolation
  4. Copyright: Maxim Popov, 123RF Stock Photo “The effectiveness of a

    modularization is dependent upon the criteria used in dividing the system into modules.”
  5. “...it is almost always incorrect to begin the decomposition of

    a system into modules on the basis of a flowchart.” “ We propose instead that one begins with a list of difficult design decisions or design decisions which are likely to change. Each module is then designed to hide such a decision from the others.” “ Since, in most cases, design decisions transcend time of execution, modules will not correspond to steps in the processing…”
  6. Copyright: Maxim Popov, 123RF Stock Photo “The connections between microservices

    are all of the assumptions which the microservices make about each other.”
  7. “We may make only those changes which do not violate

    the assumptions made by other microservices about the service being changed.” Open (internal) source considered harmful!
  8. Great user experience Rapid delivery Support future change What comes

    first? And how soon to divide into microservices?
  9. “The earlier in the lifecycle of a project that you

    make a decision, the more difficult it is likely to be to change it as assumptions grow around it.”
  10. Circa 1979 (& 2016!) Common Problems 1. We were behind

    schedule and wanted to deliver an early release, but found that we couldn’t subset the system 2. We wanted to add a simple feature, but found it would have required rewriting all or most of the current code. 3. We wanted to simplify the system by removing some feature, but taking advantage of it meant rewriting large sections of the code 4. We wanted a custom deployment (e.g. in dev, or test environments) but the system wasn’t flexible enough.
  11. Four steps to a better system structure Identify subsets first

    Apply Information hiding Hierarchical virtual machines Design the uses structure
  12. “To avoid the problems that we have described as a

    ‘chain of data transforming components’ it is necessary to stop thinking of the system in terms of components that correspond to steps in the processing. This way of thinking dies hard...”
  13. “In many software design projects, the decisions about what other

    component programs to use are left to individual systems programmers… Unless some restraint is exercised, one may end up with a system in which nothing works until everything works.”
  14. THE RULES: Microservice A is allowed to use microservice B

    iff: • A is essentially simpler because it uses B • B is not substantially more complex because it is allowed to use A • There is a useful subset containing B and not A • There is no conceivable useful subset containing A but not B And of course, it does not introduce any cycles into the dependency graph
  15. About that first rule... A is essentially simpler because it

    uses B Broken when A calls B, for B’s benefit! There’s no better information hiding than not knowing a service is there at all. Making an RPC call leaks: • There is a service • It’s here • It’s currently available Events are very powerful in this situation.
  16. Source: Exploring complex networks, Nature vol. 410, 2001 Erdös -

    Rényi Random Graph n microservices c connections phase transition at c = n/2 -> giant connected component
  17. “After examining hundreds of error-prone DRSpaces over dozens of open

    source and commercial projects, we have observed that there are just a few distinct types of architecture issues, and these occur over and over again…”
  18. BF = Bug Frequency, BC = Bug churn, CF =

    Change Frequency, CC = Change Churn How much worse for architecture hotspots?
  19. MAIN SOURCES OF MAINTENANCE COSTS: 1. Unstable interface 2. Implicit

    cross-module dependency 3. Unhealthy interface inheritance hierarchy 4. Cross-module cycle 5. Cross-package cycle
  20. The data says: The two most important areas to pay

    attention to are • the interfaces of the modules and how well they hide information so that changes can be made without cascades, and • the uses structure of the system
  21. Identifying and quantifying architectural debt: • Architectural debts consume 85%

    of the total project maintenance effort in projects studied • The top five modularity debts alone consume 61% of the total effort • Modularity violation is the most common and expensive debt overall - it accounts for 82% of the total effort in HBase! • Top debts only involve a small number of files/modules, but consume a large amount of the total project effort • About half of all architectural debts accumulate interest at a constant rate.
  22. “Defining interfaces is the most important part of system design.

    Usually it is also the most difficult, since the interface design must satisfy three conflicting requirements: an interface should be simple, it should be complete, and it should admit a sufficiently small and fast implementation.”
  23. LAMPSON’S LAWS: 1. Capture the minimum essentials of an abstraction,

    don’t rush to generalize 2. Don’t promise more than you know how to deliver. Especially don’t add features for the few that penalise the many 3. Make it fast, rather than general or powerful 4. Sometimes, it’s worth a lot of work to make a fast implementation of a clean and powerful interface. But only when you already know the importance of the interface.
  24. Lampson: make sure your interface affords an efficient implementation. Clements

    et al.: here’s how (Scalable Commutativity Rule) 2013
  25. “whenever interface operations commute, they can be implemented in a

    way that scales.” How to design a commutative interface: 1. Decompose compound operations(*) 2. Embrace specification non-determinism 3. Permit weak ordering 4. Release resources asynchronously
  26. 4 patterns for scalable implementations 1. Layer scalability (hierarchies of

    virtual machines…) 2. Defer work 3. Precede pessimism with optimism 4. Don’t read unless necessary
  27. “Recently, a lot of interest has been shown in microservices.

    In these systems, there are multiple services each with its own code and data, and ability to operate independently of its partners… This paper proposes there are a number of seminal differences between data inside a service and data sent into the space outside of the service boundary.”
  28. Monoliths live in the “now” As time marches forward and

    transactions commit, each new transaction perceives the output of the transactions that preceded it. The executing logic of the service lives with a clear and crisp sense of “now” Copyright: Maxim Popov, 123RF Stock Photo
  29. “Going to microservices is like going from Newton’s physics to

    Einstein’s physics. Newton’s time marched forward uniformly with instant knowledge at a distance. Before microservices, distributed computing strove to make many systems look like one with RPC, 2PC etc.. In Einstein’s universe, everything is relative to one’s perspective. Microservices has “now” inside (a service) and the “past” arriving in messages.”
  30. Refactor -> Extract Microservice Refactor -> Change Model of Space

    and Time Copyright: Maxim Popov, 123RF Stock Photo
  31. Copyright: Maxim Popov, 123RF Stock Photo Now: inside a microservice

    Past: messages arriving from other services Future: commands sent to other services
  32. “Operands may live either in the past or the future

    depending on their usage pattern. They live in the past if they have copies of unlocked information from a distant service. They live in the future if they contain proposed values that hopefully will be used if the operator is successfully completed. Between the services, life is in the world of “then”… This means that data on the outside lives in the world of “then”. It is past or future but it is not now.” -> It is up to the microservices themselves to reconcile now and then.
  33. Data on the Outside • Immutable • Identifiable, e.g. “The

    New York Times” ? • Stable • Any referenced data is also immutable • Messages themselves are also immutable (think retries) “Stable data has an unambiguous and unchanging interpretation across space and time… One excellent technique for the creation of stable data is the use of time-stamping and/or versioning.”
  34. The data says: The two most important areas to pay

    attention to are • the interfaces of the modules and how well they hide information so that changes can be made without cascades, and • the uses structure of the system Pay attention to data on the inside vs data on the outside Don’t forget the power of events / messages Some takeaways
  35. A new paper every weekday Published at https://blog.acolyer.org. 01 Delivered

    Straight to your inbox If you prefer email-based subscription to read at your leisure. 02 Announced on Twitter I’m @adriancolyer. 03 Go to a Papers We Love Meetup A repository of academic computer science papers and a community who loves reading them. 04 Share what you learn Anyone can take part in the great conversation. 05
  36. Adrian Colyer | @adriancolyer Paper links • On the criteria

    to be used in decomposing systems into modules https://blog.acolyer.org/2016/09/05/on-the-criteria-to-be-used-in-decomposing-systems-into-modules/ • Information distribution aspects of design methodology: https://blog.acolyer.org/2016/10/17/information-distribution-aspects-of-design-methodology/ • Designing software for ease of extension and contraction: https://blog.acolyer.org/2016/10/31/designing-software-for-ease-of-extension-and-contraction/ • Hotspot patterns: The formal definition and automatic detection of architecture smells https://blog.acolyer.org/2016/06/10/hotspot-patterns-the-formal-definition-and-automatic-detection-of-architecture-smells/ • Identifying and quantifying architectural debt https://blog.acolyer.org/2016/06/13/identifying-and-quantifying-architectural-debt/ • Exploring complex networks https://blog.acolyer.org/2015/05/25/exploring-complex-networks/ • Hints for computer system design https://blog.acolyer.org/2016/09/16/hints-for-computer-system-design/ • The scalable commutativity rule: designing scalable software for multicore processors https://blog.acolyer.org/2015/04/24/the-scalable-commutativity-rule-designing-scalable-software-for-multicore-processors/ • Data on the outside vs data on the inside https://blog.acolyer.org/2016/09/13/data-on-the-outside-versus-data-on-the-inside/