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

On the criteria for decomposing systems into microservices

On the criteria for decomposing systems into microservices

Mucon 2016 keynote, 7 November

Adrian Colyer

November 07, 2016
Tweet

More Decks by Adrian Colyer

Other Decks in Technology

Transcript

  1. Adrian Colyer | @adriancolyer
    On the criteria to be used in
    decomposing systems into
    microservices

    View full-size slide

  2. blog.acolyer.org
    400
    Foundations
    Frontiers

    View full-size slide

  3. Copyright: Maxim Popov, 123RF Stock Photo
    What does it take to
    succeed with
    microservices?
    1
    2
    System design
    Platform & processes
    3 Culture

    View full-size slide

  4. 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

    View full-size slide

  5. Copyright: Maxim Popov, 123RF Stock Photo
    “The effectiveness of
    a modularization is
    dependent upon the
    criteria used in
    dividing the system
    into modules.”

    View full-size slide

  6. Copyright: Maxim Popov, 123RF Stock Photo
    Task-based
    decomposition
    Information
    hiding

    View full-size slide

  7. “...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…”

    View full-size slide

  8. Copyright: Maxim Popov, 123RF Stock Photo
    “The connections
    between
    microservices are all
    of the assumptions
    which the
    microservices make
    about each other.”

    View full-size slide

  9. “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!

    View full-size slide

  10. Great user
    experience
    Rapid
    delivery
    Support
    future
    change
    What
    comes
    first?
    And how soon
    to divide into
    microservices?

    View full-size slide

  11. “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.”

    View full-size slide

  12. 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.

    View full-size slide

  13. Four steps to a better system structure
    Identify
    subsets
    first
    Apply
    Information
    hiding
    Hierarchical
    virtual
    machines
    Design the
    uses structure

    View full-size slide

  14. “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...”

    View full-size slide

  15. “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.”

    View full-size slide

  16. 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

    View full-size slide

  17. 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.

    View full-size slide

  18. Cake image copyright: Maxim Popov, 123RF Stock Photo

    View full-size slide

  19. 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

    View full-size slide

  20. Source: Adrian Cockcroft

    View full-size slide

  21. ICSA 2015
    ICSE 2016

    View full-size slide

  22. “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…”

    View full-size slide

  23. BF = Bug Frequency, BC = Bug churn, CF = Change Frequency, CC = Change Churn
    How much
    worse for
    architecture
    hotspots?

    View full-size slide

  24. 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

    View full-size slide

  25. 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

    View full-size slide

  26. 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.

    View full-size slide

  27. Copyright: Maxim Popov, 123RF Stock
    Photo
    1989

    View full-size slide

  28. “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.”

    View full-size slide

  29. 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.

    View full-size slide

  30. Lampson: make sure your interface affords an efficient implementation.
    Clements et al.: here’s how (Scalable Commutativity Rule)
    2013

    View full-size slide

  31. “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

    View full-size slide

  32. 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

    View full-size slide

  33. 2005
    | s/SOA/microservices/g

    View full-size slide

  34. “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.”

    View full-size slide

  35. 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

    View full-size slide

  36. “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.”

    View full-size slide

  37. Refactor -> Extract Microservice
    Refactor -> Change Model of
    Space and Time
    Copyright: Maxim Popov, 123RF Stock
    Photo

    View full-size slide

  38. Copyright: Maxim Popov, 123RF Stock
    Photo
    Now: inside a
    microservice
    Past: messages arriving
    from other services
    Future: commands sent
    to other services

    View full-size slide

  39. “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.

    View full-size slide

  40. 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.”

    View full-size slide

  41. 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

    View full-size slide

  42. 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

    View full-size slide

  43. 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/

    View full-size slide