وظائف مقابل AOP

البرمجة الموجهة نحو الجانب (AOP) تحظى بشعبية كبيرة. الدافع وراء ذلك موضح جيدًا في مقالة ويكيبيديا المقابلة.

AOP هي أداة رائعة للمفاهيم العالمية الحقيقية مثل التسجيل التي لا تؤثر بشكل مباشر على منطق الكود. ومع ذلك ، تظهر مشاكل AOP عندما يتم استخدامها لمزيد من الأشياء المتعلقة بالأعمال مثل التفويض. يجب أن تكون جوانب التطبيق هذه مرئية بوضوح في التعليمات البرمجية ذات الصلة ، حتى يتمكن المطور من معرفة ما إذا تم تنفيذها بشكل صحيح عند قراءة التعليمات البرمجية المصدر المقابلة. تحل الأطر المستندة إلى AOP عادةً لذلك باستخدام التعليقات التوضيحية للطريقة:

RequireRole (Role.Admin) // الجانب المرئي بوضوح
متعة التحديث USERPermissions (...) {
    // المنطق هنا
}

ومع ذلك ، من وجهة نظر قابلية القراءة ، فإنه لا يختلف كثيرًا عن النهج الوظيفي لنفس المشكلة باستخدام دالة requireRole بدلاً من التعليق التوضيحيRequireRole:

متعة التحديث USERPermissions (...) {
    requireRole (Role.Admin) // يلقي SecurityException
    // المنطق هنا
}

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

وينطبق الشيء نفسه على جوانب أخرى مثل المعاملات. لسوء الحظ ، من المرهق وغير المريح أن يمثل وظيفيًا مفاهيم أكثر تعقيدًا في Java ، مما يخلق شعبية مصطنعة لأطر AOP في نظام Java البيئي.

ليس هذا هو الحال مع Kotlin ، رغم ذلك. في Kotlin ، بدلاً من نهج يشبه Java في المعاملات مع AOP والشروح مثل هذا:

Transactional
متعة التحديث USERPermissions (...) {
    // المنطق هنا
}

إنه قابل للقراءة ونظيف المظهر عند إعادة كتابته بطريقة عملية:

التحديث المرح UserPermissions (...) = المعاملات {
    // المنطق هنا
}

تتمثل ميزة هذا الأسلوب الوظيفي في أنه يمكنك دائمًا Ctrl / Cmd + النقر على إعلان وظيفة المعاملات في IDE الخاص بك ومعرفة ما تفعله بالضبط على الفور ، وهو أمر غير ممكن عادةً مع أي من أطر AOP الشائعة الاستخدام. حتى عندما يتم توفير التنقل إلى الكود المصدري الجانبي بواسطة البرنامج المساعد IDE ، فإن فك تشفير منطقه يتطلب معرفة API و / أو اصطلاحات غنية منفصلة.

لسوء الحظ ، لا يتم استبدال هذا الاستبدال الوظيفي لـ AOP المستند إلى التعليقات التوضيحية في Kotlin على الفور بالحالة عندما يتم تطبيق جوانب متعددة على نفس الوظيفة مثل الأقواس المتعرجة وتبدأ المسافة البادئة في التراكم:

التحديث المرح UserPermissions (...) = تسجيل
    المعاملات {
        // المنطق هنا
    }
}

يتمثل الحل البديل في إنشاء وظيفة ذات ترتيب عالي مدمج للحفاظ على موقع استخدام الجوانب المتعددة نظيفًا:

التحديث المرح UserPermissions (…) = logTransactional {
    // المنطق هنا
}

عيب آخر للنهج الوظيفي هو أن جوانب مثل التسجيل تحتاج إلى الوصول إلى معلمات الطريقة. عادة ما تكون متاحة مباشرة في أطر AOP التقليدية عبر واجهات برمجة التطبيقات الخاصة ، ولكن وظائف الأسهم Kotlin لا يمكن الوصول إليها بسهولة. لذلك ، من أجل تمثيل جانب التسجيل الحقيقي في الواقع بطريقة عملية بحتة ، لا يزال يتعين على المرء كتابة قدر كبير من كود لوحة الغلاية:

updateUserPermissions متعة (params: Params) =
    تسجيل الدخول ("updateUserPermissions ($ params)") {
        // المنطق هنا
    }

لا يزال هذا الاعتبار يجعل AOP أداة اختيار للتسجيل عندما تحتاج حقًا إلى امتلاكها عالميًا ومتسق في التطبيق الخاص بك ، لكنني أعتقد أن استخدام AOP لجوانب مثل التخويل والمعاملات يعد إساءة ، بالنظر إلى التجريدات الوظيفية الغنية المتوفرة في Kotlin . وظائف التعامل مع هذه الجوانب بشكل أفضل وأنظف.

في الختام ، أقول إن التحسينات الإضافية في التجريدات الوظيفية لتوفير بديل أفضل عن AOP يمكن أن تكون ناقلًا واعداً للتطور المستقبلي للغة Kotlin. عادةً ما تكون أطر عمل AOP المستندة إلى Java خاصة بـ JVM ويُنظر إليها على أنها بعض السحر المعتم ، في حين أن التجريدات الوظيفية لـ Kotlin هي بالفعل منصات مشتركة وشفافة للمستخدم.