مفهوم مستقل عن اللغة يُفكّك تدفق الأعمال داخل دوال الخدمة إلى كتل تصريحية (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 nil | null -> 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، مأخوذ من SSOT | Project, Session |
| المتغير | camelCase، مُصرّح عبر @result | project, sessionCount |
| حقل request | PascalCase، مُستخرج من الطلب | ProjectID, Command |
| متغير محجوز | camelCase، يُوفّره الإطار | currentUser, config |
تختلف الأحرف الكبيرة والصغيرة بين الأنواع والمتغيرات، لذا يمكن التمييز بينها من التصريح فقط. project متغير، وProject نوع.
توسيع اللغات
SSaC مفهوم مستقل عن اللغة. Go هو التنفيذ المرجعي (PoC)، ونفس تصريحات sequence يمكن أن تُولّد كوداً بلغات أخرى.
تصريحات sequence (مشتركة)
|
+-- Go codegen
+-- Python codegen
+-- TypeScript codegen
+-- ...
المواصفات (تعريفات الأنواع، الصياغة، قواعد التحقق) وcodegen منفصلان.
يمكن الاطلاع على التطبيق المرجعي بلغة Go على GitHub.