在Python中使用DDD&Clean Architecture建造SaaS。
#教程 #python #learning #ddd

已经有几个星期了,我决定从事SaaS申请工作。

我选择了python作为编程语言,因为我觉得有点生锈 - 我已经是一个node.js开发人员了一段时间,想刷新我的python技能。

现在,我不建议这种方法。我建议专注于问题和解决方案,最重要的是与客户交谈。

构建真实应用程序时,您可以选择最熟悉的编程语言。专注于您的知识和专业知识比陷入学习或刷新新的编程语言的复杂性更重要。

我的目标也是阐述我的Python技能,学习DDD和清洁建筑实践。因此,我选择了Python。

问题空间

公司正在为所有内部通信使用Slack,并且通过共享渠道,外部成员也可以成为对话的一部分。被用来支持客户查询,与客户交谈并与团队成员合作等等。
管理与客户和内部团队的对话可能具有挑战性,因为很容易被淹没。为了解决这个问题,我决定构建一个SaaS应用程序,该应用程序与Slack无缝集成,并为团队和公司提供有效的对话支持。该解决方案旨在简化通信过程并提高提供支持的效率。

在DDD中,第一步是了解问题空间。现在,我们已经了解了要解决的问题,我们可以专注于解决方案空间 -

发现实体和属性

当我们关心其个性与系统中的所有其他对象时,

实体是一个域对象。这是能够在其一生中改变的独特之处。更改可能是如此广泛,以至于对象看起来可能有所不同,但是它是同一对象。

租户
当我们建立SaaS时,我们想代表客户。通常称他们为租户。租户可以拥有用户,客户,计费信息等。我们只有一些有关租户的信息;让我们继续。我们可以稍后添加固有的细节。

class Tenant(AbstractEntity):
    def __init__(self, tenant_id: str | None) -> None:
        self.tenant_id = tenant_id

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, Tenant):
            return False
        return self.tenant_id == other.tenant_id

    def __repr__(self) -> str:
        return f"""Tenant(
            tenant_id={self.tenant_id}
        )"""

我们将在建立过程中添加更多详细信息;现在,实体看起来不错。

用户
租户将有用户,我可以想到用户扮演一些角色。我们只有关于用户将如何注册或创建的一些信息,但我知道如何将它们表示为实体。有了这些详细信息,让我们定义用户实体。

class UserRole(Enum):
    OWNER = "owner"
    ADMINISTRATOR = "administrator"
    MEMBER = "member"

class User(AbstractEntity):
    def __init__(
        self,
        tenant_id: str,
        user_id: str | None,
        name: str | None,
        role: UserRole.MEMBER,
    ) -> None:
        self.tenant_id = tenant_id
        self.user_id = user_id
        self.name = name
        self.role = role

    def __eq__(self, other: object) -> bool:
        if not isinstance(other, User):
            return False
        return (self.tenant_id == other.tenant_id) \
          and (self.user_id == other.user_id)

    def __repr__(self) -> str:
        return f"""User(
            tenant_id={self.tenant_id},
            user_id={self.user_id},
            name={self.name},
            role={self.role.value}
        )"""

我们知道,用户应在租户中唯一可识别;因此,实体对象的平等实现是tenant_iduser_id属性的检查。

理解python中的__eq__不超出了讨论的范围。我将来会写关于它的文章。

验证
例如,我们可以在实体中安全地添加一些验证,例如,用户实体确保我们在创建/初始化用户实体时具有tenant_id,例如

...
def __init__(
        self,
        tenant_id: str,
        user_id: str | None,
        name: str | None,
        role: UserRole.MEMBER,
    ) -> None:
        self.tenant_id = tenant_id
        self.user_id = user_id
        self.name = name
        self.role = role
        ...

        assert tenant_id is not None
        assert role is not None

在上面的代码段中,我确保我们不会将tenant_id设置为None/Null,以执行用户始终是租户的一部分的域合同。

目前,我会跳过这些验证,但是在域实体中进行检查没有任何害处。

在下一期中,#2,我将重点介绍Slack Events API映射到实体和值对象。我还将更详细地探讨实体与价值对象的固有详细信息。

直到那时,遵循此系列。