jhormantasayco/laravel-lucid

可扩展软件架构。

0.3 2024-09-28 20:23 UTC

This package is auto-updated.

Last update: 2024-09-28 20:25:51 UTC


README

Documentation Slack Chat Build Status Latest Stable Version License

目录

关于Lucid

Lucid是一种用于构建可扩展Laravel项目的软件架构。它将核心的Command Bus领域驱动设计结合在一起,在此基础上构建了一系列目录和类来组织业务逻辑。它还从SOA(面向服务架构)中吸取了将功能封装在服务中的概念,并在此基础上进一步丰富了服务不仅仅是类这一概念。

使用Lucid来

  • 轻松写出干净的代码
  • 保护您的代码免受时间推移的退化
  • 在极短的时间内审查代码
  • 在您的应用程序中融入经过验证的实践和模式
  • 在代码和代码库之间导航,而不会感到陌生

概念

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

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

如果您喜欢视频,请观看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中)中,将只包含服务功能类的唯一一行,从而实现最薄的控制器形式。

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 问题跟踪器不是为了提供帮助或支持。相反,请使用以下途径之一

  • 讨论区 是大多数对话发生的地方
  • 想要聊天,请在我们的官方 Slack 工作空间#support 频道联系我们
  • 如果您喜欢在 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 目录中...

  • 克隆分叉的仓库 [您的用户名]/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》)

  • 参与者将容忍不同的观点。
  • 参与者必须确保他们的语言和行为不包含个人攻击和诋毁性的个人评论。
  • 在解读他人的言行时,参与者应始终假设对方有良好的意图。
  • 任何合理地被认为是骚扰的行为都是不可容忍的。