solid-check

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Check SOLID / IoC Rules

检查 SOLID / IoC 规则

What To Check

检查内容

$ARGUMENTS
— a class, namespace, file, or folder, in PHP (
App\AI\Tools\UpdateArticleTool
), JS/TS (
resources/script/stores/product-store.ts
,
useMessageScroll
), or Dart (
lib/features/order/
,
OrderRepository
).
If
$ARGUMENTS
is empty, check the files in the current git changes (
git status
).
If
$ARGUMENTS
is unclear (no matching file found, or a namespace with more than one meaning), take every candidate that matches into scope, and name in the report which ones you took.
$ARGUMENTS
— PHP (
App\AI\Tools\UpdateArticleTool
)、JS/TS (
resources/script/stores/product-store.ts
,
useMessageScroll
) 或 Dart (
lib/features/order/
,
OrderRepository
) 中的一个类、命名空间、文件或文件夹。
如果
$ARGUMENTS
为空,则检查当前 git 变更中的文件 (
git status
)。
如果
$ARGUMENTS
不明确(未找到匹配文件,或某个命名空间对应多个含义),则将所有匹配候选项纳入范围,并在报告中说明具体包含了哪些候选项。

Run Flow

执行流程

1. Gather the scope

1. 确定范围

  • Use Glob and Read to list and open every file in scope (
    .php
    /
    .ts
    /
    .tsx
    /
    .js
    /
    .vue
    /
    .dart
    ), and Grep to find its callers, inject points, child classes, and import sites.
  • Read each file in full.
  • Name the form: PHP class / Vue SFC / composable / store / plain TS module / Flutter widget / Bloc / Notifier / Dart repository.
  • Read the yardstick for that form: PHP →
    PHP.md
    , JS/TS →
    VUE-TS.md
    , Dart/Flutter →
    FLUTTER.md
    . A mixed scope reads each one that applies.
  • 使用 Glob 和 Read 列出并打开范围内的每个文件(
    .php
    /
    .ts
    /
    .tsx
    /
    .js
    /
    .vue
    /
    .dart
    ),并使用 Grep 查找其调用方、注入点、子类和导入位置。
  • 完整读取每个文件。
  • 明确其形态:PHP class / Vue SFC / composable / store / 普通 TS module / Flutter widget / Bloc / Notifier / Dart repository。
  • 阅读该形态对应的评审准则:PHP →
    PHP.md
    ,JS/TS →
    VUE-TS.md
    ,Dart/Flutter →
    FLUTTER.md
    。对于混合范围,读取所有适用的准则。

2. Run the six checks

2. 执行六项检查

Five SOLID principles plus IoC. Each carries language-specific check points in the yardstick you just read, where the language has them — apply both. Judge on how easy the design is to maintain, not on whether the code runs.
Before judging, take the exemptions. Two shapes earn
exempt
rather than a break:
  • By size — a small Value Object, a plain DTO, or a single-use Action class is judged on whether it stays small and clear.
  • By framework — a shape the framework dictates (Filament Resource, Nova Resource, Livewire Component, the three-part Vue SFC, the three-piece Pinia store, the
    StatefulWidget
    +
    State
    pair, a Bloc's event/state classes) is correct as it stands.
An exemption is still a verdict: mark the check
exempt
and name the shape that earned it.
五项 SOLID 原则加上 IoC。每项原则在刚读取的评审准则中都有对应语言的检查点(如果该语言适用);两者都要执行。判断依据是设计是否易于维护,而不是代码能否运行。
判断前先处理豁免情形。以下两种形态应标记为
exempt
,而不是
break
:
  • 按规模 — 对于小型 Value Object、普通 DTO 或一次性 Action class,评判标准是它是否保持小巧且清晰。
  • 按框架 — 对于框架规定的形态(Filament Resource、Nova Resource、Livewire Component、三部分式 Vue SFC、三段式 Pinia store、
    StatefulWidget
    +
    State
    组合、Bloc 的 event/state class),其现有形态即视为正确。
豁免仍然是一项结论:将检查标记为
exempt
,并说明获得豁免的具体形态。

Single Responsibility Principle (SRP)

单一职责原则 (SRP)

  • Does the class / module / composable have only one reason to change?
  • Does it handle HTTP/validation/business logic/data access/formatting/UI state all at once?
  • Are the public methods or exports about one idea, or do they mix unrelated jobs?
  • Do the file length and the method count smell of too many jobs? (Thresholds live in the yardstick.)
  • class / module / composable 是否只有一个变更原因?
  • 它是否同时处理 HTTP、validation、business logic、data access、formatting 和 UI state?
  • public method 或 export 是否围绕一个核心概念,还是混合了不相关的工作?
  • 文件长度和 method 数量是否表明职责过多?(具体阈值见评审准则。)

Open-Closed Principle (OCP)

开闭原则 (OCP)

  • When a new need comes, must you change the inside of an old class/module?
  • Do you use
    if/switch
    to branch on a type/string, instead of polymorphism or a strategy map?
  • Are the extension points shown, or does a caller have to reach inside to extend?
  • 当出现新需求时,是否必须修改旧 class / module 的内部实现?
  • 是否使用
    if/switch
    根据 type / string 分支,而不是使用 polymorphism 或 strategy map?
  • extension point 是否清晰可见,还是调用方必须深入其内部才能扩展?

Liskov Substitution Principle (LSP)

里氏替换原则 (LSP)

  • Does a child class / child type break the parent contract (throw an exception the parent did not declare, return null, tighten the pre-conditions)?
  • Do the type declarations of an overridden method match the parent class/interface?
  • Is there an
    instanceof
    /
    typeof
    / discriminator string and then branch handling for a given child type (an LSP-break smell)?
  • 子 class / 子 type 是否违反父类契约(抛出父类未声明的异常、返回 null、收紧前置条件)?
  • 被覆写 method 的类型声明是否与父 class / interface 匹配?
  • 是否先使用
    instanceof
    /
    typeof
    / discriminator string,再针对特定子 type 进行分支处理(这是违反 LSP 的信号)?

Interface Segregation Principle (ISP)

接口隔离原则 (ISP)

  • Is a type forced to implement methods it does not use (empty method, a throw, a
    undefined
    return)?
  • Should a "fat interface" or "fat props" be split into many small ones?
  • Does the client / child component depend only on the methods or prop it needs?
  • 是否强制 type 实现其并不使用的方法(空 method、抛异常或返回
    undefined
    )?
  • 臃肿的 interface 或臃肿的 props 是否应拆分为多个小型接口?
  • client / 子 component 是否仅依赖其实际需要的方法或 prop?

Dependency Inversion Principle (DIP)

依赖倒置原则 (DIP)

  • Does a high-level module
    new
    a low-level concrete class, or
    import
    a concrete build directly?
  • Is the type in the constructor inject or function parameter an abstract one or a concrete one?
  • Is the outside I/O (HTTP, file, DB, browser API) hidden behind an abstract layer so a test can swap it out?
  • 高层 module 是否通过
    new
    创建低层 concrete class,或直接 import 具体的构建实现?
  • 构造函数注入或函数参数使用的是抽象类型还是具体类型?
  • 外部 I/O(HTTP、文件、DB、browser API)是否隐藏在抽象层之后,以便测试可以替换它?

IoC / container use

IoC / 容器使用

Wholly language-specific — judge it from the yardstick for the form.
Done when: every file in scope carries an explicit verdict on all six checks —
pass
,
break
, or
exempt
. A check you did not mention is a check you did not run.
完全取决于具体语言,应根据该形态对应的评审准则进行判断。
完成标准:范围内的每个文件都必须对全部六项检查给出明确结论——
pass
、
break
或
exempt
。未提及某项检查,就表示没有执行该项检查。

3. Make a report

3. 编写报告

  1. Scope — the files you checked.
  2. Verdict table — one row per check (SRP, OCP, LSP, ISP, DIP, IoC), each
    pass
    /
    break
    /
    exempt
    .
  3. One section per check that broke — each break point as
    file_path:line_number
    + a short note, and the risk it carries (hard to test? coupling? painful to extend?).
  4. Overall judgment — pass / room to improve / serious, needs refactor.
  5. Refactor advice — each break point gets one clear, doable refactor direction, described in prose.
  1. 范围 — 检查过的文件。
  2. 结论表 — 每项检查一行(SRP、OCP、LSP、ISP、DIP、IoC),对应填写
    pass
    /
    break
    /
    exempt
    。
  3. 每个存在 break 的检查单独成节 — 每个 break 点使用
    file_path:line_number
    格式定位,附简短说明及其带来的风险(难以测试?存在耦合?难以扩展?)。
  4. 总体评价 — pass / 有改进空间 / 严重,需要重构。
  5. 重构建议 — 每个 break 点都应给出一个明确、可执行的重构方向,并以文字说明。

4. Close the check

4. 结束检查

This skill ends at the report — changing code belongs to the
run
or
fix
skill. When everything passes, say the good points in short and stop there.
When there are breaks, who called for the check decides where the report goes.
  • The user asked for it → call the
    grilling
    skill to put the refactor directions to them one at a time and settle which way to go.
  • You or another skill asked for it → the report is yours to reason from. Take it back to the work that called for the check and act on it there.
此 skill 在报告阶段结束;修改代码属于
run
或
fix
skill 的职责。如果所有检查均通过,简要说明优点后即可结束。
如果存在 break,由谁发起检查决定报告的处理方式。
  • 用户主动要求检查 → 调用
    grilling
    skill,逐项向用户说明重构方向,并确定具体采用哪种方案。
  • 你或其他 skill 发起检查 → 报告仅供你据此分析。应返回发起检查的工作流程,并在该流程中采取相应行动。