من PHP إلى Go: ما استغرق مني أطول وقت لإعادة صياغة تفكيري
كتبتُ بلغة PHP لمدة سبع سنوات. استخدمتُ Laravel لخمس منها. عندما انتقلتُ إلى Go لقيادة عملية انتقال من بنية Laravel monolith (الكتلة الواحدة) إلى microservices (الخدمات المصغرة)، لم آتِ ومعي دليل تعليمي، بل جئتُ مع عقد من العادات المكتسبة في PHP.
كان تعلم القواعد البرمجية (syntax) سهلاً؛ يمكنك قراءة Go في فترة ما بعد الظهر. الجزء الصعب كان التخلص من الطريقة التي كنت أفكر بها في الكود.
إليكم التحولات الذهنية التي استغرق مني إتقانها شهوراً:
معالجة الأخطاء (Error Handling) في PHP، كنت أستخدم try/catch. غالباً ما كانت الأخطاء تنتقل بشكل غير مرئي إلى معالج عام (global handler). أما في Go، فالأخطاء هي "قيم" (values). تعيد الدالة الخطأ كآخر قيمة لها، ويجب عليك معالجته في نفس المكان. في البداية، شعرتُ أن هذا عمل إضافي، لكنني أدركت لاحقاً أنه يجعل الفشل مرئياً. فعندما تفشل خدمة ما، تعمل رسالة الخطأ كمسار من فتات الخبز (breadcrumb trail)، حيث تخبرك بالضبط أين حدث الفشل دون الحاجة إلى تتبع مكدس (stack trace) ضخم.
الذاكرة والحالة (Memory and State) تستخدم PHP نموذج "عدم المشاركة" (shared-nothing model)؛ حيث يبدأ كل طلب بصفحة بيضاء جديدة. وتكون تسريبات الذاكرة (memory leaks) أقل أهمية لأن العملية تنتهي بعد انتهاء الطلب. أما Go فمختلفة، فالعملية تظل حية لآلاف الطلبات. وهذا يعني أن المتغير على مستوى الحزمة (package-level variable) يتم مشاركته عبر كل طلب. إذا حاول طلبان الكتابة في
mapفي نفس الوقت، سينهار البرنامج بالكامل. في Go، أنت المسؤول عن التزامن (concurrency)، ويجب عليك استخدام أدوات مثلrace detectorللحفاظ على سلامة العمليات.دور السياق (The Role of Context) في PHP، يمثل الطلب (request) الحد الفاصل؛ فعندما ينتهي الطلب، يتوقف كل شيء. أما في Go، فلا شيء يتوقف تلقائياً. إذا انقطع اتصال العميل، فقد تستمر الـ
goroutinesالخاصة بك في العمل وتستهلك الموارد بلا فائدة. يجب عليك استخدامcontext.Contextلتمرير إشارات الإلغاء عبر الكود الخاص بك. إنه العمود الفقري الذي يحافظ على صحة خدمتك تحت ضغط الأحمال العالية.التركيب بدلاً من الوراثة (Composition Over Inheritance) يعتمد Laravel بشكل كبير على توسيع الفئات الأساسية (extending base classes)، حيث تضيف الميزات عن طريق وراثة السلوك. أما Go فلا تدعم وراثة الفئات (class inheritance)، بل تستخدم الواجهات (interfaces) التي يتم استيفاؤها بشكل ضمني. أنت تحدد ما تحتاجه في المكان الذي تستخدمه فيه، مما يجعل الكود أسهل في الاختبار والاستبدال. كان عليّ التخلص من غريزتي في توسيع كل شيء لأتمكن من كتابة كود Go جيد.
الوضوح بدلاً من الذكاء المفرط (Clarity Over Cleverness) تسمح PHP باستخدام "الطرق السحرية" (magic methods) والأنواع الديناميكية (dynamic typing)، مما يتيح لك كتابة كود ذكي ومعبر. أما Go فهي "مملة" عن عمد؛ حيث يجبرك المترجم (compiler) على استخدام تنسيق قياسي ويمنع المتغيرات غير المستخدمة. في البداية، شعرتُ أن هذا قيد، لكنني الآن أقدر ذلك. Go مصممة لتناسب الشخص الذي يقرأ الكود، وليس الشخص الذي يكتبه. فالكود "الممل" يسهل إصلاحه في الثانية صباحاً أثناء وقوع حادث تقني.
الجزء الصعب في تعلم لغة جديدة ليس القواعد البرمجية الجديدة، بل الافتراضات القديمة التي تحملها معك.
Source: https://dev.to/econ__11/from-php-to-go-what-took-me-longest-to-rewire-2nfn
