可扩展软件的架构。

资助包维护!
Patreon

v2.0.0 2024-07-04 08:26 UTC

README

Documentation Slack Chat Build Status Latest Stable Version License

目录

关于Lucid

Lucid 是一个用于构建可扩展 Laravel 项目的软件架构。它将 命令总线领域驱动设计 作为核心,在此基础上构建了一组目录和类来组织业务逻辑。它还从 SOA(面向服务的架构) 中借鉴了将功能封装在服务中的概念,并通过不仅仅是类来丰富这一概念。

使用 Lucid

  • 轻松编写干净代码
  • 保护代码免受时间侵蚀
  • 以典型所需时间的一小部分审查代码
  • 将经过验证的实践和模式纳入您的应用程序
  • 导航代码并在代码库之间移动而不会感到陌生

概念

该架构是最佳实践、设计模式和经过验证的方法的融合。

  • 命令总线:用于派遣工作单元。在 Lucid 术语中,这些单元将是 功能作业操作
  • 领域驱动设计:通过根据它们所属的主题对工作单元进行分类来组织工作单元。
  • 面向服务的架构:封装和管理具有相同目的的功能及其所需资源(路由、控制器、视图、数据库迁移等)。

如果您更喜欢视频,请观看 2016 年 Laracon EU 的公告

目录

定位

在典型的 MVC 应用程序中,Lucid 将是应用程序入口点和执行工作的工作单元之间的纽带,确保代码不走向歧途

Lucid MVC Position

一看...

Lucid Stack

框架

提供“内核”以执行繁琐工作的重担,例如请求/响应生命周期、依赖注入和其他核心功能。

基础

扩展框架以提供适用于应用程序的高级抽象,可以在整个堆栈中共享,而不是特定于案例。

以下是一些可能包含在基础中的示例

  • DateTime:一个用于常见日期和时间函数的支持类
  • JsonSerializableInterface:用于标识一个对象,使其可以从和到 JSON 格式进行序列化

领域

提供分离以将作业及其属于同一主题的相应类进行分类。一个领域在与其他领域隔离的情况下运行,并通过 Lucid 作业仅将其功能暴露给功能和操作。

考虑以下结构作为领域可能的外观示例

app/Domains/GitHub
├── GitHubClient
├── Jobs
│   ├── FetchGitHubRepoInfoJob
│   └── LoginWithGitHubJob
├── Exceptions
│   ├── InvalidTokenException
│   └── RepositoryNotFoundException
└── Tests
    └── GitHubClientTest
    └── Jobs
        ├── FetchGitHubReposJobTest
        └── LoginWithGitHubJobTest

文档包含更多关于使用域的详细信息。

服务

目录功能丰富,用于将[单体]({{<ref "/micro-vs-monolith/#monolith">}})在多用途应用程序中划分为关注区域。

以一个示例应用为例,我们输入食谱并希望我们的成员在论坛中进行讨论,我们将有两个服务: 1) 厨房,2) 论坛,其中厨房将管理所有与食谱相关的功能,而论坛则显而易见。

app/Services
├── Forum
└── Kitchen

以下是单个服务结构的示例,突出显示的是Lucid特定的目录

app/Services/Forum
├── Console
│   └── Commands
├── Features
├── Operations
├── Http
│   ├── Controllers
│   └── Middleware
├── Providers
│   ├── KitchenServiceProvider
│   ├── BroadcastServiceProvider
│   └── RouteServiceProvider
├── Tests
│   └── Features
│   └── Operations
├── database
│   ├── factories
│   ├── migrations
│   └── seeds
├── resources
│   ├── lang
│   └── views
└── routes
    ├── api
    ├── channels
    ├── console
    └── web

文档提供了更多关于服务和它们内容的示例。

功能

在类中表示人类可读的应用功能。它包含实现该功能的逻辑,但以尽可能少的细节,通过在域和应用程序或服务级别运行作业。

在控制器的方法(在MVC中)中,将只包含一个服务于Feature类的行,从而实现最薄形式的控制器。

class AddRecipeFeature extends Feature
{
    public function handle(AddRecipe $request)
    {
        $price = $this->run(CalculateRecipePriceOperation::class, [
            'ingredients' => $request->input('ingredients'),
        ]);

        $this->run(SaveRecipeJob::class, [
            'price' => $price,
            'user' => Auth::user(),
            'title' => $request->input('title'),
            'ingredients' => $request->input('ingredients'),
            'instructions' => $request->input('instructions'),
        ]);

        return $this->run(RedirectBackJob::class);
    }
}

文档关于功能的说明扩展了如何将它们作为类在任何地方提供服务。

操作

它们的目的在于通过将作业拼接在一起,提高代码的可重用程度,从多个域提供复合功能。

class NotifySubscribersOperation extends Operation
{
    private int $authorId;

    public function __construct(int $authorId)
    {
        $this->authorId = $authorId;
    }

    /**
     * Sends notifications to subscribers.
     *
     * @return int Number of notification jobs enqueued.
     */
    public function handle(): int
    {
        $author = $this->run(GetAuthorByIDJob::class, [
            'id' => $this->authorId,
        ]);

        do {

            $result = $this->run(PaginateSubscribersJob::class, [
                'authorId' => $this->authorId,
            ]);

            if ($result->subscribers->isNotEmpty()) {
                // it's a queueable job so it will be enqueued, no waiting time
                $this->run(SendNotificationJob::class, [
                    'from' => $author,
                    'to' => $result->subscribers,
                    'notification' => 'article.published',
                ]);
            }

        } while ($result->hasMorePages());

        return $result->total;
    }
}

文档介绍了这个简单但强大的概念。

数据

对于一组可扩展的互联数据元素,我们在app/Data中为它们创建了一个位置,因为随着时间的推移,在应用程序中编写可能需要比模型更多的数据,例如仓库、值对象、集合等。

app/Data
├── Models
├── Values
├── Collections
└── Repositories

好处

这可能看起来像过度设计,但有其宝贵的优势。

组织

  • 在审查代码时,系统变化的可预测影响
  • 由于我们将应用程序划分为隔离的关注区域(分而治之),因此调试时间减少
  • 在单体中,我们的每个服务都可以有自己的版本控制系统(例如,API服务在v1,而聊天在v2.3,但它们都位于同一代码库中)

重用与替换

通过将我们的应用程序分解为小的代码构建块——即单元——我们立即打开了在应用程序中通过数据和域进行高度代码共享以及用最小的摩擦和债务进行替换的大门。

边界

通过设定边界,你迈出了保护应用程序代码免于变得无法忍受地庞大的一步,并使新开发者更容易上手。最重要的是,你将技术债务减少到最低,这样你就不必用错误和失眠来偿还;代码不是在好意或愿望上运行的。

多租户

当我们的应用程序扩展时,我们通常会在不同位置运行它的多个实例,在某个时候,我们可能希望在某些区域激活我们的代码库的某些部分,关闭其他部分。

以下是一个简单的示例,运行同一个应用程序的Api后台办公室Web应用实例,在Lucid术语中,这些是服务,它们通过数据共享功能

Lucid multitenancy

贡献

错误与问题报告

为了鼓励积极的合作,Lucid强烈鼓励通过拉取请求进行贡献。“错误报告”可以在问题中搜索或创建,或以包含失败测试或重现错误步骤的拉取请求的形式发送。

如果你提交错误报告,你的问题应包含标题和关于问题的清晰描述。你还应包括尽可能多的相关信息和一个演示问题的代码示例。错误报告的目标是使你自己和他人能够轻松地重现错误并开发修复方案。

⏱ 通常每周检查约三次 PR 和问题,因此您的很可能很快就会被发现。

Lucid Architecture 的源代码位于 GitHub 上,地址为 lucidarch/lucid

支持问题

Lucid Architecture 的 GitHub 问题跟踪器不是为了提供帮助或支持。相反,请使用以下渠道之一:

  • 讨论区 是大多数对话发生的地方。
  • 如果您想聊天,请在我们的官方 Slack 工作区#support 频道联系我们
  • 如果您喜欢在 StackOverflow 上发帖,可以使用 #lucidarch 标签它们

核心开发讨论

您可以在 Lucid 讨论 中提出新的功能或现有 Lucid Architecture 行为的改进。如果您提出一个新的功能,请愿意至少实现完成该功能所需的代码的一部分,或者在此期间合作进行活跃的构思。

有关错误、新功能和现有功能的实施的非正式讨论发生在 Lucid Slack 工作区#internals 频道中。Abed Halawi,Lucid 的维护者,通常在东欧夏令时(EEST)的每周工作日上午 8 点到下午 5 点在该频道中,其他时间偶尔出现。

哪个分支?以及如何贡献

包含最新实时版本并发布的是 main 分支。

  • 分叉此存储库
  • 将分叉的存储库克隆到您将编辑代码的地方
  • 为您的编辑创建一个分支(例如 feature/queueable-unitsfix/issue-31
  • 使用有意义的简短消息提交您的更改及其测试(如果适用)
  • 推送您的分支 git push origin feature/queueable-units
  • main 分支打开一个 PR,这将运行您的更改测试

⏱ PR 和问题通常每周检查约三次。

开发设置

以下是在 Lucid 上进行开发的设置步骤

假设我们处于 ~/dev 目录...

  • 克隆分叉的存储库 [你的用户名]/lucid,这将创建一个位于 ~/dev/lucidlucid 文件夹
  • 创建一个 Laravel 项目来测试您在其中实现的代码 composer create-project laravel/laravel myproject
  • 将创建的 Laravel 项目连接到本地 Lucid 安装;在 Laravel 项目的 composer.json
    "require": {
        "...": "",
        "lucidarch/lucid": "@dev"
    },
    "repositories": [
        {
            "type": "path",
            "url": "~/dev/lucid",
            "options": {
                "symlink": true
            }
        }
    ],
    "minimum-stability": "dev",

请确保将 url 改为您的目录的绝对路径

  • 运行 composer update 以创建符号链接

现在您在 lucid 目录中的所有更改将自动在项目中生效。

安全漏洞

如果您在 Lucid 中发现安全漏洞,请将电子邮件发送给 Abed Halawi(halawi.abed@gmail.com)。所有安全漏洞都将得到及时解决。

编码风格

Lucid Architecture 遵循 PSR-2 编码规范和 PSR-4 自动加载规范。

PHPDoc

以下是 Lucid Architecture 文档块的示例。请注意,@param 属性后面跟着两个空格,然后是参数类型,再跟着两个空格,最后是变量名

/**
 * Register a binding with the container.
 *
 * @param  string|array  $abstract
 * @param  \Closure|string|null  $concrete
 * @param  bool  $shared
 * @return void
 *
 * @throws \Exception
 */
public function bind($abstract, $concrete = null, $shared = false)
{
    //
}

行为准则

Lucid Architecture 的行为准则源自 Laravel 的行为准则。任何违反行为准则的行为都可以报告给 Abed Halawi(halawi.abed@gmail.com

  • 参与者将容忍不同的观点。
  • 参与者必须确保他们的语言和行为不包含个人攻击和贬低性言论。
  • 在解读他人的言语和行为时,参与者应始终假设对方有良好的意图。
  • 任何可以合理认为构成骚扰的行为将不会受到容忍。