appnap/lucid

可扩展软件的架构。

v1.0.13 2024-03-04 11:44 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

文档“使用域”包含更多详细信息。

服务

目录功能丰富,用于将[单体]{}

应用中的关注区域进行分离。

以一个应用程序为例,我们输入食物食谱,并希望我们的成员在论坛中进行讨论,我们将有两个服务: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)中,将只会有一个服务于特征类的行,从而实现最薄的控制器形式。

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,但仍然位于)。

重用与替换

通过将应用程序分解成小的代码构建块——即单元——我们立即打开了应用程序中高度代码共享的大门,与数据域一起以及最小摩擦和技术债务的可替换性。

边界

通过设置边界,你迈出了保护应用程序代码免于变得难以承受地庞大的一步,并使新开发人员更容易上线。最重要的是,你已经将技术债务降至最低,这样你就不必用错误和失眠来支付;代码不是运行在良好的意图或愿望上。

多租户

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

这是一个谦逊的例子,运行同一应用程序的ApiBack OfficeWeb App实例,在Lucid术语中,这些是服务,通过数据共享功能

Lucid multitenancy

贡献

错误与问题报告

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

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

⏱ 常规情况下,每周大约检查三次PR和问题,因此您的提交很可能很快就会被处理。

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

支持问题

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

  • 讨论区是大多数对话发生的地方
  • 如果想要聊天,请在我们的官方#support频道中的Slack工作区联系我们
  • 如果您倾向于在StackOverflow上提问,可以使用#lucidarch来标记它们

核心开发讨论

您可以在Lucid讨论区中提议新的功能或对现有Lucid Architecture行为的改进。如果您提议一个新的功能,请愿意至少实现一些完成该功能所需的代码,或者在此期间参与积极的想法交流。

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

哪个分支?如何贡献

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

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

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

开发环境设置

以下是设置Lucid开发环境的步骤

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

  • 克隆分叉的存储库[your username]/lucid,这将创建一个lucid文件夹在~/dev/lucid
  • 创建一个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

  • 参与者应宽容不同观点。
  • 参与者必须确保他们的语言和行为不包含人身攻击和贬低性言论。
  • 在解读他人的言语和行为时,参与者应始终假设对方是善意的。
  • 任何可合理视为骚扰的行为将不被容忍。