laranex / lucid
可扩展软件架构。https://lucidarch.dev/ 的维护版本
Requires
- ext-dom: *
- mockery/mockery: *
- symfony/console: *
- symfony/filesystem: *
- symfony/finder: *
- symfony/process: *
README
这是一个非官方的、由来自https://onenex.co 的开发者维护的https://lucidarch.dev 的版本。
我们完全赞赏https://lucidarch.dev,我们仅维护这个版本是为了改善社区。
维护这个存储库的主要原因如下。
- Laravel 在 10.x 版本发布后改变了任务派遣行为 - https://github.com/laravel/framework/commit/5f61fd1af0fa0b37a8888637578459eae21faeb
- Lucid 在该版本发布后停止工作,我已经创建了一个 PR 并通过 Slack 尝试联系原始的开发者 - lucidarch/lucid#51
- 由于我想在 lucid team 官方支持之前,让 lucid 在 Laravel 10.x 上工作,所以我创建了这个维护版本。
- 我非常欣赏和热爱 lucidarch 的工作。
安装
composer require laranex/lucid
请参阅官方 lucid 文档了解其他事项。
- 网站: https://lucidarch.dev
- 文档: https://docs.lucidarch.dev
- 社交: 我们分享网络上的更新和有趣的内容
- Twitter: @lucid_arch & #lucidarch
- Reddit: /r/lucidarch
目录
关于 Lucid
Lucid 是一个用于构建可扩展 Laravel 项目的软件架构。它将 命令总线 和 领域驱动设计 作为核心,在此基础上构建了一系列目录和类来组织业务逻辑。它还借鉴了 SOA (面向服务架构) 中封装功能在服务中的概念,并在此基础上增加了服务不仅仅是类的概念。
使用 Lucid
- 轻松编写干净的代码
- 保护您的代码免受时间侵蚀
- 在极短的时间内审查代码
- 在您的应用程序中结合经过验证的实践和模式
- 导航代码,在不同代码库之间移动而不会感到迷茫
概念
这种架构结合了最佳实践、设计模式和经过验证的方法。
- 命令总线:用于派遣工作单元。在 Lucid 术语中,这些单元将是
功能
、作业
或操作
。 - 领域驱动设计:根据所属主题对工作单元进行分类,以组织它们。
- 面向服务架构:封装和管理具有相同目的的功能及其所需资源(路由、控制器、视图、数据库迁移等)。
如果您喜欢视频,请观看Laracon EU 2016的公告。
目录
位置
在典型的MVC应用中,Lucid将是应用程序入口点和执行工作单元之间的纽带,确保代码不会向极端方向发展。
栈
简要概述...
框架
提供“核心”来处理请求/响应生命周期、依赖注入和其他核心功能等繁琐工作。
基础
扩展框架以提供适用于应用程序的高级抽象,这些抽象可以在整个堆栈中共享,而不是特定于场景。
以下是一些可能包含在基础中的示例:
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、Back Office和Web App实例的简单示例,在Lucid术语中,这些是通过对数据和领域共享功能性的服务。
贡献
错误 & 问题报告
为了鼓励积极协作,Lucid强烈鼓励通过拉取请求进行贡献。"错误报告"可以在问题中搜索或创建,或者以包含失败测试或复现错误的步骤的拉取请求的形式发送。
如果你提交错误报告,你的问题应包含标题和问题清晰描述。你还应包括尽可能多的相关信息和示例代码,以展示问题。错误报告的目标是使你自己和其他人都能轻松地复现错误并开发修复方案。
⏱ 拉取请求和问题通常每周检查大约三次,所以你的很可能很快就会被选中。
Lucid Architecture的源代码在GitHub上,地址为lucidarch/lucid。
支持问题
Lucid Architecture的GitHub问题跟踪器不是为了提供帮助或支持。相反,使用以下渠道之一
- 讨论是大多数对话发生的地方
- 如果您想聊天,请在我们的官方Slack工作区中的
#support
频道联系我们 - 如果您更喜欢在StackOverflow上发布问题,您可以使用#lucidarch来标记它们
核心开发讨论
您可以在Lucid Discussions中提出新功能或现有Lucid Architecture行为的改进建议。如果您提出一个新的功能,请愿意至少实现完成该功能所需的部分代码,或者在此期间积极合作。
有关错误、新功能和现有功能的实现的非正式讨论发生在Lucid Slack工作区的#internals
频道中。Abed Halawi,Lucid的维护者,通常在每周工作日的早上8点到下午5点EEST(东欧夏令时)在该频道中,其他时间偶尔出现。
哪个分支?如何贡献
main
分支包含最新的实时版本,是发布的那一个。
- 分叉此存储库
- 将分叉的存储库克隆到您将编辑代码的地方
- 为您的编辑创建一个分支(例如
feature/queueable-units
、fix/issue-31
) - 使用有意义的简短消息提交您的更改及其测试(如果适用)
- 推送您的分支
git push origin feature/queueable-units
- 向
main
分支打开一个PR,这将运行您的编辑测试
⏱ 拉取请求和问题通常每周检查大约三次。
开发环境设置
以下是设置Lucid开发的步骤
假设我们处于
~/dev
目录...
- 克隆分叉的存储库
[your username]/lucid
,这将创建一个位于~/dev/lucid
的lucid
文件夹 - 在 Laravel 项目中测试您的实现,创建一个 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 架构遵循 PSR-2 编码规范和 PSR-4 自动加载规范。
PHPDoc
以下是一个有效的 Lucid 架构文档块的示例。注意,@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 架构的行为准则来源于 Laravel 的行为准则。任何违反行为准则的行为都可以报告给 Abed Halawi(邮箱:halawi.abed@gmail.com)
- 参与者将对不同观点持宽容态度。
- 参与者必须确保他们的语言和行为不受个人攻击和贬低性言论的影响。
- 在解释他人的言行时,参与者应始终假设其具有良好意图。
- 任何可合理考虑为骚扰的行为将不会受到容忍。