مفهوم مستقل عن اللغة يُفكّك تدفق الأعمال داخل دوال الخدمة إلى كتل تصريحية (sequences).

المشكلة

يُغطي SSOT الحالي ما يقع خارج الدالة فقط:

SSOT الحالينطاق التغطيةداخل الدوال؟
OpenAPIمسارات API، المعاملات، schemas الاستجابةلا
SQL DDLهياكل الجداول، الفهارس، القيودلا

داخل الدالة — تدفق الأعمال المتمثل في “استعلام -> تحقق -> إنشاء -> استجابة” — لا يوجد مكان للتصريح عنه. لا يمكن فهمه إلا بقراءة كود التنفيذ. تملأ الـsequences هذه الفجوة.

الهيكل الطبقي لـSSOT

SSaC هي الطبقة الثالثة التي تُبنى فوق SSOT الحالي.

OpenAPI       → حدود API (المسارات، المعاملات، الاستجابات)
SQL DDL       → حدود البيانات (الجداول، القيود، الفهارس)
SSaC          → داخل الدوال (تدفق الأعمال، تصريحات sequence)
─────────────────────────────────────────────────
كود التنفيذ   → يُولّد بواسطة codegen (معالجة الأخطاء، الكود النمطي)

الطبقات الثلاث العليا تتولى التصريح، وكود التنفيذ يُشتق من التصريحات. ما يكتبه الإنسان هو التصريحات فقط.

المفاهيم الأساسية

sequence

وحدة تصريحية تُنمّط كتل التنفيذ داخل الدالة.

أعلن فقط عن الـwhat (ماذا تفعل)، ويتولى codegen ملء الـhow (كيف تفعل).

10 أنواع ثابتة

النوعالدورمثال
authorizeالتحقق من الصلاحياتاستعلام السياسات بناءً على action/resource/ID
getاستعلام المواردModel.FindByID(id) -> result
guard nilالخروج إذا كانت النتيجة nullخطأ وخروج إذا لم يُوجد
guard existsالخروج إذا كانت النتيجة موجودةخطأ وخروج إذا كان موجوداً بالفعل
postإنشاء المواردModel.Create(fields…) -> result
putتحديث المواردModel.Update(id, fields…)
deleteحذف المواردModel.Delete(id)
passwordمقارنة كلمات المرورالخروج عند عدم تطابق hash
callاستدعاء خارجيمعالجة موارد لا يمكن التعبير عنها بـCRUD؛ الخروج عند الفشل
responseإرجاع الاستجابةjson, view, redirect

بما أن الأنواع مغلقة، يمكن توليد الكود عبر مطابقة القوالب حسب النوع. هذا هو الأساس الذي يُتيح codegen رمزي بدون LLMs.

نطاق model

لا يقتصر model على جداول قاعدة البيانات. أي مورد يمكن التعامل معه عبر CRUD يُعتبر model. استعلامات قاعدة البيانات، والتحقق من وجود الملفات، واستدعاءات API الخارجية كلها تُعبّر عنها بشكل موحد عبر get/post/put/delete.

مثال على الصياغة (Go PoC)

رغم أن SSaC مفهوم مستقل عن اللغة، إلا أن التنفيذ المرجعي يستخدم صياغة تعليقات Go. بما أن الذكاء الاصطناعي يفهم Go AST بالفعل، فلا توجد تكلفة تعلم إضافية.

بسيط (إنشاء)

// @sequence get
// @model Project.FindByID
// @param ProjectID request
// @result project Project

// @sequence guard nil project
// @message "프로젝트가 존재하지 않습니다"

// @sequence post
// @model Session.Create
// @param ProjectID request
// @param Command   request
// @result session Session

// @sequence response json
// @var session
func CreateSession(w http.ResponseWriter, r *http.Request) {}

مركّب (حذف + صلاحيات + تحقق + استدعاء خارجي)

// @sequence authorize
// @action delete
// @resource project
// @id ProjectID

// @sequence get
// @model Project.FindByID
// @param ProjectID request
// @result project Project

// @sequence guard nil project
// @message "프로젝트가 존재하지 않습니다"

// @sequence get
// @model Session.CountByProjectID
// @param ProjectID request
// @result sessionCount int

// @sequence guard exists sessionCount
// @message "하위 세션이 존재하여 삭제할 수 없습니다"

// @sequence call
// @component notification
// @param project.OwnerEmail
// @param "프로젝트가 삭제됩니다"

// @sequence call
// @func cleanupProjectResources
// @param project
// @result cleaned bool

// @sequence delete
// @model Project.Delete
// @param ProjectID request

// @sequence response json
func DeleteProject(w http.ResponseWriter, r *http.Request) {}

نتيجة codegen

التنفيذ المُشتق من تصريحات sequence أعلاه:

func CreateSession(w http.ResponseWriter, r *http.Request) {
    // get
    project, err := projectModel.FindByID(projectID)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // guard nil
    if project == nil {
        http.Error(w, "프로젝트가 존재하지 않습니다", http.StatusNotFound)
        return
    }

    // post
    session, err := sessionModel.Create(projectID, command)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    // response json
    json.NewEncoder(w).Encode(map[string]interface{}{
        "session": session,
    })
}

مقارنة تكلفة الـtokens

تصريح sequenceكود التنفيذ
عدد الأسطر10~15 سطراً30~100 سطر
المحتوى المُعبّر عنهwhat (ماذا تفعل)how (كيف تفعل)
معالجة الأخطاءلا شيء (يُولّده codegen)مُتضمّن بالكامل
الاعتماد على المكتباتلا شيءimport، تهيئة، استدعاء
وقت التغييرعند تغيير تدفق الأعمالينعكس تلقائياً بإعادة تشغيل codegen

ما يُصانه من قبل الإنسان هو تصريحات sequence فقط. كود التنفيذ يُكتب فوقه بإعادة تشغيل codegen عند تغيير التصريحات.

مبادئ التصميم

early return — العقد الشامل لجميع الأنواع

هذه هي المقدمة التي تجعل الترتيب الخطي لكتل sequence ممكناً. كل sequence باستثناء response يخرج فوراً عند الفشل. call ليس استثناءً. فقط اقرأ من الأعلى إلى الأسفل بدون تفرع.

النوعشرط الفشل
authorizeلا صلاحية -> return
getخطأ استعلام -> return
guard nilnull -> return
guard existsموجود -> return
post/put/deleteخطأ قاعدة بيانات -> return
passwordعدم تطابق -> return
callفشل -> return
responseالأخير (يُرجع)

بما أن call يتبع نفس عقد guard، لا حاجة لإضافة guard منفصل بعد call. يُولّد codegen تلقائياً فحوصات الأخطاء وearly returns لكل call.

@transaction

بيانات وصفية على مستوى الدالة. ليس أحد أنواع sequence العشرة، بل يُصرّح عمّا إذا كانت الدالة بأكملها يجب أن تُغلّف في معاملة.

// @transaction
// @sequence get
// @model Account.FindByID
// @param AccountID request
// @result account Account
// ...

بالاقتران مع بنية early return، تتشكل حدود المعاملة بشكل طبيعي:

@transaction مُصرّح
  → فشل guard → rollback + return
  → نجاح آخر sequence → commit
  → حدوث خطأ → rollback + return

بما أنه لا توجد تفرعات، فحد المعاملة واحد: “الدالة بأكملها”. لا حاجة لتحديد مواضع begin/end؛ يُقرر codegen ما إذا كان سيُغلّف بناءً فقط على وجود أو غياب @transaction. إذا كنت بحاجة إلى معاملتين، فهذا يعني أن لديك مسؤوليتين. قسّم الدالة.

call — شكل خاص من model

يتشارك call نفس جوهر model. إذا كان model يمثل معالجة الموارد المُعبّر عنها بـCRUD (get/post/put/delete)، فإن call يمثل معالجة الموارد التي لا يمكن التعبير عنها بـCRUD. كلاهما يستدعي عملاً له اعتماديات خارجية، ويُرجع عند الفشل.

معالجة الموارد
  +-- model (CRUD)      → get/post/put/delete
  +-- call  (غير CRUD)  → component أو func
  • @component — نظام التسجيل. يُرقّى عندما يظهر نمط متكرر ثلاث مرات أو أكثر.
  • @func — منطق فريد. يُنفّذ مباشرة من قبل شخص أو ذكاء اصطناعي.

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

@message

بيانات وصفية يمكن إرفاقها اختيارياً بجميع أنواع sequence. تُحدد الرسالة التي تُنقل إلى المستخدم عند الفشل.

// @sequence guard nil project
// @message "프로젝트가 존재하지 않습니다"

// @sequence post
// @model Session.Create
// @param ProjectID request
// @param Command   request
// @result session Session
// @message "세션 생성에 실패했습니다"

عند حذف @message، يُولّد codegen رسالة افتراضية تلقائياً من النوع + اسم النموذج. لا يُصرّح عنه إلا عند الحاجة إلى رسالة مخصصة.

الدوال النقية لا توجد في طبقة الخدمة

جميع الكتل المُصرّح عنها في sequence تتضمن عملاً له اعتماديات خارجية. الوظائف النقية مثل تحويل التنسيق أو حساب القيم لا تنتمي إلى طبقة الخدمة، بل إلى داخل model أو الدالة المُستدعاة. دوال الخدمة تُنسّق فقط (orchestration)؛ الحساب النقي ينتمي إلى الطرف المُستدعى.

مراجع الأنواع

لا يُعرّف SSaC أنواعه الخاصة. إنه يُشير إلى أنواع مُشتقة من مصادر SSOT الحالية.

المصدرمثال
مخطط قاعدة البيانات (SQL DDL)Project, Session
مواصفات API (OpenAPI)CreateSessionRequest
تعريفات الواجهاتFileSystem, Cache

قواعد التسمية

التصنيفالقاعدةمثال
النوعPascalCase، مأخوذ من SSOTProject, Session
المتغيرcamelCase، مُصرّح عبر @resultproject, sessionCount
حقل requestPascalCase، مُستخرج من الطلبProjectID, Command
متغير محجوزcamelCase، يُوفّره الإطارcurrentUser, config

تختلف الأحرف الكبيرة والصغيرة بين الأنواع والمتغيرات، لذا يمكن التمييز بينها من التصريح فقط. project متغير، وProject نوع.

توسيع اللغات

SSaC مفهوم مستقل عن اللغة. Go هو التنفيذ المرجعي (PoC)، ونفس تصريحات sequence يمكن أن تُولّد كوداً بلغات أخرى.

تصريحات sequence (مشتركة)
  |
  +-- Go codegen
  +-- Python codegen
  +-- TypeScript codegen
  +-- ...

المواصفات (تعريفات الأنواع، الصياغة، قواعد التحقق) وcodegen منفصلان.

يمكن الاطلاع على التطبيق المرجعي بلغة Go على GitHub.