סקיל Codebase Design
codebase-design הוא סקיל לקלוד קוד שנותן שפה ועקרונות לעיצוב מודולים עמוקים: הרבה התנהגות מאחורי ממשק קטן ופשוט. במקום שכל דיון על מבנה הקוד יתפזר למונחים מעורפלים כמו "רכיב" או "שירות", הסקיל מגדיר אוצר מילים מדויק, מודול, ממשק, עומק, תפר, מנוף ולוקליות, ומלמד את קלוד לחשוב לפיו. התוצאה היא קוד שקל לקרוא, קל לבדוק וקל לתחזק. בפרויקטי הפיתוח שאני מוביל, השפה הזאת הופכת החלטות עיצוב מוויכוח סגנוני להחלטה מבוססת עקרונות. במדריך תקבלו את אוצר המילים המלא, ארבעה תרחישי שימוש, וצ'קליסט לעבודה נכונה.
פקודת התקנה
npx skills add mattpocock/skills@codebase-design -g -y
ההתקנה מתבצעת דרך מנהל החבילות הרשמי של הסקילים בפקודה אחת. הסקיל הוא קובץ Markdown פתוח מהמאגר של מאט פוקוק. הוא משמש גם כשפה משותפת שסקילים אחרים נשענים עליה. אפשר להוריד ולבדוק את הקוד דרך הכפתורים שבראש העמוד.
מה הסקיל כולל?
הסקיל מתעד אוצר מילים ועקרונות עיצוב מדויקים, עם דגש על ההבחנה בין מודול עמוק למודול רדוד ועל איך לתכנן ממשקים קטנים שמסתירים מורכבות.
קוד הסקיל המלא
---
name: codebase-design
description: Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary.
---
# Codebase Design
Design **deep modules**: a lot of behaviour behind a small interface, placed at a clean seam, testable through that interface. Use this language and these principles wherever code is being designed or restructured. The aim is leverage for callers, locality for maintainers, and testability for everyone.
## Glossary
Use these terms exactly — don't substitute "component," "service," "API," or "boundary." Consistent language is the whole point.
**Module** — anything with an interface and an implementation. Deliberately scale-agnostic: a function, class, package, or tier-spanning slice. _Avoid_: unit, component, service.
**Interface** — everything a caller must know to use the module correctly: the type signature, but also invariants, ordering constraints, error modes, required configuration, and performance characteristics. _Avoid_: API, signature (too narrow — they refer only to the type-level surface).
**Implementation** — what's inside a module, its body of code. Distinct from **Adapter**: a thing can be a small adapter with a large implementation (a Postgres repo) or a large adapter with a small implementation (an in-memory fake). Reach for "adapter" when the seam is the topic; "implementation" otherwise.
**Depth** — leverage at the interface: the amount of behaviour a caller (or test) can exercise per unit of interface they have to learn. A module is **deep** when a large amount of behaviour sits behind a small interface, **shallow** when the interface is nearly as complex as the implementation.
**Seam** _(Michael Feathers)_ — a place where you can alter behaviour without editing in that place; the *location* at which a module's interface lives. Where to put the seam is its own design decision, distinct from what goes behind it. _Avoid_: boundary (overloaded with DDD's bounded context).
**Adapter** — a concrete thing that satisfies an interface at a seam. Describes *role* (what slot it fills), not substance (what's inside).
**Leverage** — what callers get from depth: more capability per unit of interface they learn. One implementation pays back across N call sites and M tests.
**Locality** — what maintainers get from depth: change, bugs, knowledge, and verification concentrate in one place rather than spreading across callers. Fix once, fixed everywhere.
## Deep vs shallow
**Deep module** = small interface + lots of implementation:
```
┌─────────────────────┐
│ Small Interface │ ← Few methods, simple params
├─────────────────────┤
│ │
│ Deep Implementation│ ← Complex logic hidden
│ │
└─────────────────────┘
```
**Shallow module** = large interface + little implementation (avoid):
```
┌─────────────────────────────────┐
│ Large Interface │ ← Many methods, complex params
├─────────────────────────────────┤
│ Thin Implementation │ ← Just passes through
└─────────────────────────────────┘
```
When designing an interface, ask:
- Can I reduce the number of methods?
- Can I simplify the parameters?
- Can I hide more complexity inside?
## Principles
- **Depth is a property of the interface, not the implementation.** A deep module can be internally composed of small, mockable, swappable parts — they just aren't part of the interface. A module can have **internal seams** (private to its implementation, used by its own tests) as well as the **external seam** at its interface.
- **The deletion test.** Imagine deleting the module. If complexity vanishes, it was a pass-through. If complexity reappears across N callers, it was earning its keep.
- **The interface is the test surface.** Callers and tests cross the same seam. If you want to test *past* the interface, the module is probably the wrong shape.
- **One adapter means a hypothetical seam. Two adapters means a real one.** Don't introduce a seam unless something actually varies across it.
## Designing for testability
Good interfaces make testing natural:
1. **Accept dependencies, don't create them.**
```typescript
// Testable
function processOrder(order, paymentGateway) {}
// Hard to test
function processOrder(order) {
const gateway = new StripeGateway();
}
```
2. **Return results, don't produce side effects.**
```typescript
// Testable
function calculateDiscount(cart): Discount {}
// Hard to test
function applyDiscount(cart): void {
cart.total -= discount;
}
```
3. **Small surface area.** Fewer methods = fewer tests needed. Fewer params = simpler test setup.
## Relationships
- A **Module** has exactly one **Interface** (the surface it presents to callers and tests).
- **Depth** is a property of a **Module**, measured against its **Interface**.
- A **Seam** is where a **Module**'s **Interface** lives.
- An **Adapter** sits at a **Seam** and satisfies the **Interface**.
- **Depth** produces **Leverage** for callers and **Locality** for maintainers.
## Rejected framings
- **Depth as ratio of implementation-lines to interface-lines** (Ousterhout): rewards padding the implementation. We use depth-as-leverage instead.
- **"Interface" as the TypeScript `interface` keyword or a class's public methods**: too narrow — interface here includes every fact a caller must know.
- **"Boundary"**: overloaded with DDD's bounded context. Say **seam** or **interface**.
## Going deeper
- **Deepening a cluster given its dependencies** — see [DEEPENING.md](DEEPENING.md): dependency categories, seam discipline, and replace-don't-layer testing.
- **Exploring alternative interfaces** — see [DESIGN-IT-TWICE.md](DESIGN-IT-TWICE.md): spin up parallel sub-agents to design the interface several radically different ways, then compare on depth, locality, and seam placement.
מה זה codebase-design ולמה הסקיל הזה שונה?
codebase-design פותר בעיה שקטה אך יקרה: דיונים על מבנה קוד שמתפזרים כי לכל אחד מילון משלו. אחד אומר "רכיב", השני "שירות", השלישי "שכבה", וכולם מתכוונים למשהו קצת אחר. הסקיל מחליף את הבלבול הזה בשפה אחת מדויקת, וזה לבדו משנה את איכות ההחלטות.
מה שמייחד אותו הוא העיקרון של מודול עמוק: הרבה התנהגות מאחורי ממשק קטן. מודול עמוק נותן לקורא מנוף, הוא לומד מעט ומקבל הרבה, בעוד מודול רדוד חושף ממשק מורכב כמעט כמו המימוש ולכן רק מוסיף רעש. הסקיל מלמד מתי להוסיף תפר, מתי לא, ואיך לתכנן ממשק שניתן לבדיקה טבעית. הוא אפילו מגדיר אילו מונחים לא להשתמש בהם, כדי לשמור על דיוק.
ההבדל מורגש בכל החלטת עיצוב. במקום ויכוח סגנוני, יש קריטריון: האם הממשק קטן, האם המורכבות מוסתרת, האם יש מנוף. בשילוב עם סקיל improve-codebase-architecture שמאתר הזדמנויות העמקה, מקבלים גם את השפה וגם את הכלי ליישם אותה, וזה צמד חזק לכל מי שאכפת לו ממבנה הקוד.
מה codebase-design נותן לקלוד קוד?
הסקיל מוסיף לקלוד שפה ועקרונות של אדריכל תוכנה, כך שכל החלטת עיצוב נשענת על קריטריונים ברורים במקום על תחושת בטן.
שפה מדויקת ואחידה
הסקיל מגדיר אוצר מילים קבוע, מודול, ממשק, עומק, תפר, מנוף ולוקליות, ומשתמש בו בעקביות. כך כל דיון על מבנה הקוד מתנהל באותה שפה, וההמלצות הופכות ברורות וישימות במקום מעורפלות.
עומק על פני רדידות
העיקרון המנחה הוא לתכנן מודולים עמוקים: ממשק קטן שמסתיר מורכבות רבה. הסקיל מלמד את קלוד לצמצם מתודות, לפשט פרמטרים ולהסתיר עוד לוגיקה פנימה, וכך הקוד נותן יותר ערך עם פחות שטח פנים.
תכנון לבדיקות
ממשק טוב הופך בדיקות לטבעיות. הסקיל מנחה לקבל תלויות במקום ליצור אותן, ולהחזיר תוצאות במקום לייצר תופעות לוואי. כך הקוד ניתן לבדיקה דרך הממשק שלו, ולא צריך לעקוף אותו כדי לבדוק.
מבחן המחיקה והתפר
שני כלי חשיבה חדים: מבחן המחיקה בודק אם מודול מרוויח את מקומו, ועקרון התפר קובע מתי באמת צריך נקודת החלפה. הכלל פשוט: תפר אחד הוא היפותטי, שניים הם אמיתי, ואין להוסיף הפשטה ללא צורך.
ארבע היכולות הופכות את קלוד למי שמדבר ומעצב כמו אדריכל תוכנה. בעבודות שלי, השפה הזאת קיצרה דיוני עיצוב והובילה לקוד שקל יותר להרחיב ולבדוק לאורך זמן.
למי הסקיל הזה מתאים?
מובילי פיתוח ואדריכלי תוכנה: זה הקהל המובהק. הסקיל נותן שפה משותפת שמייעלת כל דיון עיצובי והופך אותו לממוקד. השילוב עם סקיל diagnosing-bugs עוזר גם כשבאג חושף בעיית מבנה.
צוותים שרוצים עקביות: כשכל חברי הצוות מדברים באותה שפה על מבנה הקוד, מפסיקים להתווכח על מילים ומתמקדים במהות. זה מאיץ סקירות קוד והחלטות תכנון.
מפתחים שלומדים לתכנן טוב יותר: הסקיל הוא קורס מזוקק בעיצוב מודולים. הוא מלמד לזהות רדידות, לתכנן עומק ולמקם תפרים נכון, מיומנויות שמבדילות מפתח טוב ממצוין.
סוכנויות ומשרדי פיתוח: קוד בנוי נכון קל יותר למסור בין מפתחים ולתחזק לאורך זמן. גם בעבודות אוטומציה שלי, מודולים עמוקים הופכים מערכות לקלות להרחבה.
מפתחים שעובדים עם AI: קוד עם ממשקים קטנים וברורים קל יותר גם לסוכני AI לנווט ולשנות. עיצוב מודולים עמוקים הוא השקעה שמשתלמת גם בעבודה עם בינה מלאכותית.
מי שפחות יתאים: סקריפט חד-פעמי קצר לא זקוק לתורת עיצוב מודולים. הסקיל מבריק דווקא בקוד שאמור לחיות, לגדול ולהיבדק לאורך זמן.
איך codebase-design עזר לי בפרויקטים אמיתיים
ממשק שצומצם ממורכב לפשוט
מודול חשף עשר מתודות ופרמטרים מבלבלים. עם השפה של הסקיל זיהינו שהוא רדוד, וצמצמנו אותו לממשק קטן שמסתיר את המורכבות. הקוראים פתאום נדרשו ללמוד הרבה פחות, והשימוש במודול הפך פשוט ובטוח.
החלטה מבוססת על מבחן המחיקה
התלבטנו אם להשאיר שכבת הפשטה. מבחן המחיקה של הסקיל נתן תשובה ברורה: מחיקתה לא הוסיפה מורכבות לקוראים, סימן שהיא הייתה מעבר ריק. הסרנו אותה, והקוד נעשה ישיר וברור יותר בלי לאבד דבר.
מיקום תפר נכון לבדיקות
קוד היה קשה לבדיקה כי לא היה תפר במקום הנכון. בעזרת עקרון התפר מיקמנו נקודת החלפה אחת גבוהה, והבדיקות הפכו לטבעיות דרך הממשק. כלל שני המתאמים מנע מאיתנו להוסיף תפרים מיותרים.
שפה משותפת שזירזה סקירות קוד
בצוות, סקירות קוד נמשכו כי כל אחד תיאר בעיות מבנה אחרת. אימוץ אוצר המילים של הסקיל יצר שפה משותפת, וההערות הפכו מדויקות וקצרות. הסקירות התקצרו והאיכות עלתה, כי כולם דיברו על אותו דבר.
ארבעת המקרים מראים שהסקיל לא רק מנקה קוד, הוא משדרג את אופן החשיבה עליו. כששפת העיצוב מדויקת, ההחלטות טובות יותר, הקוד עמוק יותר, והוא נשאר קל לתחזוקה ולבדיקה לאורך זמן.
סיכום
סקיל codebase-design הוא בסיס לכל מי שאכפת לו מאיכות מבנה הקוד. הוא נותן שפה ועקרונות לעיצוב מודולים עמוקים, ובכך הופך החלטות עיצוב מוויכוח סגנוני להחלטה מבוססת עומק, מנוף ולוקליות.
אם אתם מתחילים, בפעם הבאה שאתם מתכננים מודול, בקשו מקלוד להעריך אותו בשפה של הסקיל: האם הממשק קטן, האם הוא עמוק, היכן התפר. תראו איך השאלות האלה מובילות לעיצוב טוב יותר כמעט מאליו.
בפוסטים הבאים אמשיך לסקור סקילים שמשדרגים את איכות הפיתוח. האתר של דביר נעמן מרכז את כל הכלים, השיטות והליווי שאני מציע לעסקים שרוצים לבנות תוכנה איכותית עם בינה מלאכותית.
שיתוף הסקיל
שאלות ותשובות
מה זה בעצם הסקיל codebase-design?
זה סקיל לקלוד קוד שנותן שפה ועקרונות לעיצוב מודולים עמוקים: הרבה התנהגות מאחורי ממשק קטן. הוא מגדיר אוצר מילים מדויק, כמו מודול, ממשק, עומק, תפר ומנוף, ומלמד את קלוד לעצב ולשפר קוד לפיו. המטרה היא קוד קריא, בר-בדיקה וקל לתחזוקה.
מה זה מודול עמוק ולמה הוא עדיף?
מודול עמוק הוא כזה שמסתיר הרבה מורכבות מאחורי ממשק קטן ופשוט, כך שהקורא לומד מעט ומקבל הרבה. מודול רדוד, לעומתו, חושף ממשק מורכב כמעט כמו המימוש ולכן רק מוסיף רעש בלי לחסוך עבודה. עומק נותן מנוף לקוראים ולוקליות למתחזקים, וזה לב העיצוב הטוב.
איך מתקינים את הסקיל בקלוד קוד?
בפקודה אחת דרך מנהל החבילות הרשמי של הסקילים, כפי שמופיע בקופסת ההתקנה למעלה. הסקיל הוא קובץ Markdown פתוח מהמאגר של מאט פוקוק. הוא משמש גם כשפה משותפת שסקילים אחרים בתחום הארכיטקטורה נשענים עליה.
מה זה תפר ולמה הוא חשוב?
תפר הוא מקום שבו אפשר לשנות התנהגות בלי לערוך את הקוד עצמו, כלומר היכן שהממשק של המודול יושב. מיקום התפר הוא החלטת עיצוב בפני עצמה. הכלל של הסקיל פשוט: תפר אחד הוא היפותטי, שני מתאמים הם תפר אמיתי, ואין להוסיף נקודת החלפה בלי שמשהו באמת משתנה דרכה.
איך הסקיל עוזר לכתוב קוד שקל לבדוק?
הוא מנחה שני עקרונות מרכזיים: לקבל תלויות במקום ליצור אותן בתוך המודול, ולהחזיר תוצאות במקום לייצר תופעות לוואי. קוד כזה ניתן לבדיקה טבעית דרך הממשק שלו, בלי לעקוף אותו. בנוסף, שטח פנים קטן פירושו פחות בדיקות והגדרה פשוטה יותר לכל בדיקה.
מה זה מבחן המחיקה?
זה כלי חשיבה פשוט: דמיינו שאתם מוחקים מודול. אם המורכבות נעלמת, הוא היה רק מעבר ריק שלא הצדיק את קיומו. אם המורכבות מופיעה מחדש ומתפזרת על פני כמה קוראים, סימן שהוא הרוויח את מקומו. המבחן עוזר להבדיל בין הפשטה אמיתית לשכבה מיותרת.
האם הסקיל מתאים לכל שפת תכנות?
כן. העקרונות, כמו עומק מודולים, תפרים, מנוף ולוקליות, אינם תלויים בשפה. בין אם אתם כותבים בטייפסקריפט, פייתון או כל שפה אחרת, אוצר המילים והעקרונות חלים באותה מידה. הסקיל עוסק בעיצוב, לא בתחביר ספציפי.
האם הסקיל מתאים גם למתחילים?
בהחלט, והוא אפילו מומלץ. הוא מלמד דרך חשיבה שלוקח שנים לפתח לבד: לזהות רדידות, לתכנן עומק ולמקם תפרים. מפתח מתחיל שמאמץ את השפה הזאת מקדים את זמנו, כי הוא לומד לעצב נכון מההתחלה במקום לתקן הרגלים בהמשך.