امنیت، هویت، استقرار و تابآوری · فصل ۷ — Dependency، Contract، Event و Network Failure · 112
Architecture–Implementation Gap
failure را بعد از وقوع و بهصورت موردی تحلیل میکند و هنوز detection، containment و repair path از قبل طراحی نشده است. موضوع جاری: «Architecture–Implementation Gap». میتواند failure family «Architecture–Implementation Gap» را بازتولید/تشخیص دهد و detection، containment و recovery مناسب را تعیین کند.
خلاصهٔ درس
failure را بعد از وقوع و بهصورت موردی تحلیل میکند و هنوز detection، containment و repair path از قبل طراحی نشده است. موضوع جاری: «Architecture–Implementation Gap».
میتواند failure family «Architecture–Implementation Gap» را بازتولید/تشخیص دهد و detection، containment و recovery مناسب را تعیین کند.
خروجی این درس
میتواند failure family «Architecture–Implementation Gap» را بازتولید/تشخیص دهد و detection، containment و recovery مناسب را تعیین کند.
پیشنیازها
1. مسئله واقعی چیست؟
فرض کن diagram معماری میگوید ماژول billing نباید مستقیماً به persistence وصل شود و فقط باید از یک port تعریفشده استفاده کند. حالا import graph تمیز است، اما runtime registration یک writer خام از persistence را مستقیم داخل BillingService تزریق کرده است. روی کاغذ boundary سالم به نظر میرسد؛ در اجرای واقعی bypass داریم. Architecture–Implementation Gap یعنی اختلاف بین intent معتبر معماری و مسیر واقعاً اجراشده، نه صرفاً متفاوت بودن دو فایل یا دو نمودار.
2. intent و implementation دو artifact مستقلاند
Architecture intent باید بگوید چه ruleی معتبر است، مالک responsibility کیست، dependency direction چیست و چه exceptionهایی رسماً پذیرفته شدهاند. Implementation evidence چیز دیگری است: importها، runtime wiring، registration، call path، data flow یا architecture test. هیچکدام حق ندارد دیگری را بیصدا override کند. اگر بین آنها تضاد دیدی، ابتدا evidence chain بساز؛ بعد تصمیم بگیر کدامیک stale، ناقص یا واقعاً متخلف است.
3. یک architecture rule قابلبررسی چه اجزایی دارد؟
Rule مفید باید حداقل چهار بخش داشته باشد: subject، ممنوع/مجاز بودن رابطه، boundary یا owner و مرجع تصمیم. مثلاً: «billing میتواند از BillingRepositoryPort استفاده کند، اما نباید concrete storage implementation را مستقیم import یا در runtime call کند.» اگر فقط جملهای کلی مثل «لایهها باید جدا باشند» داشته باشیم، نمیتوان divergence را دقیق و قابلممیزی ثبت کرد.
4. import graph فقط بخشی از implementation است
Direct import میتواند یک accidental coupling واضح بسازد، اما نبودن direct import به معنی سالم بودن معماری نیست. dependency injection container، service locator، callback registration، plugin loading یا generated wiring میتواند در runtime مسیری بسازد که در import graph دیده نمیشود. برای همین Architecture Implementation Divergence Record v1 باید observed_structure و runtime_path را جدا نگه دارد.
5. اولین divergence پشتیبانیشده را پیدا کن
از symptom آخر شروع نکن و داستان root cause نساز. rule را بنویس، observed structure را ثبت کن، runtime path را در صورت وجود بازسازی کن و اولین نقطهای را پیدا کن که evidence از intent معتبر جدا میشود. اگر direct import از billing به persistence.sql_repo میبینی و هیچ exception معتبری وجود ندارد، همان edge میتواند اولین divergence باشد. اگر import تمیز است اما runtime binding writer ممنوع را inject میکند، divergence در wiring است، نه در source import.
6. هر cross-boundary edge تخلف نیست
ممکن است یک exception محدود و مصوب وجود داشته باشد؛ مثلاً مسیر read-only reconciliation اجازه داشته باشد یک read model مشخص را مستقیماً مصرف کند. در این حالت edge واقعی است، اما تا وقتی scope، authority و materiality با exception منطبقاند، نباید آن را accidental coupling گزارش کنی. rule بدون exception_authority ناقص است. «این edge عجیب است» evidence violation نیست.
7. گاهی code درست است و documentation stale است
یک diagram قدیمی ممکن است هنوز legacy_store را owner بداند، در حالی که ADR معتبر ownership را به platform_storage منتقل کرده و implementation نیز دقیقاً همان تصمیم جدید را اجرا میکند. در این case تغییر دادن code برای «هماهنگی با diagram» اشتباه است. failure family واقعی stale documentation است و repair target باید documentation/architecture view باشد. intent معتبر را از صرفاً تصویر قدیمی تشخیص بده.
8. material gap یعنی اختلافی که boundary را واقعاً تغییر میدهد
هر تفاوتی material نیست. rename یک box در diagram یا generated adapter مجاز ممکن است هیچ boundary ruleی را نقض نکند. materiality وقتی بالا میرود که ownership، dependency direction، data access، runtime call path یا کنترل موردنیاز دور زده شود. Record باید impact را نسبت به rule همان درس ثبت کند؛ نه اینکه هر تفاوت ساختاری را failure اعلام کند.
9. negative evidence و حالت OPEN
برای diagnosis قابل دفاع، حداقل یک توضیح رقیب را با probe محدود رد کن. اگر direct import نمیبینی، این negative evidence فقط فرضیه direct-import coupling را ضعیف میکند؛ هنوز runtime bypass ممکن است. اگر runtime registration یا decision authority در دسترس نیست، unknown را fact نکن. state باید OPEN_BOUNDARY_UNRESOLVED بماند و دقیقاً نوشته شود کدام evidence برای closure کم است.
10. containment با repair یکی نیست
Containment میتواند hotfix path را disable کند، rollout را محدود کند یا binding مشکلدار را موقتاً به مسیر امن برگرداند. Repair یعنی boundary دوباره به rule پشتیبانیشده برگردد: direct import حذف شود، dependency از port عبور کند، registration اصلاح شود یا documentation stale به تصمیم معتبر بهروز شود. containment برای کمکردن blast radius است؛ repair برای بازگرداندن قرارداد معماری.
11. green rerun بدون recurrence sensor closure نیست
ممکن است بعد از حذف یک import، functional test سبز شود. این فقط میگوید symptom فعلی دیده نشد. اگر هیچ sensor مستقلی برای برگشت همان violation نداشته باشی، claim «repair بسته شد» بیش از evidence است. sensor میتواند static architecture test، runtime binding assertion یا review-based rule باشد؛ انتخاب آن به boundary بستگی دارد. برای claim این درس، closure نیازمند سنسوری است که recurrence همان rule violation را detect کند.
12. worked case: hotfix و exception را قاطی نکن
در fixture اصلی، سه ماژول billing، service_boundary و persistence داریم. یک hotfix direct path غیرمجاز ساخته است، اما همزمان یک read-only reconciliation edge دارای exception معتبر است. learner باید direct path را material gap تشخیص دهد و edge مجاز را دستنخورده نگه دارد. اگر هر دو edge را violation اعلام کند، diagnosis از روی topology انجام شده نه از روی intent + authority + evidence.
13. transfer: capability package و generated adapter
در transfer، ownership از module به capability package منتقل میشود و generated adapterها رسماً مجازند. بنابراین cross-package edge به adapter بهتنهایی violation نیست. در همان fixture یک capability دیگر concrete storage داخلی را بدون exception مستقیم مصرف میکند. باید record را از صفر بازسازی کنی: allowed generated path را حفظ کن، direct internal path را بهعنوان divergence بررسی کن و rule را با context جدید بخوان.
14. Lab و 64 assertion
FLR002-LAB1 کاملاً local، deterministic و synthetic است و ۸ fixture دارد. evaluator هشت بُعد را برای هر case میسنجد: intent rule، observed structure، runtime path، exception authority، materiality، repair target، recurrence sensor و bounded unknowns. ۸×۸ یعنی ۶۴ assertion. learner-visible fixtureها observation میدهند، اما classification و hidden expected record را افشا نمیکنند.
15. چکلیست خروج
برای خروج مستقل باید rule و owner را صریح ثبت کنی؛ structure و runtime path را یکی نگیری؛ exception authority را قبل از violation verdict بررسی کنی؛ stale documentation را از code violation جدا کنی؛ حداقل یک alternative را با negative evidence رد کنی؛ unknown را OPEN نگه داری؛ containment و repair را تفکیک کنی؛ و برای repair یک recurrence sensor تعریف و همان mutation را دوباره امتحان کنی. این درس فقط یک fixture مصنوعی را اثبات میکند و درباره وضعیت هیچ production repository واقعی ادعایی ندارد.
ارزیابی
پاسخنامهی این درس در بستهی آموزش وجود ندارد؛ خودت جواب بده و صادقانه علامت بزن. «نیاز به مرور» درس را به صف تکرار میفرستد.
FLR-002-AF1 formative
FLR-002-AF2 formative
FLR-002-AF3 formative
FLR-002-S1 retrieval
FLR-002-S2 application
FLR-002-S3 diagnosis
FLR-002-S4 decision
FLR-002-S5 transfer
ملاکهای ارزیابی (rubric)
| Dimension | Sufficient evidence | Blocking failure |
|---|---|---|
| Intent + boundary | Current rule, owner, and decision authority are explicit | Old diagram or vague layering slogan treated as unquestioned authority |
| Evidence discrimination | Source structure and runtime path are separate; one alternative is rejected with negative evidence | One artifact alone produces causal closure |
| Exception + materiality | Exception authority/scope is checked before violation classification | Every cross-boundary edge labeled a violation |
| Repair + recurrence | Containment differs from repair and the same violation has a recurrence sensor/mutation rerun | Green functional rerun alone treated as proof |
| Transfer | Capability-package case is rebuilt from changed rules and evidence | Original module classification copied into the transfer context |
منابع و تازگی
مطالعهٔ موارد (case studies)
تصاویر درس
فایلهای آزمایشگاه
Use the eight local synthetic fixtures in fixtures/cases.json.
For each case:
- record direct observations before inference;
- state the active architecture rule and intended owner;
- keep source/import structure separate from runtime path;
- verify whether an allowed exception has valid authority and scope;
- classify a material gap only when evidence supports it;
- distinguish containment from repair;
- define a recurrence sensor for closure; and
- preserve bounded unknowns as OPEN instead of guessing.
Implement build_record(case) in starter.py. The learner package contains no hidden expected classification. Everything is synthetic and offline.