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

Domain Driven Design Kinda

Domain Driven Design Kinda

Explains how we kinda do Domain Driven Design in our Ruby on Rails at Product Hunt.

Radoslav Stankov

March 14, 2021
Tweet

More Decks by Radoslav Stankov

Other Decks in Technology

Transcript

  1. Domain Driven


    Desig
    n

    kinda

    View Slide

  2. 👋

    View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. View Slide

  8. View Slide

  9. View Slide

  10. View Slide

  11. View Slide

  12. Refactoring

    View Slide

  13. Life Goals

    View Slide

  14. View Slide

  15. Domain Driven
    Design

    View Slide

  16. ...kinda 🙈

    View Slide

  17. Product Hunt favored
    Domain Driven


    Desig
    n

    View Slide

  18. View Slide

  19. View Slide

  20. View Slide

  21. “Domain-driven design (DDD) is the concept
    that the structure and language of software
    code (classes, methods, functions, variables).”
    What is Domain Driven Design?

    View Slide

  22. What problems does DDD solve?
    “Developers are too wrapped up with
    technology and trying to solve problems using
    technology rather than careful thought and
    design”
    1

    View Slide

  23. What problems does DDD solve?
    “The database is given too much priority, and
    most discussions about the solutions center
    around the database and a data model rather
    than business processes and operations.”
    2

    View Slide

  24. What problems does DDD solve?
    “Developers don’t give proper emphasis to
    naming objects and operations according to
    the business purpose that they
    fi
    ll.”
    3

    View Slide

  25. What problems does DDD solve?
    “Application logic is disjointed and hard to
    follow. It is hard to see an overview of the
    application features”
    4

    View Slide

  26. What are the issues with traditional DDD?
    “In order to help maintain the model as a pure
    and helpful language construct, the team must
    typically implement a great deal of isolation and
    encapsulation within the domain model. Which
    overcomplicates the system.”
    1

    View Slide

  27. What are the issues with traditional DDD?
    “Rails and Node doesn't
    fi
    t very well with DDD
    mindset. DDD comes from Java and similar
    languages.”
    2

    View Slide

  28. What are the issues with traditional DDD?
    “A lot of DDD practices are focused on
    consultancy model and are used for model
    complicated business processes.”
    3

    View Slide

  29. Product Hunt favored
    Domain Driven


    Desig
    n

    View Slide

  30. View Slide

  31. What


    is


    Domain Driven Design
    ?

    View Slide

  32. Ubiquitous Language
    “A language structured around the domain
    model and used by all team members to
    connect all the activities of the team with the
    software.”

    View Slide

  33. Ubiquitous Language
    “There are only two hard things in Computer
    Science: cache invalidation and naming things.”


    -- Phil Karlton

    View Slide

  34. Ubiquitous Language
    app/models/use.rb 🙈

    View Slide

  35. Ubiquitous Language
    app/models/use.rb 🤮

    View Slide

  36. Ubiquitous Language
    app/models/stack_item.rb 👍

    View Slide

  37. Ubiquitous Language
    app/model/founder_club/member.rb 👍

    View Slide

  38. Domains
    “A sphere of knowledge, in
    fl
    uence, or activity.
    The subject area to which the user applies a
    program is the domain of the software;”

    View Slide

  39. Domain Types
    🎂 Core domain

    🍰 Supporting sub domain

    🧁 Generic sub domain

    View Slide

  40. Domain Types
    🎂 Core domain

    🍰 Supporting sub domain

    🧁 Generic sub domain

    🥮 Utilities (infrastructure) sub domain

    View Slide

  41. Domain Types
    🎂 Core domain - Post, User, Ship

    🍰 Supporting sub domain - Collections, Discussions

    🧁 Generic sub domain - Votes, Comments, Seo

    🥮 Utilities - External, ExecSQL, HandleRaceCondition

    View Slide

  42. What is PH Code Domain

    View Slide

  43. 🤷

    View Slide

  44. Moderation
    Voting Comments
    Posts
    Collections
    Maker Goals
    Sharing
    Seo
    Discussions
    Ask
    Ship
    Mentors Founder Club Golden Kitty
    Maker Fest
    Topics
    Stories
    Spam Newsletter
    Noti
    fi
    cations Metrics
    Users
    Payments
    Activity Feed
    Jobs

    View Slide

  45. Moderation
    Voting Comments
    Posts
    Collections
    Maker Goals
    Sharing
    Seo
    Discussions
    Ask
    Ship
    Mentors Founder Club Golden Kitty
    Maker Fest
    Topics
    Stories
    Spam Newsletter
    Noti
    fi
    cations Metrics
    Users
    Payments
    Activity Feed
    Jobs
    Core Feature Generic
    Context Map

    View Slide

  46. Moderation
    Voting Comments
    Posts
    Collections
    Maker Goals
    Sharing
    Seo
    Discussions
    Ask
    Ship
    Mentors Founder Club Golden Kitty
    Maker Fest
    Topics
    Stories
    Spam Newsletter
    Noti
    fi
    cations Metrics
    Users
    Payments
    Activity Feed
    Jobs
    Core Feature Generic
    Context Map
    Utilities

    View Slide

  47. Bounded Context
    “A semantic contextual boundary. This means
    that within the boundary each component of the
    software model has a speci
    fi
    c meaning and
    does speci
    fi
    c things.”

    View Slide

  48. View Slide

  49. ...kinda 🙈

    View Slide

  50. Admin
    Other


    Bounded
    Context
    Utilities


    Bounded Context (Domain)
    Models Services Jobs
    GraphQL
    Mutations Resolvers Types

    View Slide

  51. https://www.phoenixframework.org/

    View Slide

  52. defmodule Hello.Accounts do


    @moduledoc """


    The Accounts context.


    """


    import Ecto.Query, warn: false


    alias Hello.Repo


    alias Hello.Accounts.User


    @doc """


    Returns the list of users.


    ## Examples


    iex> list_users()


    [%User{}, ...]


    """


    def list_users do


    Repo.all(User)


    end


    ...


    end

    View Slide

  53. Showcase 1

    Feature Domain

    View Slide

  54. View Slide

  55. /app/domain/

    /app/domain/founder_club.r
    b

    /app/domain/founder_club/*.rb

    View Slide

  56. FounderClub.join_waitlist(user:)

    FounderClub.join(user:)


    FounderClub.request_access(user:, code:)


    FounderClub.deliver_waitlist_invite(invite:)


    FounderClub.plan_for(code:)

    FounderClub.subscribe(user:, subscription_id:)


    FounderClub.claim_deal(user:, deal:)


    FounderClub.claimed_deals_by(user:)


    FounderClub.deals_available_to(user:)


    FounderClub.create_referral_code(user:, email:)


    FounderClub.destroy_referral_code(user:, email:)

    FounderClub.referrals_of(user:)


    FounderClub.active_subscription?(user)


    FounderClub.list_subscriptions

    FounderClub.transfer_subscription(from:, to:)

    View Slide

  57. FounderClub::Admin::DealForm

    FounderClub::Policy

    FounderClub::MailerInfo
    🤷

    View Slide

  58. FounderClub.admin_deal_form

    FounderClub.policy

    FounderClub.mail_info
    🤔

    View Slide

  59. module FounderClub


    extend self



    def admin_deal_form

    FounderClub::Admin::DealForm

    end


    def policy

    FounderClub::Policy

    end


    def mailer_info


    FounderClub::MailerInfo

    end

    end
    🤔

    View Slide

  60. Showcase 2

    Generic Domain

    View Slide

  61. Sharing.text_for(post)

    Sharing.text_for(post, current_user: user)

    Sharing.image_for(post)

    Sharing.image_for_comment(comment, highlighted_text: 'Awesome')

    View Slide

  62. module Sharing


    extend self


    def text_for(subject, current_user: nil)


    generator = FindConst.call(Sharing::Text, subject)


    if generator.method(:call).arity == 1


    generator.call(subject)


    else


    generator.call(subject, current_user: current_user)


    end


    end


    def image_for(subject)


    generator = FindConst.call(Sharing::ImageUrl, subject)


    generator.call(subject)


    end


    def image_for_comment(comment, highlighted_text:)


    Sharing::ImageUrl:Comment.call(comment, highlighted_text: highlighted_text)


    end


    endd


    View Slide

  63. Domain Event
    “A domain object that de
    fi
    nes an event
    (something that happens). A domain event is an
    event that domain experts care about.”

    View Slide

  64. Domain Event != Event Souring

    View Slide

  65. Kitty Event
    s

    https://github.com/producthunt/KittyEvents

    View Slide

  66. Design Patterns
    🚗 Entity

    🚕 Value Object

    🚙 Aggregate


    🚌 Repository


    🚎 Facade


    🚐 Factory


    🚚 Service

    🚛 Presenter

    View Slide

  67. Design Patterns
    🚗 Entity

    🚕 Value Object

    🚙 Aggregate


    🚌 Repository


    🚎 Facade


    🚐 Factory


    🚚 Service

    🚛 Presenter

    View Slide

  68. Design Patterns
    🚗 Entity

    🚕 Value Object

    🚙 Aggregate


    🚌 Repository


    🚎 Facade


    🚐 Factory


    🚚 Service

    🚛 Presenter

    View Slide

  69. View Slide

  70. https://github.com/producthunt/producthunt/tree/master/app/services/sharing
    👉
    https://github.com/producthunt/stacks/tree/master/backend/app/services/share

    View Slide

  71. module Share::Subject
    extend self
    def call(subject:, current_profile:
    )

    subject_class = subject.class.name.tr('::', ''
    )

    share = "Share::Subjects::#{subject_class}".constantiz
    e

    share.generate subject, current_profil
    e

    end
    end

    View Slide

  72. module Share
    extend self
    def message_for(subject, current_profile: nil
    )

    subject_class = subject.class.name.tr('::', ''
    )

    share = "Share::Subjects::#{subject_class}".constantiz
    e

    share.generate subject, current_profil
    e

    end
    end

    View Slide

  73. module Share
    extend self
    def message_for(subject, current_profile: nil
    )

    subject_class = subject.class.name.tr('::', ''
    )

    share = "Share::Message::#{subject_class}".constantiz
    e

    share.generate subject, current_profil
    e

    end
    end

    View Slide

  74. module Share
    extend self
    def message_for(subject, current_profile: nil
    )

    share = Utils.module_for(subject, in: Share::Message
    )

    share.generate subject, current_profil
    e

    end
    end
    💡

    View Slide

  75. View Slide

  76. Books

    View Slide

  77. View Slide

  78. Whats next...

    View Slide

  79. ... any ideas? 💡 😅

    View Slide

  80. View Slide