كتابة شفرة جافا سكريبت نظيفة وقابلة للتطوير: 12 نصيحة

جافا سكريبت هي من الويب في وقت مبكر. في البداية ، كُتبت نصوص بسيطة عليها "تنشط" صفحات المواقع. أصبح JS الآن لغة برمجة كاملة يمكن استخدامها حتى لتطوير مشاريع من جانب الخادم.

تعتمد تطبيقات الويب الحديثة بشكل كبير على JavaScript. وينطبق هذا بشكل خاص على التطبيقات ذات الصفحة الواحدة (التطبيق ذو الصفحة الواحدة ، واس). بفضل ظهور المكتبات والأطر مثل React و Angular و Vue ، أصبح JavaScript أحد العناصر الأساسية لتطبيقات الويب.



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

يريد مؤلف المقال ، الذي ننشر ترجمته اليوم ، مشاركة النصائح حول كتابة شفرة جافا سكريبت البحتة. يقول المقال هو لمبرمجي JS من أي مستوى المهارة. ولكن سيكون مفيدًا بشكل خاص لأولئك الذين لديهم دراية JavaScript على الأقل في المستوى المتوسط.

1. رمز العزلة


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

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

2. انهيار رمز في وحدات


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

 function add(a, b) {   return a + b  } function subtract(a, b) {   return a - b  } module.exports = {   add,   subtract } 

وإليك كيفية استخدام هذه الوحدة في ملف آخر (دعنا نسميها index.js ):

 const { add, subtract } = require('./calculations') console.log(subtract(5, add(3, 2)) 

يمكن إعطاء مطوري التطبيقات Frontend التوصيات التالية. لتصدير أهم الكيانات المعلنة في الوحدة ، استخدم خيارات التصدير الافتراضية. بالنسبة للكيانات الثانوية ، يمكنك استخدام التصدير المحدد.

3. استخدام معلمات متعددة الوظائف بدلا من كائن واحد مع المعلمات


عند التصريح عن وظيفة ، يجب أن تسعى جاهدة لاستخدام العديد من المعلمات ، بدلا من كائن واحد مع المعلمات. فيما يلي بعض الأمثلة:

 //  function displayUser(firstName, lastName, age) {   console.log(`This is ${firstName} ${lastName}. She is ${age} years old.`) } //  function displayUser(user) {   console.log(`This is ${user.firstName} ${user.lastName}. She is ${user.age} years old.`) } 

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

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

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

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

4. إعادة الهيكلة


إعادة الهيكلة هي آلية مفيدة ظهرت في ES6. يسمح لك باستخراج الحقول المحددة من الكائنات وكتابتها على الفور للمتغيرات. يمكن استخدامه عند العمل مع الكائنات والوحدات النمطية:

 //    const { add, subtract } = require('./calculations') 

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

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

 function logCountry({name, code, language, currency, population, continent}) {   let msg = `The official language of ${name} `   if(code) msg += `(${code}) `   msg += `is ${language}. ${population} inhabitants pay in ${currency}.`   if(contintent) msg += ` The country is located in ${continent}` } logCountry({   name: 'Germany',   code: 'DE',   language 'german',   currency: 'Euro',   population: '82 Million', }) logCountry({   name: 'China',   language 'mandarin',   currency: 'Renminbi',   population: '1.4 Billion',   continent: 'Asia', }) 

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

بالمناسبة ، يمكن أيضًا إعادة الهيكلة عند العمل مع المكونات الوظيفية لـ React.

5. تعيين القيم الافتراضية للمعلمات وظيفة


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

 function logCountry({   name = 'United States',   code,   language = 'English',   currency = 'USD',   population = '327 Million',   continent, }) {   let msg = `The official language of ${name} `   if(code) msg += `(${code}) `   msg += `is ${language}. ${population} inhabitants pay in ${currency}.`   if(contintent) msg += ` The country is located in ${continent}` } logCountry({   name: 'Germany',   code: 'DE',   language 'german',   currency: 'Euro',   population: '82 Million', }) logCountry({   name: 'China',   language 'mandarin',   currency: 'Renminbi',   population: '1.4 Billion',   continent: 'Asia', }) 

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

6. لا تقم بتمرير البيانات غير الضرورية إلى الوظائف


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

7. الحد من عدد الخطوط في الملفات والحد الأقصى لمستوى تداخل الكود


لقد رأيت ملفات كبيرة مع رمز البرنامج. كبير جدا وكان بعض أكثر من 3000 خطوط. في مثل هذه الملفات يكون من الصعب للغاية التنقل.

نتيجة لذلك ، يوصى بتحديد حجم الملفات المقاسة في سطور التعليمات البرمجية. عادة ما أسعى للتأكد من أن حجم ملفاتي لا يتجاوز 100 سطر. في بعض الأحيان ، عندما يكون من الصعب تقسيم منطق معين إلى أجزاء صغيرة ، فإن أحجام ملفاتي تصل إلى 200-300 سطر. ونادرا جدا ، يصل حجمها إلى 400 خط. الملفات التي تتجاوز هذا الحد يصعب قراءتها وصيانتها.

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

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

ربما تساعد متابعة هذه التوصيات في تطبيق قواعد ESLint linter المناسبة.

8. استخدام الأدوات لتنسيق التعليمات البرمجية تلقائيا


عند العمل على مشاريع جافا سكريبت في فريق ، تحتاج إلى تطوير دليل واضح لأسلوب وتنسيق الكود. يمكنك أتمتة تنسيق التعليمات البرمجية باستخدام ESLint. يقدم هذا linter المطور مجموعة كبيرة من القواعد القابلة للتخصيص. يوجد أمر eslint --fix يمكنه إصلاح بعض الأخطاء.

ومع ذلك ، أوصي باستخدام Prettier بدلاً من ESLint لأتمتة تنسيق التعليمات البرمجية. مع هذا النهج ، قد لا يضطر المطور للقلق بشأن تنسيق التعليمات البرمجية. انه يحتاج فقط لكتابة برامج الجودة. ستبدو جميع الشفرات التي يتم تنسيقها تلقائيًا باستخدام مجموعة واحدة من القواعد متسقة.

9. استخدام أسماء متغير مصممة تصميما جيدا


يجب أن يعكس اسم المتغير محتوياته بشكل مثالي. فيما يلي بعض الإرشادات لتحديد أسماء المتغيرات المفيدة.

. وظائف


عادة ما تقوم الوظائف بنوع من العمل. عندما يتحدث الناس عن الأفعال ، يستخدمون الأفعال. على سبيل المثال - تحويل (تحويل) أو عرض (عرض). يوصى بتكوين أسماء الدوال بحيث تبدأ فعلًا. على سبيل المثال ، convertCurrency أو displayUser .

▍Massivy


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

 const students = ['Eddie', 'Julia', 'Nathan', 'Theresa'] 

القيم المنطقية


أسماء المتغيرات المنطقية منطقية لتبدأ بـ أو has . هذا يجعلهم أقرب إلى الإنشاءات المتوفرة في اللغة العادية. على سبيل المثال ، إليك السؤال: "هل هذا الشخص معلم؟" يمكن أن يكون الجواب على هذا "نعم" أو "لا". يمكنك أن تفعل الشيء نفسه عن طريق تحديد أسماء المتغيرات المنطقية:

 const isTeacher = true //  false 

passed معلمات الوظائف التي تم تمريرها إلى أساليب الصفيف القياسية


فيما يلي بعض الأساليب القياسية لصفيف JavaScript: forEach ، map ، reduce ، filter . أنها تسمح لك لأداء بعض الإجراءات مع المصفوفات. يتم تمرير وظائف تصف العمليات على المصفوفات. رأيت عدد المبرمجين الذين يقومون ببساطة بتمرير المعلمات بأسماء مثل el أو element لمثل هذه الوظائف. على الرغم من أن هذا النهج يحرر المبرمج من التفكير في تسمية مثل هذه المعلمات ، فمن الأفضل أن ندعو إليها بناءً على البيانات التي تظهر فيها. على سبيل المثال:

 const cities = ['Berlin', 'San Francisco', 'Tel Aviv', 'Seoul'] cities.forEach(function(city) { ... }) 

▍ معرفات


غالبًا ما يحدث أن يحتاج مبرمج إلى العمل مع معرفات مجموعات أو كائنات بيانات معينة. إذا كانت هذه المعرّفات متداخلة ، فلا يجب القيام بأي شيء خاص بها. على سبيل المثال ، عند العمل مع MongoDB ، أقوم عادةً بتحويل _id إلى id قبل إرجاع الكائن إلى تطبيق الواجهة الأمامية. عند استخراج المعرفات من الكائنات ، يوصى بتكوين أسمائهم عن طريق تعيين نوع الكائن قبل id . على سبيل المثال:

 const studentId = student.id //  const { id: studentId } = student //    

يعمل استثناء لهذه القاعدة مع مراجع MongoDB في النماذج. في مثل هذه الحالات ، يوصى بتسمية الحقول وفقًا للنماذج المشار إليها. هذا ، عند ملء المستندات التي توجد بها روابط في الحقول ، سيسمح بالحفاظ على الشفرة نظيفة وموحدة:

 const StudentSchema = new Schema({   teacher: {       type: Schema.Types.ObjectId,       ref: 'Teacher',       required: true,   },   name: String,   ... }) 

10. استخدام متزامن / انتظار بناء حيثما كان ذلك ممكنا.


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

11. الإجراء لاستيراد الوحدات


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

 //    import React from 'react' import styled from 'styled-components' //  import Store from '~/Store // ,    import Button from '~/components/Button' //   import { add, subtract } from '~/utils/calculate' //  import Intro from './Intro' import Selector from './Selector' 

هذا المثال يعتمد على React. لن يكون من الصعب نقل الفكرة نفسها إلى أي بيئة تطوير أخرى.

12. تجنب استخدام console.log


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

نتيجة لذلك ، يمكننا القول أنه من الممكن استخدام console.log لأغراض التصحيح ، وفي الحالات التي يتم فيها التخطيط لأوامر التسجيل لاستخدامها في مشاريع العمل ، يكون من المنطقي اللجوء إلى المكتبات المتخصصة. من بينها loglevel و winston . بالإضافة إلى ذلك ، يمكن استخدام ESLint لمكافحة أوامر التسجيل غير الضرورية. هذا يسمح بالبحث الشامل وإزالة هذه الأوامر.

النتائج


يقول مؤلف هذه المادة إن كل شيء تحدث عنه هنا يساعده كثيرًا في الحفاظ على نظافة وقاعدة التدرج في مشاريعه. نأمل أن تجد هذه النصائح مفيدة.

أعزائي القراء! ما الذي يمكنك إضافته إلى النصائح الـ 12 هنا لكتابة رمز JS نظيف وقابل للتطوير؟

Source: https://habr.com/ru/post/ar452562/


All Articles