• صفحه اصلی
  • درباره من
  • مهارت‌های ایجنت
  • پروژه‌ها
  • بلاگ
  • مشاوره
  • تماس با من
مشاورهرزومه
مهارت‌های ایجنت‌های برنامه‌نویسی/معماری/بازبینی اصول SOLID در React

بازبینی اصول SOLID در React

کد React/TypeScript را برای violationهای عملی SOLID بررسی کن و با کوچک‌ترین refactor کافی، responsibility، dependency و component contractها را اصلاح کن.

reacttypescriptsolidclean-codearchitecturerefactoring

راهنمای نصب Skill

فایل SKILL.md را دانلود کنید و در مسیر مخصوص ایجنت موردنظرتان قرار دهید. پیشنهاد می‌کنیم پیش از فعال‌سازی، محتوای کامل فایل و سطح دسترسی آن را بررسی کنید.

Codex

~/.codex/skills/react-solid-principles-review/SKILL.md

Claude Code

.claude/skills/react-solid-principles-review/SKILL.md

Cursor

.cursor/skills/react-solid-principles-review/SKILL.md

GitHub Copilot

.github/skills/react-solid-principles-review/SKILL.md
</>مشاهده محتوای خام SKILL.mdفقط دستورالعمل‌هایی را ببینید که ایجنت برنامه‌نویسی دریافت می‌کند؛ بدون عنوان، تگ و متادیتای کاتالوگ.
فایل منبع: react-solid-principles-review/SKILL.md
---
name: "react-solid-principles-review"
description: "کد React/TypeScript را برای violationهای عملی SOLID بررسی کن و با کوچک‌ترین refactor کافی، responsibility، dependency و component contractها را اصلاح کن."
---

# بازبینی اصول SOLID در React

این Skill را زمانی فعال کن که کاربر می‌خواهد یک Feature، Component، Custom Hook یا Service در React/TypeScript از نظر responsibility، coupling، dependency direction و قابلیت تغییر بازبینی یا refactor شود.

هدف اجرای SOLID به‌عنوان چک‌لیست مکانیکی نیست. فقط violationهایی را اصلاح کن که شواهد واقعی از هزینه نگهداری، coupling، تست‌پذیری ضعیف یا تغییرات پرریسک دارند.

## Trigger / Usage Context

از این Skill استفاده کن وقتی درخواست شامل یکی از این موارد است:

- review یا refactor یک Component بزرگ؛
- Custom Hook چندمسئولیتی؛
- Service یا API layer وابسته به implementation خاص؛
- boolean prop explosion یا interface بیش از حد بزرگ؛
- dependencyهای معکوس یا circular؛
- اضافه‌کردن قابلیت جدید بدون دست‌کاری چند branch شرطی؛
- ساده‌کردن کدی که با abstractionهای زودهنگام پیچیده شده است.

برای سؤال صرفاً آموزشی درباره تعریف SOLID، این Skill را به‌عنوان workflow refactor اجرا نکن مگر کاربر یک codebase یا snippet برای بررسی داده باشد.

## Goals

- مسئولیت‌هایی را پیدا کن که دلیل تغییر متفاوت دارند.
- coupling مؤثر بر تغییرپذیری یا تست را کاهش بده.
- abstraction را فقط در مرزهایی ایجاد کن که واقعاً چند implementation یا policy مستقل دارند.
- Component API را کوچک، ترکیب‌پذیر و قابل‌فهم نگه دار.
- رفتار فعلی را تا زمانی که کاربر تغییر behavior نخواسته حفظ کن.
- ساده‌ترین refactor کافی را انتخاب کن.

## Architectural Context

قبل از پیشنهاد SOLID، ساختار واقعی پروژه را inspect کن:

1. مالکیت Featureها و module boundaryها؛
2. محل state و side effectها؛
3. API client و dependencyهای خارجی؛
4. Component contractها و مصرف‌کننده‌های آن‌ها؛
5. testها، typeها و public exportها؛
6. conventionهای فعلی repo.

اگر پروژه یک الگوی سالم دارد، SOLID را با همان الگو تطبیق بده. معماری جدید را صرفاً برای نمایش pattern وارد نکن.

## Workflow

### 1. Scope را مشخص کن

فایل‌ها و dependencyهای مستقیم محدوده را فهرست کن.

برای هر فایل بنویس:

```text
File:
Primary responsibility:
Reasons to change:
Dependencies:
Consumers:
```

اگر یک فایل چند دلیل تغییر مستقل دارد، آن را candidate برای SRP در نظر بگیر؛ نه اینکه صرفاً به‌خاطر تعداد خطوط بزرگ باشد.

### 2. Findings را با Evidence ثبت کن

هر finding باید این قالب را داشته باشد:

```text
Principle:
Evidence:
Maintenance cost:
Smallest useful change:
Risk:
```

فقط نام اصل را گزارش نکن.

### 3. SRP را روی دلیل تغییر اعمال کن

نمونه smell:

```tsx
function CheckoutPage() {
  // fetch pricing
  // validate coupon
  // calculate totals
  // persist cart
  // render layout
}
```

قبل از split کردن، مشخص کن کدام responsibility واقعاً مستقل است.

Refactor احتمالی:

```text
CheckoutPage
├── useCheckoutPricing
├── checkout domain calculations
└── CheckoutView
```

اگر استخراج function ساده کافی است، layer جدید ایجاد نکن.

### 4. OCP را با Composition ترجیح بده

اگر افزودن variant جدید دائماً نیازمند اضافه‌کردن شرط به Component مرکزی است:

```tsx
if (type === "card") ...
if (type === "paypal") ...
if (type === "crypto") ...
```

بررسی کن آیا composition یا strategy ساده تغییر را محلی می‌کند:

```ts
const paymentRenderers = {
  card: CardPayment,
  paypal: PayPalPayment,
}
```

اما registry را فقط وقتی بساز که variantها واقعاً extension point هستند. برای دو branch ثابت که بعید است رشد کنند، `if` ممکن است واضح‌تر باشد.

### 5. LSP را روی Component Contract بررسی کن

در React، LSP را بیشتر در contract و substitutability بررسی کن تا inheritance کلاسیک.

smell:

```tsx
<Button variant="link" disabled />
```

اگر variant خاص بعضی props را عملاً نادیده می‌گیرد یا semantics متفاوتی دارد، contract احتمالاً بیش از حد عمومی است.

راه‌حل ممکن است union type یا componentهای مشخص‌تر باشد:

```ts
type ButtonProps =
  | { kind: "button"; disabled?: boolean }
  | { kind: "link"; href: string }
```

هدف جلوگیری از state نامعتبر است، نه پیچیده‌کردن typeها.

### 6. ISP را روی Props و Service Interface اعمال کن

اگر Component یا hook یک object بسیار بزرگ فقط برای چند field دریافت می‌کند:

```ts
function UserAvatar({ user }: { user: User }) {
  return <img src={user.avatarUrl} alt={user.name} />
}
```

بررسی کن آیا contract کوچک‌تر بهتر است:

```ts
type UserAvatarProps = {
  name: string
  avatarUrl: string
}
```

اما اگر `User` همان contract دامنه‌ای پایدار و مناسب است، split مکانیکی انجام نده.

### 7. DIP را فقط در Boundaryهای واقعی اعمال کن

smell:

```ts
import axios from "axios"

export async function submitOrder(input: OrderInput) {
  return axios.post("/orders", input)
}
```

اگر use case باید مستقل از transport تست یا reuse شود، port کوچک تعریف کن:

```ts
export interface OrderRepository {
  create(input: OrderInput): Promise<Order>
}
```

و adapter infrastructure:

```ts
export class HttpOrderRepository implements OrderRepository {
  async create(input: OrderInput) {
    return postOrder(input)
  }
}
```

اما برای یک fetch ساده داخل Feature کوچک، interface و class فقط برای رعایت DIP نساز.

### 8. تغییر را مرحله‌ای اعمال کن

ترتیب ترجیحی:

```text
1. Rename / extract pure logic
2. Reduce contract surface
3. Move responsibility to correct owner
4. Introduce a boundary only when justified
5. Update imports
6. Run available checks
```

### 9. Validation

در حد امکانات پروژه اجرا یا پیشنهاد کن:

```text
typecheck
lint
unit tests
integration tests
build
```

اگر امکان اجرا نداری، دقیقاً بگو چه چیزی verify نشده است.

## Rules / Constraints

- SOLID را معیار افزایش تعداد فایل‌ها ندان.
- class یا interface فقط برای نمایش pattern نساز.
- behavior را بدون درخواست کاربر تغییر نده.
- public API را بدون بررسی مصرف‌کننده‌ها تغییر نده.
- abstraction مشترک را قبل از وجود حداقل دو نیاز واقعی تحمیل نکن.
- dependency injection container برای مسئله‌ای که با function parameter حل می‌شود اضافه نکن.
- React composition را به inheritance ترجیح بده.
- domain logic را تا حد ممکن از render و transport جدا نگه دار.
- code smell را با evidence گزارش کن، نه با سلیقه شخصی.

## Anti-patterns

### SRP = یک function برای هر پنج خط

خیر. SRP درباره reason to change است، نه اندازه.

### OCP = همه چیز plugin system باشد

خیر. extension point فقط وقتی ارزش دارد که extension واقعاً بخشی از نیاز محصول باشد.

### DIP = برای هر API یک interface

خیر. boundary زمانی لازم است که dependency direction، تست یا چند implementation ارزش واقعی ایجاد کند.

### ISP = خردکردن تمام typeها

خیر. contract کوچک‌تر باید coupling مصرف‌کننده را کاهش دهد.

### SOLID = پیچیده‌تر شدن کد

اگر refactor برای فهمیدن به diagram بیشتری نیاز دارد ولی هزینه تغییر را کم نکرده، احتمالاً نتیجه بدتر شده است.

## Examples / Patterns

### قبل

```tsx
export function ProfilePanel({ user, api, analytics, theme }: Props) {
  // fetch
  // transform
  // track
  // permissions
  // rendering
}
```

### بعد از review

ممکن است نتیجه فقط این باشد:

```text
- داده از query hook بیاید.
- transform pure به function مستقل منتقل شود.
- analytics در event handler نزدیک interaction بماند.
- permission helper موجود reuse شود.
- ProfilePanel فقط composition و rendering را نگه دارد.
```

نیازی نیست حتماً repository، service و use-case class اضافه شود.

## Output Expectations

خروجی نهایی را به این ترتیب ارائه کن:

1. **Scope reviewed**
2. **Prioritized findings**
3. **SOLID principle + evidence**
4. **Minimal refactor plan**
5. **Files changed**
6. **Behavior preserved / changed**
7. **Validation performed**
8. **Remaining risks**

یافته‌ها را با شدت تقریبی `high / medium / low` اولویت‌بندی کن.

## Safety / Limits

- secret، credential یا token را در output کپی نکن.
- dependency خارجی را بدون نیاز واقعی اضافه نکن.
- migration سراسری repo را از یک finding محلی نتیجه نگیر.
- اگر تغییر public contract یا data model ریسک بالایی دارد، آن را جدا گزارش کن.
- اگر تست کافی وجود ندارد، refactor را کوچک و reversible نگه دار.

این Skill را زمانی فعال کن که کاربر می‌خواهد یک Feature، Component، Custom Hook یا Service در React/TypeScript از نظر responsibility، coupling، dependency direction و قابلیت تغییر بازبینی یا refactor شود.

هدف اجرای SOLID به‌عنوان چک‌لیست مکانیکی نیست. فقط violationهایی را اصلاح کن که شواهد واقعی از هزینه نگهداری، coupling، تست‌پذیری ضعیف یا تغییرات پرریسک دارند.

Trigger / Usage Context

از این Skill استفاده کن وقتی درخواست شامل یکی از این موارد است:

  • review یا refactor یک Component بزرگ؛
  • Custom Hook چندمسئولیتی؛
  • Service یا API layer وابسته به implementation خاص؛
  • boolean prop explosion یا interface بیش از حد بزرگ؛
  • dependencyهای معکوس یا circular؛
  • اضافه‌کردن قابلیت جدید بدون دست‌کاری چند branch شرطی؛
  • ساده‌کردن کدی که با abstractionهای زودهنگام پیچیده شده است.

برای سؤال صرفاً آموزشی درباره تعریف SOLID، این Skill را به‌عنوان workflow refactor اجرا نکن مگر کاربر یک codebase یا snippet برای بررسی داده باشد.

Goals

  • مسئولیت‌هایی را پیدا کن که دلیل تغییر متفاوت دارند.
  • coupling مؤثر بر تغییرپذیری یا تست را کاهش بده.
  • abstraction را فقط در مرزهایی ایجاد کن که واقعاً چند implementation یا policy مستقل دارند.
  • Component API را کوچک، ترکیب‌پذیر و قابل‌فهم نگه دار.
  • رفتار فعلی را تا زمانی که کاربر تغییر behavior نخواسته حفظ کن.
  • ساده‌ترین refactor کافی را انتخاب کن.

Architectural Context

قبل از پیشنهاد SOLID، ساختار واقعی پروژه را inspect کن:

  1. مالکیت Featureها و module boundaryها؛
  2. محل state و side effectها؛
  3. API client و dependencyهای خارجی؛
  4. Component contractها و مصرف‌کننده‌های آن‌ها؛
  5. testها، typeها و public exportها؛
  6. conventionهای فعلی repo.

اگر پروژه یک الگوی سالم دارد، SOLID را با همان الگو تطبیق بده. معماری جدید را صرفاً برای نمایش pattern وارد نکن.

Workflow

1. Scope را مشخص کن

فایل‌ها و dependencyهای مستقیم محدوده را فهرست کن.

برای هر فایل بنویس:

File:
Primary responsibility:
Reasons to change:
Dependencies:
Consumers:

اگر یک فایل چند دلیل تغییر مستقل دارد، آن را candidate برای SRP در نظر بگیر؛ نه اینکه صرفاً به‌خاطر تعداد خطوط بزرگ باشد.

2. Findings را با Evidence ثبت کن

هر finding باید این قالب را داشته باشد:

Principle:
Evidence:
Maintenance cost:
Smallest useful change:
Risk:

فقط نام اصل را گزارش نکن.

3. SRP را روی دلیل تغییر اعمال کن

نمونه smell:

function CheckoutPage() {
  // fetch pricing
  // validate coupon
  // calculate totals
  // persist cart
  // render layout
}

قبل از split کردن، مشخص کن کدام responsibility واقعاً مستقل است.

Refactor احتمالی:

CheckoutPage
├── useCheckoutPricing
├── checkout domain calculations
└── CheckoutView

اگر استخراج function ساده کافی است، layer جدید ایجاد نکن.

4. OCP را با Composition ترجیح بده

اگر افزودن variant جدید دائماً نیازمند اضافه‌کردن شرط به Component مرکزی است:

if (type === "card") ...
if (type === "paypal") ...
if (type === "crypto") ...

بررسی کن آیا composition یا strategy ساده تغییر را محلی می‌کند:

const paymentRenderers = {
  card: CardPayment,
  paypal: PayPalPayment,
}

اما registry را فقط وقتی بساز که variantها واقعاً extension point هستند. برای دو branch ثابت که بعید است رشد کنند، if ممکن است واضح‌تر باشد.

5. LSP را روی Component Contract بررسی کن

در React، LSP را بیشتر در contract و substitutability بررسی کن تا inheritance کلاسیک.

smell:

<Button variant="link" disabled />

اگر variant خاص بعضی props را عملاً نادیده می‌گیرد یا semantics متفاوتی دارد، contract احتمالاً بیش از حد عمومی است.

راه‌حل ممکن است union type یا componentهای مشخص‌تر باشد:

type ButtonProps =
  | { kind: "button"; disabled?: boolean }
  | { kind: "link"; href: string }

هدف جلوگیری از state نامعتبر است، نه پیچیده‌کردن typeها.

6. ISP را روی Props و Service Interface اعمال کن

اگر Component یا hook یک object بسیار بزرگ فقط برای چند field دریافت می‌کند:

function UserAvatar({ user }: { user: User }) {
  return <img src={user.avatarUrl} alt={user.name} />
}

بررسی کن آیا contract کوچک‌تر بهتر است:

type UserAvatarProps = {
  name: string
  avatarUrl: string
}

اما اگر User همان contract دامنه‌ای پایدار و مناسب است، split مکانیکی انجام نده.

7. DIP را فقط در Boundaryهای واقعی اعمال کن

smell:

import axios from "axios"

export async function submitOrder(input: OrderInput) {
  return axios.post("/orders", input)
}

اگر use case باید مستقل از transport تست یا reuse شود، port کوچک تعریف کن:

export interface OrderRepository {
  create(input: OrderInput): Promise<Order>
}

و adapter infrastructure:

export class HttpOrderRepository implements OrderRepository {
  async create(input: OrderInput) {
    return postOrder(input)
  }
}

اما برای یک fetch ساده داخل Feature کوچک، interface و class فقط برای رعایت DIP نساز.

8. تغییر را مرحله‌ای اعمال کن

ترتیب ترجیحی:

1. Rename / extract pure logic
2. Reduce contract surface
3. Move responsibility to correct owner
4. Introduce a boundary only when justified
5. Update imports
6. Run available checks

9. Validation

در حد امکانات پروژه اجرا یا پیشنهاد کن:

typecheck
lint
unit tests
integration tests
build

اگر امکان اجرا نداری، دقیقاً بگو چه چیزی verify نشده است.

Rules / Constraints

  • SOLID را معیار افزایش تعداد فایل‌ها ندان.
  • class یا interface فقط برای نمایش pattern نساز.
  • behavior را بدون درخواست کاربر تغییر نده.
  • public API را بدون بررسی مصرف‌کننده‌ها تغییر نده.
  • abstraction مشترک را قبل از وجود حداقل دو نیاز واقعی تحمیل نکن.
  • dependency injection container برای مسئله‌ای که با function parameter حل می‌شود اضافه نکن.
  • React composition را به inheritance ترجیح بده.
  • domain logic را تا حد ممکن از render و transport جدا نگه دار.
  • code smell را با evidence گزارش کن، نه با سلیقه شخصی.

Anti-patterns

SRP = یک function برای هر پنج خط

خیر. SRP درباره reason to change است، نه اندازه.

OCP = همه چیز plugin system باشد

خیر. extension point فقط وقتی ارزش دارد که extension واقعاً بخشی از نیاز محصول باشد.

DIP = برای هر API یک interface

خیر. boundary زمانی لازم است که dependency direction، تست یا چند implementation ارزش واقعی ایجاد کند.

ISP = خردکردن تمام typeها

خیر. contract کوچک‌تر باید coupling مصرف‌کننده را کاهش دهد.

SOLID = پیچیده‌تر شدن کد

اگر refactor برای فهمیدن به diagram بیشتری نیاز دارد ولی هزینه تغییر را کم نکرده، احتمالاً نتیجه بدتر شده است.

Examples / Patterns

قبل

export function ProfilePanel({ user, api, analytics, theme }: Props) {
  // fetch
  // transform
  // track
  // permissions
  // rendering
}

بعد از review

ممکن است نتیجه فقط این باشد:

- داده از query hook بیاید.
- transform pure به function مستقل منتقل شود.
- analytics در event handler نزدیک interaction بماند.
- permission helper موجود reuse شود.
- ProfilePanel فقط composition و rendering را نگه دارد.

نیازی نیست حتماً repository، service و use-case class اضافه شود.

Output Expectations

خروجی نهایی را به این ترتیب ارائه کن:

  1. Scope reviewed
  2. Prioritized findings
  3. SOLID principle + evidence
  4. Minimal refactor plan
  5. Files changed
  6. Behavior preserved / changed
  7. Validation performed
  8. Remaining risks

یافته‌ها را با شدت تقریبی high / medium / low اولویت‌بندی کن.

Safety / Limits

  • secret، credential یا token را در output کپی نکن.
  • dependency خارجی را بدون نیاز واقعی اضافه نکن.
  • migration سراسری repo را از یک finding محلی نتیجه نگیر.
  • اگر تغییر public contract یا data model ریسک بالایی دارد، آن را جدا گزارش کن.
  • اگر تست کافی وجود ندارد، refactor را کوچک و reversible نگه دار.

مشخصات Skill

نسخه
1.0.0
آخرین تغییر
2026-09-07
دسته‌بندی
معماری
سطح پیچیدگی
پیشرفته
مجوز
MIT
نویسنده
Naser Rasouli

سطح دسترسی و اجرا

امکان اجرای اسکریپتندارد
دسترسی شبکهندارد

مقاله منبع

برای توضیح عمیق‌تر مفاهیم، زمینه و مثال‌ها، مقاله‌ای را بخوانید که این Skill از آن ساخته شده است.