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

Designing testable serverless apps using hexagonal architecture

Designing testable serverless apps using hexagonal architecture

Presentation from Serverless Days Hamburg 2019 (https://hamburg.serverlessdays.io).

Description:

The main idea of hexagonal architecture is to allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases. On the other side, it is not trivial to run and test serverless applications locally. But what if we apply hexagonal architecture to serverless functions?

It seems they are natural fit!

With hexagonal architecture, your can design beautiful serverless functions, that can be run and tested locally or in the serverless environment. It also allows you to write unit tests without complex mocks, and as many integration tests as you need. As a bonus, your code looks clean and it’s easy to maintain, and hexagonal architecture helps you fighting vendor lock-in.

The main goal of this talk is to show you how to design testable serverless functions. It starts with explanation of hexagonal architecture and it’s importance for serverless apps, and it ends with real-world examples using Node.js.

Slobodan Stojanović

February 15, 2019
Tweet

More Decks by Slobodan Stojanović

Other Decks in Programming

Transcript

  1. What's the scariest thing
    about serverless?

    View full-size slide

  2. @slobodan_
    Long-running tasks?

    View full-size slide

  3. @slobodan_
    Compliance?

    View full-size slide

  4. @slobodan_
    Using binaries and large dependencies?

    View full-size slide

  5. @slobodan_
    Cold start?

    View full-size slide

  6. @slobodan_
    Cold start with VPN?

    View full-size slide

  7. @slobodan_
    Node.js?

    View full-size slide

  8. @slobodan_
    But, what about…

    View full-size slide

  9. @slobodan_
    BIG

    View full-size slide

  10. @slobodan_
    BAD

    View full-size slide

  11. @slobodan_
    VENDOR
    LOCK-IN

    View full-size slide

  12. @slobodan_
    What is vendor lock-in?

    View full-size slide

  13. @slobodan_
    "In economics, vendor lock-in, makes a
    customer dependent on a vendor for
    products and services, unable to use another
    vendor without substantial switching costs."

    View full-size slide

  14. @slobodan_
    A guy with a lot of servers.

    Let's call him Jeff.

    View full-size slide

  15. @slobodan_
    A guy with a lot of servers.

    Let's call him Jeff.

    View full-size slide

  16. @slobodan_
    Jeff is smart, and he knows
    how do you use his servers.

    View full-size slide

  17. @slobodan_
    Jeff is smart, and he knows
    how do you use his servers.

    View full-size slide

  18. @slobodan_
    Jeff is smart, and he knows
    how do you use his servers.

    View full-size slide

  19. @slobodan_
    Jeff is smart, and he knows
    how do you use his servers.

    View full-size slide

  20. @slobodan_
    Jeff is smart, and he knows
    how do you use his servers.

    View full-size slide

  21. @slobodan_
    Jeff is smart, and he knows
    how do you use his servers.

    View full-size slide

  22. @slobodan_
    Jeff is smart, and he knows
    how do you use his servers.

    View full-size slide

  23. @slobodan_
    But what if Jeff is
    actually a villain?

    View full-size slide

  24. @slobodan_
    But what if Jeff is
    actually a villain?

    View full-size slide

  25. @slobodan_
    But what if Jeff is
    actually a villain?

    View full-size slide

  26. @slobodan_
    Your wallet would not be happy…

    View full-size slide

  27. @slobodan_
    Another guy with a lot of servers.

    Let's call him Bill.

    View full-size slide

  28. @slobodan_
    Another guy with a lot of servers.

    Let's call him Bill.

    View full-size slide

  29. @slobodan_
    Another guy with a lot of servers.

    Let's call him Bill.

    View full-size slide

  30. @slobodan_
    Another guy with a lot of servers.

    Let's call him Bill.

    View full-size slide

  31. @slobodan_
    Another guy with a lot of servers.

    Let's call him Bill.

    View full-size slide

  32. @slobodan_
    That's vendor lock-in in the cloud

    View full-size slide

  33. @slobodan_
    "My train of thought went like this:
    the term “lock-in” is misleading.
    We are really talking about switching costs."
    Mark Schwartz

    Enterprise Strategist at AWS

    View full-size slide

  34. @slobodan_
    "As soon as you commit yourself to
    a platform or a vendor you will have
    switching costs if you later decide to change."
    Mark Schwartz

    Enterprise Strategist at AWS

    View full-size slide

  35. @slobodan_
    How to fight
    vendor lock-in?

    View full-size slide

  36. @slobodan_
    Or how to keep your
    switching costs
    reasonable?

    View full-size slide

  37. @slobodan_
    • Planning and analysis
    • Good architecture
    • Deployment procedures
    How likely will I need to switch?
    What would be the cost?

    View full-size slide

  38. @slobodan_
    That leads us to our topic…

    View full-size slide

  39. Designing testable
    serverless apps
    using hexagonal architecture

    View full-size slide

  40. @slobodan_
    But, before we continue…

    View full-size slide

  41. Slobodan Stojanovic
    CTO @ Cloud Horizon & CTO @ Vacation Tracker
    co-author of Serverless Applications with Node.js book
    AWS Serverless Hero
    @slobodan_
    serverless.pub

    View full-size slide

  42. @slobodan_
    Designing testable serverless apps
    using hexagonal architecture

    View full-size slide

  43. @slobodan_
    Why is testing important
    for serverless apps?

    View full-size slide

  44. @slobodan_
    Most of the time serverless apps
    are not fully isolated monoliths
    without integrations

    View full-size slide

  45. @slobodan_
    Instead, they contain many services
    interacting with each other
    and with external dependencies

    View full-size slide

  46. @slobodan_
    Integrations can change every moment!

    View full-size slide

  47. @slobodan_
    Tests don't prevent changes.
    They make sure your changes
    are not accidental.

    View full-size slide

  48. @slobodan_
    But how do you know
    what should you test in a serverless app?

    View full-size slide

  49. @slobodan_
    Testing pyramid

    View full-size slide

  50. @slobodan_
    Testing pyramid
    vs
    "Serverless testing pyramid"

    View full-size slide

  51. @slobodan_
    Integration tests are cheaper,
    but also more important,
    because the common serverless app
    is split into many small pieces

    View full-size slide

  52. @slobodan_
    Designing testable serverless apps
    using hexagonal architecture

    View full-size slide

  53. @slobodan_
    Ok, so which architecture
    is the best for serverless apps?

    View full-size slide

  54. @slobodan_
    Any architecture that
    will let you test your serverless app easily
    and keep switching costs low.

    View full-size slide

  55. @slobodan_
    Because sooner or later you'll need to
    switch/migrate pieces of your app.

    View full-size slide

  56. @slobodan_
    Not to another cloud vendor,
    but to your new service,
    new or changed integration…

    View full-size slide

  57. @slobodan_
    Risks to consider when building
    a serverless app

    View full-size slide

  58. @slobodan_
    • configuration risks
    • technical workflow risks
    • business logic risks
    • integration risks

    View full-size slide

  59. @slobodan_
    One of the app architectures
    that fits these needs is

    hexagonal architecture

    View full-size slide

  60. @slobodan_
    Designing testable serverless apps
    using hexagonal architecture

    View full-size slide

  61. @slobodan_
    "Allow an application to equally be driven by users,
    programs, automated test or batch scripts,
    and to be developed and tested in isolation from
    its eventual run-time devices and databases."
    Alistair Cockburn

    Creator of Hexagonal architecture

    View full-size slide

  62. @slobodan_
    An example

    View full-size slide

  63. @slobodan_
    Code, please

    View full-size slide

  64. @slobodan_
    const {

    httpResponse,
    parseApiEvent,

    SnsRepository

    } = require('../common')

    const main = require('./main')

    async function handler(event) {
    const { body, headers } = parseApiEvent(event)
    // Create instance of SNS notification repository

    const notification = new SnsRepository(

    process.env.topic
    )
    // Invoke main function with all dependencies

    await main(body, headers, notification)

    return httpResponse()

    }

    View full-size slide

  65. @slobodan_
    await main(body, headers, notification)

    View full-size slide

  66. @slobodan_
    Unit tests

    View full-size slide

  67. @slobodan_
    await main(body, headers, mockNotification)
    Mock notification repository
    instance
    Some static
    values

    View full-size slide

  68. @slobodan_
    Integration tests

    View full-size slide

  69. @slobodan_
    await main(body, headers, localNotification)
    Local notification adapter,
    using JS events for example
    Some static
    values

    View full-size slide

  70. @slobodan_
    Simple and nice

    View full-size slide

  71. @slobodan_
    But, do you remember…

    View full-size slide

  72. @slobodan_
    BIG

    View full-size slide

  73. @slobodan_
    BAD

    View full-size slide

  74. @slobodan_
    VENDOR
    LOCK-IN

    View full-size slide

  75. @slobodan_
    How does hexagonal architecture
    help you fighting vendor lock-in?

    View full-size slide

  76. @slobodan_
    Story time

    View full-size slide

  77. @slobodan_
    Vacation Tracker
    vacationtracker.io

    View full-size slide

  78. @slobodan_
    vacationtracker.io

    View full-size slide

  79. @slobodan_
    • Serverless prototype
    • Small team (1 fulltime developer)
    • Initial product was Serverless
    chatbot + Express.js and MongoDB
    • Growing fast (200+ teams using it)

    View full-size slide

  80. @slobodan_
    • Express -> Serverless migration
    • MongoDB -> DynamoDB migration

    View full-size slide

  81. @slobodan_
    Let's talk about
    MongoDB -> DynamoDB
    switch

    View full-size slide

  82. @slobodan_
    How does this
    look like?

    View full-size slide

  83. @slobodan_
    describe('DynamoDB repository', () => {
    describe('unit', () => { ... })
    describe('integration', () => {
    beforeAll(() => {
    // Create test DB
    })
    afterAll(() => {
    // Destroy test DB
    })
    // Tests
    })
    })

    View full-size slide

  84. @slobodan_
    beforeAll(async () => {
    const params = { ... }
    await dynamoDb.createTable(params).promise()
    await dynamoDb.waitFor('tableExists', {
    TableName: tableName
    }).promise()
    })

    View full-size slide

  85. @slobodan_
    afterAll(async () => {
    await dynamoDb.deleteTable({
    TableName: tableName
    }).promise()
    await dynamoDb.waitFor('tableNotExists', {
    TableName: tableName
    }).promise()
    })

    View full-size slide

  86. @slobodan_
    And they lived happily ever after…

    View full-size slide

  87. @slobodan_
    Beyond testing

    View full-size slide

  88. @slobodan_
    What should we do with things
    that can't be tested?

    View full-size slide

  89. @slobodan_
    What should we do with things
    that can't be tested?
    For example, Google or someone else deprecated
    an API while your app is in production

    View full-size slide

  90. @slobodan_
    Make sure you are monitoring your
    app and tracking errors

    View full-size slide

  91. @slobodan_
    Monitoring/error-tracking tools

    View full-size slide

  92. @slobodan_
    • Built-in tools (CloudWatch, X-Ray)
    • Epsagon
    • IOpipe
    • Thundra
    • Lumigo
    • and many others

    View full-size slide

  93. @slobodan_
    Serverless apps often heavily relies on
    front end, in those cases you need to track
    front end errors as well

    View full-size slide

  94. @slobodan_
    desole.io

    View full-size slide

  95. @slobodan_
    Summary

    View full-size slide

  96. @slobodan_
    • Good architecture helps you to maintain your
    switching costs low (or at least reasonable)
    • Hexagonal architecture is a nice fit for
    serverless apps
    • Test your integrations (and app in general)
    • Testing is not enough, you'll need monitoring
    and error tracking for your serverless apps

    View full-size slide

  97. @slobodan_
    Links to the things
    I mentioned

    View full-size slide

  98. @slobodan_
    • Mark Schwartz - Switching Costs and Lock-In:
    amzn.to/2S4iT3G
    • Hexagonal Architecture: bit.ly/hex-arch
    • Vacation Tracker: vacationtracker.io
    • Hexagonal Architecture at Vacation Tracker:
    bit.ly/vt-hex-arch
    • Desole (error-tracking tool): desole.io

    View full-size slide

  99. @slobodan_
    One more thing!

    View full-size slide

  100. @slobodan_
    Serverless Applications with Node.js
    Use claudia40 promo code
    for 40% off
    serverless.pub/book
    @slobodan_

    View full-size slide

  101. @slobodan_
    Thank you!

    View full-size slide

  102. @slobodan_
    Thank you!
    Danke

    View full-size slide