إن كتابة شيفرة برمجية جميلة ومصممة بشكل جيد وحسنة المظهر ليست بالصعوبة التي تبدو عليها. يتطلب الأمر القليل من الجهد للتعرف على القواعد الرئيسية واستخدامها فقط في شفرتك البرمجية. وليس من الضروري أن يكون كل شيء دفعة واحدة، ولكن كلما شعرت بالراحة في شيء ما حاول التفكير في شيء آخر وهكذا.
بناء كود متين وليس غبيًا
لنبدأ بتقديم القواعد الأساسية التي تسمى SOLID. وهو مصطلح يصف مجموعة من مبادئ التصميم من أجل حسن الكود التي اخترعها روبرت سي مارتن وكيف تسير الأمور:
S تعني مبدأ المسؤولية الواحدة
ينص على أنه يجب أن يكون للفصل سبب واحد فقط للتغيير. بمعنى آخر، يجب أن يكون للفصل وظيفة واحدة فقط للقيام بها، لذا يجب أن نتجنب كتابة فصول كبيرة ذات مسؤوليات كثيرة. إذا كان على صفنا أن يقوم بالعديد من المهام، فيجب تفويض كل منها إلى مهام منفصلة.
صنف الإخطار
تعريف التهيئة (بارامز)
@بارامز = بارامز
نهاية
ديف استدعاء
EmailSender.new(message).call.call
إنهاء
خاص
ديف رسالة
# بعض التنفيذ
النهاية
النهاية
O يعني مبدأ الفتح/الإغلاق
تنص على أنه يجب أن تكون قادرًا على توسيع سلوك الفصول، دون تعديلها. بعبارة أخرى، يجب أن يكون من السهل توسيع الصنف دون إجراء أي تعديلات عليه. يمكننا تحقيق ذلك على سبيل المثال باستخدام نمط الاستراتيجية أو المزخرفات.
صنف الإخطار
تعريف التهيئة (البارامات، المرسل)
بارامز = بارامز
المرسل = المرسل
نهاية
ديف استدعاء
المرسل. استدعاء الرسالة
إنهاء
خاص
تعريف الرسالة
# بعض التنفيذ
النهاية
النهاية
فئة مرسل البريد الإلكتروني
ديف استدعاء(رسالة)
# بعض التنفيذ
النهاية
النهاية
صنف مرسل الرسائل القصيرة
تعريف استدعاء(رسالة)
# بعض التنفيذ
إنهاء
النهاية
مع هذا التصميم، من الممكن إضافة مرسلين جدد دون تغيير أي رمز.
L يعني مبدأ الإحلال ليسكوف
ينص على أن الفئات المشتقة يجب أن تكون قابلة للاستبدال بفئاتها الأساسية. وبعبارة أخرى، يجب أن يكون من السهل استبدال الفئات التي تأتي من نفس السلف بفئات أخرى سليفة.
فئة المسجل {
معلومات (رسالة) {
console.info(this._prefixFor('info) + message)
}
خطأ (رسالة، خطأ) { {
خطأ (console.error(this._prefixFor('error) + message)
إذا (خطأ) {
console.error(err)
}
}
_ prefixFor (النوع) {
// بعض التنفيذ
}
}
صنف ScepticLogger يمد المسجل {
معلومات (رسالة) {
super.info(message)
console.info(هذا._prefixFor('info)) + 'وهذا كل ما لدي لأقوله.')
}
خطأ (رسالة، خطأ) {
super.error(message, err)
خطأ (console.error(this._prefixFor('error)) + 'مشكلة كبيرة!')
}
}
يمكننا بسهولة استبدال اسم الفصل، لأن كلاهما له نفس واجهة الاستخدام بالضبط.
أعني مبدأ الفصل بين الواجهات
ينص على أنه يجب عليك إنشاء واجهات دقيقة الحبيبات الخاصة بالعميل. ما هي الواجهة؟ إنها طريقة مقدمة لاستخدام جزء من الكود. لذا يمكن أن يكون انتهاك هذه القاعدة على سبيل المثال صنفًا يحتوي على عدد كبير جدًا من الطرق بالإضافة إلى طريقة ذات خيارات وسيطة كثيرة جدًا. من الأمثلة الجيدة لتصور هذا المبدأ هو نمط المستودع، ليس فقط لأننا غالبًا ما نضع الكثير من الطرق في صنف واحد ولكن أيضًا هذه الطرق معرضة لخطر قبول الكثير من الوسيطات.
# ليس أفضل مثال هذه المرة
صنف NotificationRepository
تعريف find_all_by_ids(ids:, info:)
الإشعارات = Notification.where(id: ids)
info ? notifications.where(النوع: ::info) : الإخطارات
النهاية
النهاية
# وأفضل
فئة NotificationRepository
تعريف find_all_by_ids(ids:)
Notification.where(id: ids)
نهاية
تعريف find_all_by_id_info(ids:)
find_all_ by_ids(ids).where(النوع: ::info)
النهاية
النهاية
د تعني مبدأ انعكاس التبعية
ينص على أنه يجب أن تعتمد على التجريدات وليس على التجسيدات. بعبارة أخرى، لا يجب أن تعتمد الفئة التي تستخدم فئة أخرى على تفاصيل تنفيذها، كل ما هو مهم هو واجهة المستخدم.
صنف الإخطار
تعريف التهيئة (البارامات، المرسل)
بارامز = بارامز
المرسل = المرسل
نهاية
ديف استدعاء
المرسل. استدعاء الرسالة
إنهاء
خاص
تعريف الرسالة
# بعض التنفيذ
النهاية
النهاية
كل ما نحتاج إلى معرفته عن الكائن المرسل هو أنه يعرض طريقة "استدعاء" التي تتوقع الرسالة كوسيطة.
ليس أفضل كود على الإطلاق
من المهم جدًا أيضًا معرفة الأشياء التي يجب تجنبها تمامًا أثناء كتابة التعليمات البرمجية، لذا إليك مجموعة أخرى من المبادئ الغبية التي تجعل التعليمات البرمجية غير قابلة للصيانة وصعبة الاختبار وإعادة الاستخدام.
س تعني "سينجلتون
غالبًا ما تعتبر الأنماط المنفردة أنماطًا مضادة ويجب تجنبها بشكل عام. لكن المشكلة الرئيسية في هذا النمط هو أنه نوع من التذرع بالمتغيرات/الأساليب العامة ويمكن أن يفرط المطورون في استخدامه بسرعة.
T تعني اقتران محكم
يتم الاحتفاظ بها عندما يتطلب التغيير في إحدى الوحدات النمطية تغييرات في أجزاء أخرى من التطبيق أيضًا.
U تعني عدم القابلية للاختبار
إذا كانت شفرتك البرمجية جيدة، فيجب أن تبدو كتابة الاختبارات ممتعة وليست كابوسًا.
P تعني التحسين السابق لأوانه
كلمة قبل الأوان هي المفتاح هنا، إذا لم تكن بحاجة إليها الآن فهي مضيعة للوقت. من الأفضل التركيز على شيفرة جيدة ونظيفة بدلًا من التركيز على بعض التحسينات الجزئية - والتي تتسبب عمومًا في تعقيد الشيفرة.
أعني التسمية غير الوصفية
إنه أصعب شيء في كتابة التعليمات البرمجية الجيدة، ولكن تذكر أنه ليس فقط لبقية الفريق ولكن أيضًا من أجل مستقبلك أيضًا، لذا عاملني بشكل صحيح 🙂 من الأفضل أن تكتب اسمًا طويلًا لطريقة ما ولكنه يقول كل شيء، من أن تكتب اسمًا قصيرًا ومبهمًا.
د تعني الازدواجية
السبب الرئيسي للازدواجية في الشيفرة البرمجية هو اتباع مبدأ الاقتران المحكم. إذا كانت شفرتك البرمجية مقترنة بإحكام، فلا يمكنك إعادة استخدامها وتظهر شيفرة مكررة، لذا اتبع مبدأ الاقتران المحكم ولا تكرر.
الأمر ليس مهماً في الوقت الحالي
أود أيضًا أن أذكر شيئين مهمين جدًا غالبًا ما يتم إغفالهما. يجب أن تكون قد سمعت عن الأول - إنه YAGNI وهو ما يعني: لن تحتاج إليه. من وقت لآخر ألاحظ هذه المشكلة أثناء القيام بمراجعة الشيفرة أو حتى كتابة الشيفرة البرمجية الخاصة بي، ولكن يجب أن نغير تفكيرنا في تنفيذ ميزة ما. يجب أن نكتب الكود الذي نحتاجه بالضبط في هذه اللحظة بالذات، وليس أكثر أو أقل. يجب أن نضع في اعتبارنا أن كل شيء يتغير بسرعة كبيرة (خاصةً متطلبات التطبيق)، لذا لا فائدة من التفكير في أن شيئًا ما سيأتي يومًا ما في متناول اليد. لا تضيع وقتك.
أنا لا أفهم
والشيء الأخير، وهو ليس واضحًا حقًا على ما أفترض، وقد يكون مثيرًا للجدل تمامًا للبعض، إنه رمز وصفي. لا أقصد بذلك فقط استخدام الأسماء الصحيحة للفئات أو المتغيرات أو الطرق. من الجيد حقًا أن تكون الشيفرة بأكملها قابلة للقراءة من النظرة الأولى. ما هو الغرض من الكود القصير جدًا في حين أنه مبهم بقدر ما يمكن أن يكون، ولا أحد يعرف ما يفعله، باستثناء الشخص الذي كتبه؟ في رأيي، من الأفضل كتابة بعض الحروفبيانات الحالةشيء آخر أكثر من كلمة واحدة ثم جلس بالأمس يتساءل: انتظر ما هي النتيجة، وكيف حدث ذلك، وهكذا.
const params = [
{
الأفلام: [
{ العنوان: 'The Shawshank Redemption'},
{ العنوان: { العنوان: "One Flew Over the Cuckoo's Nest" }
]
},
{
الأفلام: [
{ العنوان: { العنوان: 'Saving Private Ryan' },
{ العنوان: 'Pulp Fiction'}، [ العنوان: 'Pulp Fiction'},
{ العنوان: { العنوان: "The Shawshank Redemption" },
]
}
]
// الاقتراح الأول
دالة عناوين الأفلام الفريدة من (params) {
العناوين = بارامز
.map(param => param.movies)
.reduce((prev, nex) => prev.concat(next)))
.map(movie => movie.title)
إرجاع [...مجموعة جديدة (عناوين)]
}
// الاقتراح الثاني
دالة عناوين الأفلام الفريدة من (بارامز) {
العناوين = {}
params.forEach(param => { {
param.films.forEach(movie => عناوين[movie.title] = true)
})
إرجاع Object.keys(العناوين)
}
خلاصة القول
كما ترى، هناك الكثير من القواعد التي يجب أن تتذكرها، ولكن كما ذكرت في البداية فإن كتابة كود جيد هي مسألة وقت. إذا بدأت بالتفكير في تحسين واحد لعاداتك في البرمجة فسترى أن قاعدة جيدة أخرى ستتبعها، لأن كل الأشياء الجيدة تنشأ من نفسها تماماً مثل الأشياء السيئة.
اقرأ المزيد:
ما هو Ruby on Jets وكيفية إنشاء تطبيق باستخدامه؟
Vuelendar. مشروع كودست جديد يستند إلى Vue.js
تقرير كودست الأسبوعي لأفضل المقالات التقنية. بناء برمجيات لـ 50 مليون مقبس متزامن (10)