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

DDD on AWS Lambda / How to implement your domain models on your AWS Lambda function

Atsushi Fukui
November 25, 2021

DDD on AWS Lambda / How to implement your domain models on your AWS Lambda function

マイクロサービスアーキテクチャでサービス分割の指針としてドメイン駆動設計が再び注目されています。このLTではLambda函数でドメインモデルを実装しユニットテストを実施する方法について15分で紹介することにチャレンジします。
詳細は以下の記事をご覧ください。
https://qiita.com/afukui/items/c705aca2cb46e182c5e4

Atsushi Fukui

November 25, 2021
Tweet

More Decks by Atsushi Fukui

Other Decks in Design

Transcript

  1. © 2021, Amazon Web Services, Inc. or its Affiliates.

    View Slide

  2. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Atsushi Fukui
    Senior Solutions Architect
    Serverless Specialist
    Amazon Web Services Japan
    DDD on AWS Lambda
    How to implement your domain models on your AWS Lambda function
    JAWS PANKLATION 2021
    2021/11/20

    View Slide

  3. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Who am I
    v Name
    v Atsushi Fukui / twitter: [email protected]
    v Role and company
    v Senior Solutions Architect Serverless Specialist
    v Amazon Web Services Japan
    v Interests
    v Software Architecture, Object Oriented Design and programming,
    Agile Development process
    v My favorite AWS Services
    v AWS Lambda, AWS Step SQS and other all serverless services

    View Slide

  4. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Agenda
    o Domain Driven Design (DDD)
    o Hexagonal Architecture
    o Domain models for sample application
    o How to implement unit testing code
    o Demo
    o Conclusion

    View Slide

  5. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Domain-driven design
    o Provides a broad framework for
    making design decisions and
    developing a technical
    vocabulary for discussing
    domain design
    o Ubiquitous language - modeling
    the language of the business
    o Provides guidance about
    tactical design - model domains
    with entities, value objects,
    repositories and services, and
    strategic design…

    View Slide

  6. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Hexagonal architecture
    Domain
    Model
    Ports
    Adapters
    Primary
    Actor
    Secondary
    Actor
    HTTP Request
    Event Message
    Queue

    File Storage
    Database
    Queue

    View Slide

  7. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Sample Senario
    o Vaccination reservation system
    o Use cases:
    o A recipient can search for some vacant slots and register a reservation slot for
    vaccination reservation.
    o A recipient cannot register her reservation if there is no vacant slot.
    o A recipient cannot reserve her reservations more than two slots.
    o A recipient cannot reserve two reservations if there are same date time.
    There are pure business logics you need to implement on your domain model.

    View Slide

  8. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Class diagram: register vaccination reservation

    View Slide

  9. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Sequence diagram: register vaccination reservation

    View Slide

  10. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Hexagonal architecture with the Lambda function
    Domain
    Model
    Ports
    Adapters
    Amazon API Gateway Amazon DynamoDB
    AWS Lambda function

    View Slide

  11. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Implement domain models

    View Slide

  12. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Domain models
    from slot import Slot
    class Recipient:
    def __init__(self, recipient_id:str, email:str, first_name:str, last_name:str, age:int):
    self.__recipient_id = recipient_id
    ….
    @property
    def recipient_id(self):
    return self.__recipient_id

    def add_reserve_slot(self, slot:Slot) -> bool:
    if self.are_slots_same_date(slot):
    return False
    if self.is_slot_counts_equal_or_over_two():
    return False
    self.__slots.append(slot)
    slot.use_slot()

    View Slide

  13. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Unit testing for functions

    View Slide

  14. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Unit test for Domain Model
    def test_cannot_append_slot_more_than_two(fixture_recipient, fixture_slot, fixture_slot_2, fixture_slot_3):
    slot = fixture_slot
    slot2 = fixture_slot_2
    slot3 = fixture_slot_3
    target = fixture_recipient
    target.add_reserve_slot(slot)
    target.add_reserve_slot(slot2)
    ret = target.add_reserve_slot(slot3)
    assert False == ret
    assert 2 == len(target.slots)
    def test_cannot_append_same_date_slot(fixture_recipient, fixture_slot):
    slot = fixture_slot
    target = fixture_recipient
    target.add_reserve_slot(slot)
    ret = target.add_reserve_slot(slot)
    assert False == ret
    assert 1 == len(target.slots)

    View Slide

  15. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Unit test for Ports and Adapters classes
    class DummyRecipientAdapter(IRecipientAdapter):
    def load(self, recipient_id:str) -> Recipient:
    return Recipient(recipient_id, email, first_name, last_name, age)
    def save(self, recipient:Recipient) -> bool:
    return True
    class DummyModule(Module):
    def configure(self, binder):
    binder.bind(RecipientPort, to=RecipientPort(DummyRecipientAdapter()))
    @pytest.fixture()
    def fixture_recipient_port():
    injector = Injector([DummyModule])
    recipient_port = injector.get(RecipientPort)
    return recipient_port

    View Slide

  16. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Unit test for Ports and Adapters classes
    def test_recipient_port_recipient_by_id(fixture_recipient_port):
    target = fixture_recipient_port
    recipient_id = "dummy_number"
    recipient = target.recipient_by_id(recipient_id)
    assert recipient != None
    assert recipient_id == recipient.recipient_id
    assert email == recipient.email
    assert first_name == recipient.first_name
    assert last_name == recipient.last_name
    assert age == recipient.age

    View Slide

  17. © 2021, Amazon Web Services, Inc. or its Affiliates.
    app.py calls concrate class instances
    class RequestPortModule(Module):
    def configure(self, binder):
    binder.bind(ReservationService, to=ReservationService(
    RecipientPort(DDBRecipientAdapter()), SlotPort(DDBSlotAdapter())))
    def lambda_handler(event, context):
    body = json.loads(event['body'])
    recipient_id = body['recipient_id']
    slot_id = body['slot_id']
    injector = Injector([RequestPortModule])
    request_port = injector.get(RequestPort)
    status = request_port.make_reservation(recipient_id, slot_id)

    View Slide

  18. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Demo

    View Slide

  19. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Summary
    o Loosely coupling and strong encapsulation are key concept.
    o Hexagonal architecture is an architecture pattern used for encapslating
    domain logic, and decoupling it from other implementaion details, such as
    infrastructure or client requests.
    o This approach can help create separetion of concerns and sepalate the
    domain logic from the infrastructure.
    o Inversion of control (IoC) or injecting object instances is useful for unit
    testing with mock or fake objects.

    View Slide

  20. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Please see my sample project on GitHub
    o https://github.com/afukui/jaws-pankration-ddd-lambda

    View Slide

  21. © 2021, Amazon Web Services, Inc. or its Affiliates.
    Thank you!

    View Slide