appnap / lucid
可扩展软件的架构。
Requires
- ext-dom: *
- mockery/mockery: *
- symfony/console: *
- symfony/filesystem: *
- symfony/finder: *
- symfony/process: *
README
- 网站: https://lucidarch.dev
- 文档: https://docs.lucidarch.dev
- 社交:我们分享更新和来自网络的有趣内容
- Twitter: @lucid_arch & #lucidarch
- Reddit: /r/lucidarch
目录
关于 Lucid
Lucid 是一个用于构建可扩展 Laravel 项目的软件架构。它将 命令总线 和 领域驱动设计 作为核心,在此基础上构建了一系列目录和类来组织业务逻辑。它还从 SOA(面向服务架构) 中汲取了将功能封装在服务中的概念,并在此基础上扩展了服务不仅仅是类的概念。
使用 Lucid 来
- 轻松编写干净的代码
- 保护您的代码免受时间的影响而恶化
- 在极短的时间内审查代码
- 将经过验证的实践和模式融入您的应用程序
- 导航代码,在不同代码库之间移动而不会感到陌生
概念
这种架构结合了最佳实践、设计模式和经过验证的方法。
- 命令总线:用于分配工作单元。在 Lucid 术语中,这些单元将是一个
功能、作业或操作。 - 领域驱动设计:通过根据它们所属的主题对工作单元进行分类来组织工作单元。
- 面向服务架构:将具有相同目的的功能及其所需资源(路由、控制器、视图、数据库迁移等)进行封装和管理。
如果您更喜欢视频,请观看 2016 年 Laracon EU 的公告
目录
位置
在一个典型的 MVC 应用程序中,Lucid 将是应用程序入口点和执行工作的工作单元之间的纽带,确保代码不会走向歧途
堆栈
简而言之...
框架
提供“内核”来完成请求/响应生命周期、依赖注入和其他核心功能等繁琐工作的重担。
基础
扩展框架以提供适用于应用程序的高级抽象,这些抽象可以在整个堆栈中共享,而不是特定于某个案例。
以下是一些可能包含在基础中的示例
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,但仍然位于)。
重用与替换
通过将应用程序分解成小的代码构建块——即单元——我们立即打开了应用程序中高度代码共享的大门,与数据域一起以及最小摩擦和技术债务的可替换性。
边界
通过设置边界,你迈出了保护应用程序代码免于变得难以承受地庞大的一步,并使新开发人员更容易上线。最重要的是,你已经将技术债务降至最低,这样你就不必用错误和失眠来支付;代码不是运行在良好的意图或愿望上。
多租户
当我们的应用程序扩展时,我们通常会有一群在不同位置运行的同一应用程序的实例,在某个时候,我们会在某些区域激活代码库的某些部分,关闭其他部分。
这是一个谦逊的例子,运行同一应用程序的Api、Back Office和Web App实例,在Lucid术语中,这些是服务,通过数据和域共享功能
贡献
错误与问题报告
为了鼓励积极的协作,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-units、fix/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)
- 参与者应宽容不同观点。
- 参与者必须确保他们的语言和行为不包含人身攻击和贬低性言论。
- 在解读他人的言语和行为时,参与者应始终假设对方是善意的。
- 任何可合理视为骚扰的行为将不被容忍。



