Feature Chain — تتبّع الـ full-stack بالكامل عبر operationId واحد

أي الملفات يجب تعديلها لتغيير ميزة واحدة؟ اكتب operationId واحدًا، ستظهر الإجابة.


المشكلة

في تطبيق full-stack، “الميزة الواحدة” لا تعيش في ملف واحد.

لنفترض أنك بحاجة إلى تعديل ميزة اسمها “ExecuteWorkflow”. هذه الميزة موجودة في مواصفات API، وفي منطق الخدمة، وفي مخطط قاعدة البيانات، وفي سياسة التفويض، وفي مخطط انتقال الحالات، وفي استدعاءات الدوال الخارجية، وفي سيناريوهات الاختبار، وفي مكونات الواجهة الأمامية.

تقليديًا، كانت هناك طريقتان لاستيعاب النطاق بأكمله:

  1. تشغيل grep عشرات المرات
  2. تتبّع الكود يدويًا

كلتاهما بطيئة، وكلتاهما تُفوّت أشياء. المراجع العابرة للطبقات على وجه الخصوص — من مواصفات API إلى الخدمة، ومن الخدمة إلى مخطط قاعدة البيانات، ومن الخدمة إلى سياسة التفويض — يكاد يكون من المستحيل على الإنسان تتبعها بشكل شامل.

ويصبح الأمر أسوأ حين تُكلّف الذكاء الاصطناعي بالتعديل. عند 200 endpoint، لا يعود الذكاء الاصطناعي قادرًا على الإمساك بالسياق الكامل. ينهار السياق، تنحرف الأنماط، وتصبح الميزة الحادية بعد المائتين أغلى بعشرة أضعاف من الحادية والعشرين. هذا هو الجدار الذي يصطدم به vibe coding.

لكن إذا كان مصدر كل طبقة يشير رمزيًا إلى الطبقات الأخرى، يكفي اتباع تلك المراجع لكشف النطاق بأكمله تلقائيًا.


ما هو Feature Chain

Feature Chain هو مجموعة كل العقد المصدرية المرتبطة بميزة API واحدة (operationId).

انطلاقًا من operationId واحد، يتتبع المراجع الرمزية بين المصادر ويطبع دفعةً واحدة جميع الملفات وأرقام الأسطر ذات الصلة. عشرات استخدامات grep تُستبدل بأمر واحد.

yongol chain ExecuteWorkflow specs/
── Feature Chain: ExecuteWorkflow ──

  OpenAPI    api/openapi.yaml                         POST /workflows/{id}/execute
  SSaC       service/workflow/execute_workflow.ssac   @get @empty @auth @state @call @publish @response
  DDL        db/workflows.sql                         CREATE TABLE workflows
  DDL        db/execution_logs.sql                    CREATE TABLE execution_logs
  Rego       policy/authz.rego                        resource: workflow
  StateDiag  states/workflow.md                       diagram: workflow → ExecuteWorkflow
  FuncSpec   func/billing/check_credits.go            @func billing.CheckCredits
  FuncSpec   func/billing/deduct_credit.go            @func billing.DeductCredit
  FuncSpec   func/worker/process_actions.go           @func worker.ProcessActions
  FuncSpec   func/webhook/deliver.go                  @func webhook.Deliver
  Hurl       tests/scenario-happy-path.hurl           scenario: scenario-happy-path.hurl

تظهر البنية الكاملة للميزة على شاشة واحدة. الطبقات غير المتصلة لا تُطبع.


لماذا يعمل

هذه ليست سحرًا. يعمل لأن المصادر تشير بالفعل بعضها إلى بعض.

في إطار عمل yongol، كل طبقة SSOT (Single Source of Truth) تشير رمزيًا إلى الطبقات الأخرى:

  • @get Model.Method في SSaC ← جدول DDL
  • @auth action resource في SSaC ← سياسة تفويض Rego
  • @state diagramID في SSaC ← مخطط حالات Mermaid
  • @call pkg.Func في SSaC ← تنفيذ FuncSpec
  • @publish "topic" في SSaC ← الدوال المشتركة في نفس topic
  • operationId في OpenAPI ← اسم ملف SSaC
  • سيناريو Hurl ← endpoint في OpenAPI
  • apiClient.<op>() في React TSX ← operationId في OpenAPI

صُمّمت هذه المراجع في الأصل من أجل yongol validate — المرحلة التي تتحقق تقاطعيًا من اتساق 9 SSOT قبل التصريف. وبما أن validate يُحلّلها أصلًا، فإن إعادة استخدام نفس البنية التحتية تُحوّل استخراج feature chain إلى اجتياز رسم بياني.


مسار الاجتياز

إذا جعلنا operationId نقطة البداية، يتفرع رسم المراجع هكذا:

operationId (نقطة الدخول)
├── OpenAPI ← path + method
├── SSaC ← ملف دالة الخدمة
│   ├── @get ← جداول DDL
│   ├── @auth ← قواعد سياسة Rego
│   ├── @state ← انتقالات Mermaid stateDiagram
│   ├── @call ← تنفيذات FuncSpec
│   └── @publish ← مشتركو الطابور
├── Hurl ← سيناريوهات اختبار تشير إلى operationId
└── React TSX ← ملفات الـ frontend التي تستدعي endpoint عبر apiClient

يتبع كل فرع خطوة واحدة فقط من المرجع الرمزي. إنه اجتياز واسع لا عميق. تظهر كل طبقة تترك فيها الميزة أثرًا.


ماذا يتغيّر

تحديد نطاق التعديل

“أين أضع يدي لتغيير هذه الميزة؟”

للإجابة على ذلك، نقرأ الكود، ونشغّل grep، ونسأل زملاءنا. يستبدل Feature Chain هذا السؤال بأمر واحد. لا يُفلت ملف — طالما وُجد المرجع الرمزي.

تعديلات يقودها الذكاء الاصطناعي

أصعب ما في تكليف الذكاء الاصطناعي بتعديل ميزة هو إخباره بـ"ما هو النطاق". الذكاء الاصطناعي لا يُعدّل بشكل صحيح إلا إذا كانت الملفات ذات الصلة في نافذة سياقه، ويجب على الإنسان أن يقرر أيها ذي صلة.

مع Feature Chain الأمر مختلف. أعطه operationId واحدًا، فيُحدَّد النطاق بأكمله تلقائيًا. يُعَدّ سياق الذكاء الاصطناعي دون أي نقص. ولأن الـ 9 SSOT عبارة عن مواصفات إعلانية — أكثر تضاغطًا بكثير من كود Go المُولَّد — فإن السلسلة كاملة تسع في نافذة السياق مع هامش.

مراجعة الكود

عند مراجعة PR، يصبح السؤال “إن لمسوا هذه الميزة، ألا يجب أن يتغير ذلك الملف أيضًا؟” تحققًا بديهيًا — يكفي مقارنته بالسلسلة. البنية هي التي تلتقط التنافر بين الطبقات بدل الأشخاص.

التأهيل

عندما يقول مهندس جديد: “أريد أن أفهم كيف تعمل ExecuteWorkflow”، يكفي أن تُريه Feature Chain. من API حتى قاعدة البيانات، ومن سياسة التفويض حتى سيناريوهات الاختبار — تضاريس الميزة كاملةً على شاشة واحدة.


لماذا operationId

اختيار نقطة البداية مهم. اختار Feature Chain operationId.

السبب بسيط. في تطبيق full-stack، وحدة الميزة هي endpoint API. يضغط المستخدم زرًا، فيُستدعى API، ثم يُشغَّل منطق الخدمة، وتُقرأ قاعدة البيانات، ويُتحقق من التفويض، وتحدث انتقالات الحالة. بداية هذا التدفق بأكمله هي operationId.

operationId مُعرَّف مسبقًا في مواصفات OpenAPI، وهو اسم مشترك بين الفريق بأكمله. إن قلت “علينا تعديل ExecuteWorkflow”، فإن مهندس الـ backend ومهندس الـ frontend والـ QA يفكرون في الشيء ذاته. صُمّم Feature Chain حول هذا الاسم الكوني بوصفه خيطًا يخترق الـ stack بأكمله.

يسمي yongol هذا “operationId هو حجر الأساس (keystone)”. مُعرِّف واحد بصيغة PascalCase يربط 9 طبقات ربطًا فعليًا.


الشروط المسبقة

لكي يعمل Feature Chain، ثمة افتراضات:

  1. يجب أن تشير المصادر بعضها إلى بعض رمزيًا. يجب أن تُشير توجيهات @get و@auth و@state و@call و@publish في SSaC إلى SSOT أخرى بشكل صريح. إذا كان المرجع ضمنيًا — مثلًا اسم جدول قاعدة بيانات يوجد فقط كسلسلة نصية داخل الكود — فلا يمكن تتبعه.

  2. يجب أن ينجح yongol validate. يتبع Feature Chain مراجع رمزية، فإن لم تكن صالحة تصبح النتيجة خاطئة. يضمن validate سلامة المراجع، وFeature Chain يجتاز فوقه.

لهذا Feature Chain ليس أداةً عامة. لا يمكن تطبيقه على أي مشروع. يعمل فقط في المشاريع التي صُمّمت فيها المراجع بين المصادر بشكل صريح — مثل yongol، حيث تشير الـ SSOT بعضها إلى بعض صراحة.


المستقبل: GEUL + SILK

حاليًا، يجتاز Feature Chain باستدعاء كل محلل SSOT على حدة. يستدعي محلل SSaC ومحلل DDL ومحلل Rego ومحلل Mermaid ومحلل Hurl ومحلل TSX ثم يدمج النتائج.

عند ترجمة جميع الـ SSOT إلى رسم GEUL، يتحول Feature Chain إلى استعلام فهرس واحد. وبعملية AND على مستوى البِتات في SIDX ضمن SILK، يمكن استخراج كل العقد المرتبطة بـ operationId في استعلام واحد.

من الاجتياز عبر كل محلل إلى استعلام الرسم. تظل واجهة Feature Chain كما هي، لكن الداخل يتغير جذريًا.


خلاصة

في تطبيق full-stack، “الميزة” لا تعيش في ملف واحد. تمتد عبر عدة طبقات، وتلك الطبقات تشير بعضها إلى بعض. يتبع Feature Chain هذه المراجع ليستخرج تلقائيًا النطاق الكامل لميزة واحدة.

اكتب operationId واحدًا ستحصل على كل شيء: من مواصفات API إلى مخطط قاعدة البيانات، ومن سياسة التفويض إلى سيناريوهات الاختبار، ومن تنفيذ الدوال إلى مكونات الواجهة الأمامية. عشرات استخدامات grep تُستبدل بأمر واحد. يحصل الذكاء الاصطناعي على سياق بلا نقص، ويحصل الإنسان على حرية على القضبان.

الكود: github.com/park-jun-woo/yongol