filefunc × Hono — الكود الذي يقرأه الوكيل دفعةً واحدة: من 60 سطراً إلى 18

إذا كان وكيل الترميز يصلح الشيء الخطأ باستمرار في قواعد الكود الضخمة، وإذا كانت قراءة ملف واحد تجرّ معها 19 دالة لا علاقة لها بالأمر فتُلوّث السياق، وإذا ساورك الشك في أن تقاليد كـ “1 file 1 concept” تُحدث فارقاً حقيقياً — فإليك نتيجة قياس ذلك في إطار عمل حقيقي يحمل 23 ألف نجمة.

“ألا تكثر الملفات كثيراً؟”

هذا أكثر سؤال يُطرح على filefunc. ألا يصعب إدارة 186 ملفاً حين تُجزَّأ إلى 626؟

الجواب في Hono. إطار ويب خفيف الوزن يعمل على Cloudflare Workers وDeno وBun وNode.js. أكثر من 23 ألف نجمة، وأكثر من مليون تنزيل أسبوعي على npm. كود إنتاجي موثَّق في الميدان. أعدنا هيكلة هذا الكود باستخدام filefunc. 4419 اختباراً، جميعها اجتازت. (يمكن التحقق منها مباشرةً في فرع park-jun-woo/hono)

الأرقام

المقياسالأصلبعد إعادة الهيكلة
ملفات المصدر186626
إجمالي الأسطر24,65330,244
انتهاكات filefunc3970
اختبارات vitest ناجحة44194419
اختبارات vitest فاشلة44 (عيوب قديمة)
اختبارات vitest متخطّاة3333

تضاعفت الملفات 3.4 مرة. ارتفعت الأسطر بنسبة 23%. انعدمت الانتهاكات من 397 إلى صفر. لم ينكسر اختبار واحد — بل فشلت 4 اختبارات بالضبط كما في الأصل (عيوب كانت موجودة من البداية). جاءت الزيادة البالغة 23% من التعليقات التوضيحية (//ff:func، //ff:what) ومن re-export hub. لم تتغير سطرٌ واحد من المنطق. إعادة هيكلة بنيوية خالصة.

الأساس ليس عدد الملفات بل ‘طول ما يُقرأ’

“لا انتهاكات، 626 ملفاً” هو في الواقع مؤشر وكالة. الهدف الحقيقي لـ filefunc ليس تجزئة الملفات — بل جعل الوكيل حين يقرأ مفهوماً واحداً يقرأ ذلك المفهوم فحسب، من غير إطالة مفرطة. لذا فالرقم الحقيقي الواجب إثباته ليس عدد الانتهاكات بل طول القراءة لكل ملف. قسنا ذلك.

أسطر لكل ملفالأصلبعد إعادة الهيكلة
الوسيط60.017.5 (−71%)
p90305119 (−61%)
الحد الأقصى2,7781,051 (−62%)
نسبة الملفات ≤20 سطراً26%54%

حين يفتح الوكيل مفهوماً واحداً، كان يبتلع في السابق 60 سطراً في المتوسط، والآن يبتلع 18. حتى أسوأ حالة (p90) تراجعت من 305 سطر إلى 120. طول الدوال نفسها لم يتغير (الوسيط 11→12 سطراً) — طبعاً، فنحن لم نُعد كتابة الدوال بل أعدنا ترتيبها. ما تقلّص هو “الكود المحيط الذي يُقرأ إجبارياً لفهم مفهوم واحد”.

لماذا يهم هذا؟ السياق الطويل ليس مجانياً. تُخفق نماذج LLM بشكل منهجي في استرجاع المعلومات المدفونة في منتصف المدخلات الطويلة (Liu et al.، Lost in the Middle، TACL 2023، arXiv:2307.03172). وفي مهام الترميز تنهار الأداء حين يطول السياق — في إحدى المقاييس انخفضت دقة Claude 3.5 Sonnet من 29% إلى 3% (Rando et al.، LongCodeBench، 2025، arXiv:2505.07897). وتقديم الكود مقطَّعاً بوحدات مفاهيمية بدلاً من ملفات كاملة يرفع جودة إكمال الكود (Yusuf et al.، 2025، arXiv:2510.06606). تقليل طول القراءة ليس ذوقاً؛ إنه دفاع عن الدقة.

مشكلة types.ts

لنتجاوز المجرد إلى الملموس. ملف src/types.ts الأصلي في Hono كان يضم أكثر من 20 واجهة ونوعاً.

إذا أراد وكيل الذكاء الاصطناعي أن يجد النوع HonoRequest وقرأ هذا الملف، تبعته 19 نوعاً لا داعي لها. تلوّث في السياق.

بعد إعادة الهيكلة، كل نوع في ملف مستقل. إذا احتجت إلى HonoRequest فقط، تقرأ hono_request.ts وحده. أُبقي على types.ts الأصلي كـ re-export hub للحفاظ على مسارات الاستيراد القائمة.

# الأصل
import { HonoRequest } from './types'  // يجرّ معه 20+ نوع

# بعد إعادة الهيكلة
import { HonoRequest } from './types'  // نفس المسار، نفس السلوك
// داخلياً: types.ts → hono_request.ts re-export

من الخارج لم يتغير شيء. من منظور وكيل الذكاء الاصطناعي تغيّر كل شيء.

من عمق 6 إلى عمق 2

خوارزمية التوجيه في Hono معقدة. كانت Node.search في trie-router تصل إلى عمق تداخل 6.

for → if → if → for → if → if   // عمق 6

هل عمق 6 كود رديء؟ لا. البحث في trie ينطوي بطبيعته على تداخل عميق. لكن لكي يفهم وكيل الذكاء الاصطناعي هذه الدالة، عليه أن يستوعب 6 مستويات من التداخل دفعةً واحدة. وكذلك الإنسان. استخرج filefunc المنطق الداخلي إلى توابع خاصة ودوال سهمية على مستوى الوحدة. العمق 6 → 2. كل قطعة تمتلك تدفقاً تحكمياً واحداً. الخوارزمية الكلية لم تتغير.

# الأصل: search أحادية البنية
Node.search()   // عمق 6، أكثر من 100 سطر

# بعد إعادة الهيكلة: مجزأة
Node.search()           // عمق 2، يختص بالتنسيق فقط
  → matchParam()        // عمق 1، مطابقة المعاملات
  → matchWildcard()     // عمق 1، معالجة أحرف البدل
  → mergeHandlers()     // عمق 1، دمج المعالجات

F1 في TypeScript، والذيل الصادق

القاعدة الجوهرية F1 في filefunc هي “ملف واحد لدالة واحدة”. في Go الأمر بديهي. لكن في TypeScript يُفضي تجزئة الملفات إلى كسر نظام الوحدات؛ حين تُنقل توابع الصنف إلى ملف خارجي يختفي ربط this. لذا يحسب محلل filefunc لـ TypeScript ‏(ts_ast.js) تصريحات function فحسب، دون احتساب دوال الأسهم const. المبدأ هو “ملف واحد لمفهوم واحد”، لا “دالة واحدة نحوياً لكل ملف”.

ينبغي هنا الصدق. هذا النهج فصل الحالات السهلة (الأنواع، المساعدات الفردية) بنظافة، لكنه لم يفصل كل شيء. عند إعادة قياس ما بعد إعادة الهيكلة:

  • 90% من الـ 626 (أي 566 ملفاً) تضم دالة ≤1 — تستوفي “1 ملف 1 مفهوم”. (الأصل كان 70%.)
  • لكن 60 ملفاً (9.6%) لا تزال تضم دالتين أو أكثر. وهذه الملفات تحديداً طويلة — الوسيط لهذه الـ 60 هو 151 سطراً. مثلاً src/utils/url.ts يضم 14 دالة في 319 سطراً.

بمعنى أن أسلوب const السهمي يُجتاز العداد لكن يحقق الهدف جزئياً فحسب. حين تبقى في ملف دوال سهمية متعددة، يظل الوكيل يقرأ مفاهيم عدة حين يفتح ذلك الملف. في اللحظة التي يصبح فيها المقياس هدفاً ينكسر المقياس (Goodhart). ولا يُستثنى filefunc من ذلك — إذ تتركز معظم مخاطر طول القراءة المتبقية في هذا الذيل البالغ 10%. ألا نُعلي من شأن رقم “لا انتهاكات” إلى مرتبة الإجابة النهائية، وأن نقيس ما لم يتحقق بعد — ذلك هو التحقق.

“وما الذي يتحسن فعلاً؟”

قد يُشعر وجود 626 ملفاً الإنسان بعدم الارتياح؛ حين تفتح الدليل تنهمر عليك الملفات. لكن وكيل الذكاء الاصطناعي لا يفتح الأدلة. يستخدم grep.

rg '//ff:func' --glob '*.ts' -l | head -20    # استخراج الملفات المرشحة
rg '//ff:what.*router' --glob '*.ts'            # الدوال المتعلقة بالتوجيه فقط

حين تتوزع الدوال بمعدل 3-4 في كل من الـ 186 ملفاً، يعثر grep على الملف لكن قراءته تجرّ دوالاً زائدة. حين يضم كل ملف من الـ 626 مفهوماً واحداً، يعني ما يجده grep = المفهوم المطلوب. تختفي الخطوة الوسيطة. “تحديد الموقع” في استكشاف الكود بواسطة الوكيل هو عنق الزجاجة لحل المشكلات اللاحقة (Chen et al.، LocAgent، 2025، arXiv:2503.09089)، وfilefunc يجعل هذا الاستكشاف حتمياً بمحاذاة المفاهيم مع حدود الملفات.

هل الوحدة الدالية صواب دائماً؟

لنستعرض الأدلة المعاكسة بأمانة. تجربة ميدانية متحكَّم بها تُفيد بأن “تقطيع الكود بوحدات دالية في RAG للإكمال التلقائي أدنى بـ 3.6–5.6 نقطة مئوية من الاستراتيجيات الأخرى وليس باريتو-أمثل” (Wu et al.، 2026، arXiv:2605.04763). الوحدة الدالية ليست ترياقاً شاملاً.

غير أن هذا حديث عن طبقة مختلفة. تلك التجربة تتناور في سياق الإكمال التلقائي حيث يُقطّع محرك البحث الكود ويدفعه إلى الموجّه. أما filefunc فيعالج وحدة التشغيل التي يختار فيها الوكيل ملفاً ليقرأه مباشرةً. استراتيجية التقطيع (retrieval chunk) ووحدة التشغيل (ملف يفتحه الوكيل) طبقتان مختلفتان. مع ذلك يبقى تصريح هذا التمييز أمراً جوهرياً — “التجزئة مفيدة دائماً” ادعاء مبالَغ فيه لا تقول به filefunc. الادعاء هو “حين تتطابق وحدة القراءة للوكيل مع المفهوم يقصر طول القراءة”، وهذا ما تُظهره الأرقام أعلاه.

القيد حرية

ما تأكد من إعادة هيكلة Hono بـ filefunc شيء واحد.

القيد البنيوي لا يكبّل الكود. بل يُحرّر الاستكشاف.

كثرة الملفات تكلفة. لكن حين يضم كل ملف مفهوماً واحداً فحسب، يقرأ الوكيل بالضبط ما يحتاجه دون أن يتلوث بسياق لا ضرورة له — والقياس الذي يُثبت ذلك هو تراجع طول القراءة من 60 سطراً إلى 18. والإنسان كذلك؛ حين يكون اسم الدالة هو اسم الملف يُصبح الدليل فهرساً.

397 انتهاكاً تحولت إلى صفر، و4419 اختباراً اجتازت مطابقةً للأصل. ويمكن لأي شخص إعادة تشغيل تلك النتيجة من تقرير إعادة الهيكلة في README. هذا هو الدليل على أن “1 file 1 concept” ليس نظرية بل ممارسة حقيقية. بما في ذلك الذيل البالغ 9.6% المتبقي.

مقالات ذات صلة

للاستزادة (خارجي)

  • Effective context engineering for AI agents — Anthropic. يُعيّن “context rot” وميزانية الانتباه المحدودة باعتبارهما المشكلة الجوهرية — نفس الأساس الذي يقوم عليه تقليل السياق غير الضروري في filefunc.
  • Strategies and Tactics for working with Coding Agents — Brian Kihoon Lee. حجة صريحة لتصميم الاستكشاف القائم على grep ومعمارية المعلومات يدوياً — ما يرتبط مباشرةً بتقليد بنية الملف الذي يجعل الوكيل “يقرأ الهدف فحسب”.
  • The Vibes Don’t Scale — Paul Stack. آلية انهيار vibe coding في الأحجام الكبيرة بسبب انجراف المعمارية — وعي المشكلة التي تسعى filefunc إلى حلها: “قواعد الكود الضخمة تكسر الوكيل”.
  • Agentic Engineering Patterns — Simon Willison. أنماط إدارة السياق كـ Context Quarantine/Pruning — توسيع لادعاء agent-operable في filefunc إلى لغة أنماط عملية.
  • Agent Harness Engineering — Addy Osmani. أداء الوكيل يتقرر في البنية التحتية المحيطة لا في النموذج — يُعيد تأطير تقليد بنية الكود باعتباره محوراً من محاور الهارنيس.

المراجع

  • Liu et al. “Lost in the Middle: How Language Models Use Long Contexts” (TACL 2023, arXiv:2307.03172)
  • Rando et al. “LongCodeBench: Evaluating Coding LLMs at 1M Context Windows” (2025, arXiv:2505.07897)
  • Yusuf et al. “Beyond More Context: How Granularity and Order Drive Code Completion Quality” (2025, arXiv:2510.06606)
  • Chen et al. “LocAgent: Graph-Guided LLM Agents for Code Localization” (2025, arXiv:2503.09089)
  • Wu et al. “How Does Chunking Affect Retrieval-Augmented Code Completion? A Controlled Empirical Study” (2026, arXiv:2605.04763)
  • نتائج إعادة الهيكلة: park-jun-woo/hono (filefunc Refactoring Report في README) · التقليد: filefunc
  • الصورة التمثيلية: مولَّدة بالذكاء الاصطناعي (Google Gemini)