إرشادات لكتابة رمز JavaScript النظيف

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



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

أسئلة كود و WTF


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

عند طرح الأسئلة على WTF حول رمز شخص آخر ، يسأل المبرمجون أنفسهم ما هو (WTF هو هذا؟) ، ما الذي حاول مؤلف الكود فعله (هل فعلت WTF هنا؟) ، لماذا هذا أو ذاك موجود في الكود (WTF هو هذا ل؟)

فيما يلي صورة تفيد أن المؤشر الموثوق الوحيد لجودة الشفرة هو عدد أسئلة WTF في الدقيقة.


على اليسار هو رمز جيد. إلى اليمين سيئة

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

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

1. الشيكات المساواة صارمة


حاول استخدام === بدلاً من == .

 //     == -       .     ,   ,   ,   -    . 0 == false // true 0 === false // false 2 == "2" // true 2 === "2" // false //  const value = "500"; if (value === 500) { console.log(value); //     } if (value === "500") { console.log(value); //    } 

2. المتغيرات


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

 let daysSLV = 10; let y = new Date().getFullYear(); let ok; if (user.age > 30) { ok = true; } 

حسن:

 const MAX_AGE = 30; let daysSinceLastVisit = 10; let currentYear = new Date().getFullYear(); ... const isUserOlderThanAllowed = user.age > MAX_AGE; 

لا حاجة لإضافة كلمات إضافية إلى أسماء المتغيرات غير اللازمة.

الفقراء:

 let nameValue; let theProduct; 

حسن:

 let name; let product; 

لا ينبغي عليك إجبار أي شخص يقرأ الكود على أن يتذكر البيئة التي أعلن فيها المتغير.

الفقراء:

 const users = ["John", "Marco", "Peter"]; users.forEach(u => { doSomething(); doSomethingElse(); // ... // ... // ... // ... //    ,    WTF- "   `u`?" register(u); }); 

حسن:

 const users = ["John", "Marco", "Peter"]; users.forEach(user => { doSomething(); doSomethingElse(); // ... // ... // ... // ... register(user); }); 

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

الفقراء:

 const user = { userName: "John", userSurname: "Doe", userAge: "28" }; ... user.userName; 

حسن:

 const user = { name: "John", surname: "Doe", age: "28" }; ... user.name; 

3. وظائف


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

الفقراء:

 function notif(user) { //  } 

حسن:

 function notifyUser(emailAddress) { //  } 

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

الفقراء:

 function getUsers(fields, fromDate, toDate) { //  } 

حسن:

 function getUsers({ fields, fromDate, toDate }) { //  } getUsers({ fields: ['name', 'surname', 'email'], fromDate: '2019-01-01', toDate: '2019-01-18' }) 

استخدم الوسائط الافتراضية ، مما يعطيها الأفضلية على التركيبات الشرطية.

الفقراء:

 function createShape(type) { const shapeType = type || "cube"; // ... } 

حسن:

 function createShape(type = "cube") { // ... } 

وظيفة يجب أن تحل مشكلة واحدة. نسعى جاهدين للتأكد من أن وظيفة واحدة لا تؤدي العديد من الإجراءات.

الفقراء:

 function notifyUsers(users) { users.forEach(user => {   const userRecord = database.lookup(user);   if (userRecord.isVerified()) {     notify(user);   } }); } 

حسن:

 function notifyVerifiedUsers(users) { users.filter(isUserVerified).forEach(notify); } function isUserVerified(user) { const userRecord = database.lookup(user); return userRecord.isVerified(); } 

استخدم Object.assign لتعيين خصائص الكائنات بشكل افتراضي.

الفقراء:

 const shapeConfig = { type: "cube", width: 200, height: null }; function createShape(config) { config.type = config.type || "cube"; config.width = config.width || 250; config.height = config. height || 250; } createShape(shapeConfig); 

حسن:

 const shapeConfig = { type: "cube", width: 200 //   'height'   }; function createShape(config) { config = Object.assign(   {     type: "cube",     width: 250,     height: 250   },   config ); ... } createShape(shapeConfig); 

لا تستخدم الأعلام كمعلمات. استخدامها يعني أن الوظيفة تؤدي إجراءات أكثر مما يجب أن تؤديه.

الفقراء:

 function createFile(name, isPublic) { if (isPublic) {   fs.create(`./public/${name}`); } else {   fs.create(name); } } 

حسن:

 function createFile(name) { fs.create(name); } function createPublicFile(name) { createFile(`./public/${name}`); } 

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

الفقراء:

 Array.prototype.myFunc = function myFunc() { //  }; 

حسن:

 class SuperArray extends Array { myFunc() {   //  } } 

4. الانشاءات الشرطية


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

الفقراء:

 function isUserNotBlocked(user) { //  } if (!isUserNotBlocked(user)) { //  } 

حسن:

 function isUserBlocked(user) { //  } if (isUserBlocked(user)) { //  } 

استخدم النموذج المختصر للإنشاءات الشرطية. ربما تبدو هذه التوصية تافهة ، لكن تجدر الإشارة إلى ذلك. استخدم هذه الطريقة فقط للمتغيرات المنطقية ، وإذا كنت متأكدًا من أن قيمة المتغير لن تكون undefined أو null .

الفقراء:

 if (isValid === true) { // - ... } if (isValid === false) { // - ... } 

حسن:

 if (isValid) { // - ... } if (!isValid) { // - ... } 

تجنب الإنشاءات المنطقية كلما أمكن ذلك. استخدم تعدد الأشكال والميراث بدلاً من ذلك.

الفقراء:

 class Car { // ... getMaximumSpeed() {   switch (this.type) {     case "Ford":       return this.someFactor() + this.anotherFactor();     case "Mazda":       return this.someFactor();     case "McLaren":       return this.someFactor() - this.anotherFactor();   } } } 

حسن:

 class Car { // ... } class Ford extends Car { // ... getMaximumSpeed() {   return this.someFactor() + this.anotherFactor(); } } class Mazda extends Car { // ... getMaximumSpeed() {   return this.someFactor(); } } class McLaren extends Car { // ... getMaximumSpeed() {   return this.someFactor() - this.anotherFactor(); } } 

5. فصول ES


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

الفقراء:

 const Person = function(name) { if (!(this instanceof Person)) {   throw new Error("Instantiate Person with `new` keyword"); } this.name = name; }; Person.prototype.sayHello = function sayHello() { /**/ }; const Student = function(name, school) { if (!(this instanceof Student)) {   throw new Error("Instantiate Student with `new` keyword"); } Person.call(this, name); this.school = school; }; Student.prototype = Object.create(Person.prototype); Student.prototype.constructor = Student; Student.prototype.printSchoolName = function printSchoolName() { /**/ }; 

حسن:

 class Person { constructor(name) {   this.name = name; } sayHello() {   /* ... */ } } class Student extends Person { constructor(name, school) {   super(name);   this.school = school; } printSchoolName() {   /* ... */ } } 

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

الفقراء:

 class Person { constructor(name) {   this.name = name; } setSurname(surname) {   this.surname = surname; } setAge(age) {   this.age = age; } save() {   console.log(this.name, this.surname, this.age); } } const person = new Person("John"); person.setSurname("Doe"); person.setAge(29); person.save(); 

حسن:

 class Person { constructor(name) {   this.name = name; } setSurname(surname) {   this.surname = surname;   //  this           return this; } setAge(age) {   this.age = age;   //  this           return this; } save() {   console.log(this.name, this.surname, this.age);   //  this           return this; } } const person = new Person("John")   .setSurname("Doe")   .setAge(29)   .save(); 

6. ما هو الأفضل عدم القيام به


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

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

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

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


في بعض الأحيان يشبه الكود الخاص بي هذا الشرفة. لا أعرف المهمة التي يحلها ، لكني أخشى التخلص منه.

النتائج


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

في كثير من الأحيان ، ننشر مواد عن مشكلة كتابة شفرة JavaScript عالية الجودة. إذا كنت مهتمًا بهذا الموضوع ، فإليك بعض الروابط.


نأمل أن يساعدك ما تعلمته من خلال قراءة هذه المقالة وما يمكنك العثور عليه في المنشورات الأخرى في سعيكم لكتابة شفرة JavaScript نظيفة.

أعزائي القراء! هل سبق لك أن طرحت أسئلة WTF أثناء قراءة رمز شخص آخر؟



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


All Articles