Blog#45: Clean Code Javascript 😊 (Series: Bí kíp Javascript – PHẦN 37)

Mình là TUẤN hiện đang là một Full-stack Developer tại Tokyo 😊. Nếu bạn thấy Blog này hay xin hãy cho mình một like và đăng ký để ủng hộ mình nhé 😉. Chào buổi sáng mọi người, hãy cũng nhau cưỡi ngựa xem hoa, cưỡi tên lửa ngắm đài điểu những Ví dụ về

image.png

Mình là TUẤN hiện đang là một Full-stack Developer tại Tokyo 😊.
Nếu bạn thấy Blog này hay xin hãy cho mình một like và đăng ký để ủng hộ mình nhé 😉.

Chào buổi sáng mọi người, hãy cũng nhau cưỡi ngựa xem hoa, cưỡi tên lửa ngắm đài điểu những Ví dụ về clean code. Cứ xem bài viết này như là một Checklist cho chúng ta tự Review Code của mình trước khi commit.

OK cùng ngồi xuống uống miếng bánh ăn miếng nước và GÉT GÔ nào….

Variables

Sử dụng tên biến có nghĩa

Not Good

const yyyymmdstr =moment().format('YYYY/MM/DD');

Good

const currentDate =moment().format('YYYY/MM/DD');

Sử dụng cùng từ vựng cho cùng loại biến

Not Good

getUserInfo();getClientData();getCustomerRecord();

Good

getUser();

Sử dụng các tên có thể tìm kiếm được

Not Good

// 86400000 là cái gì?setTimeout(blastOff,86400000);

Good

// Khai báo chúng như một biến global.constMILLISECONDS_IN_A_DAY=86400000;setTimeout(blastOff,MILLISECONDS_IN_A_DAY);

Sử dụng những biến có thể giải thích được

Not Good

const address ='One Infinite Loop, Cupertino 95014';const cityZipCodeRegex =/^[^,\]+[,\s]+(.+?)s*(d{5})?$/;saveCityZipCode(address.match(cityZipCodeRegex)[1], address.match(cityZipCodeRegex)[2]);

Good

const address ='One Infinite Loop, Cupertino 95014';const cityZipCodeRegex =/^[^,\]+[,\s]+(.+?)s*(d{5})?$/;const[, city, zipCode]= address.match(cityZipCodeRegex)||[];saveCityZipCode(city, zipCode);

Tường minh mọi thứ

Not Good

const locations =['Austin','New York','San Francisco'];
locations.forEach((l)=>{doStuff();doSomeOtherStuff();// ...// ...// ...// `l` làm cái gì vậy?dispatch(l);});

Good

const locations =['Austin','New York','San Francisco'];
locations.forEach((location)=>{doStuff();doSomeOtherStuff();// ...// ...// ...dispatch(location);});

Đừng thêm những thứ không cần thiết

Not Good

const Car ={
  carMake:'Honda',
  carModel:'Accord',
  carColor:'Blue'};functionpaintCar(car, color){
  car.carColor = color;}

Good

const Car ={
  make:'Honda',
  model:'Accord',
  color:'Blue'};functionpaintCar(car, color){
  car.color = color;}

Sử dụng những tham số mặc định thay vì kiểm tra các điều kiện lòng vòng

Not Good

functioncreateMicrobrewery(name){const breweryName = name ||'Hipster Brew Co.';// ...}

Good

functioncreateMicrobrewery(breweryName ='Hipster Brew Co.'){// ...}

Functions

Đối số của hàm

Lý tưởng là ít hơn hoặc bằng 2.
Not Good

functioncreateMenu(title, body, buttonText, cancellable){// ...}

Good

functioncreateMenu({ title, body, buttonText, cancellable }){// ...}createMenu({
  title:'Foo',
  body:'Bar',
  buttonText:'Baz',
  cancellable:true});

Một Function chỉ nên giải quyết một vấn đề

Not Good

functionemailClients(clients){
  clients.forEach((client)=>{const clientRecord = database.lookup(client);if(clientRecord.isActive()){email(client);}});}

Good

functionemailClients(clients){
  clients
    .filter(isClientActive).forEach(email);}functionisClientActive(client){const clientRecord = database.lookup(client);return clientRecord.isActive();}

Tên hàm phải nói ra được những gì chúng làm

Not Good

functionaddToDate(date, month){// ...}const date =newDate();// Khó để biết được hàm này thêm gì thông qua tên hàm.addToDate(date,1);

Good

functionaddMonthToDate(month, date){// ...}const date =newDate();addMonthToDate(1, date);

Hàm chỉ nên có một lớp trừu tượng

Not Good

functionparseBetterJSAlternative(code){constREGEXES=[// ...];const statements = code.split(' ');const tokens =[];REGEXES.forEach((REGEX)=>{
    statements.forEach((statement)=>{// ...});});const ast =[];
  tokens.forEach((token)=>{// lex...});

  ast.forEach((node)=>{// parse...});}

Good

functiontokenize(code){constREGEXES=[// ...];const statements = code.split(' ');const tokens =[];REGEXES.forEach((REGEX)=>{
    statements.forEach((statement)=>{
      tokens.push(/* ... */);});});return tokens;}functionlexer(tokens){const ast =[];
  tokens.forEach((token)=>{
    ast.push(/* ... */);});return ast;}functionparseBetterJSAlternative(code){const tokens =tokenize(code);const ast =lexer(tokens);
  ast.forEach((node)=>{// parse...});}

Xóa code trùng lặp

Not Good

functionshowDeveloperList(developers){
  developers.forEach((developer)=>{const expectedSalary = developer.calculateExpectedSalary();const experience = developer.getExperience();const githubLink = developer.getGithubLink();const data ={
      expectedSalary,
      experience,
      githubLink
    };render(data);});}functionshowManagerList(managers){
  managers.forEach((manager)=>{const expectedSalary = manager.calculateExpectedSalary();const experience = manager.getExperience();const portfolio = manager.getMBAProjects();const data ={
      expectedSalary,
      experience,
      portfolio
    };render(data);});}

Good

functionshowEmployeeList(employees){
  employees.forEach((employee)=>{const expectedSalary = employee.calculateExpectedSalary();const experience = employee.getExperience();let portfolio = employee.getGithubLink();if(employee.type ==='manager'){
      portfolio = employee.getMBAProjects();}const data ={
      expectedSalary,
      experience,
      portfolio
    };render(data);});}

Thiết lập những đối tượng mặc định với Object.assign

Not Good

const menuConfig ={
  title:null,
  body:'Bar',
  buttonText:null,
  cancellable:true};functioncreateMenu(config){
  config.title = config.title ||'Foo';
  config.body = config.body ||'Bar';
  config.buttonText = config.buttonText ||'Baz';
  config.cancellable = config.cancellable ===undefined? config.cancellable :true;}createMenu(menuConfig);

Good

const menuConfig ={
  title:'Order',// User did not include 'body' key
  buttonText:'Send',
  cancellable:true};functioncreateMenu(config){
  config = Object.assign({
    title:'Foo',
    body:'Bar',
    buttonText:'Baz',
    cancellable:true}, config);// config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}// ...}createMenu(menuConfig);

Đừng sử dụng các flag như đối số của hàm

Not Good

functioncreateFile(name, temp){if(temp){
    fs.create(`./temp/${name}`);}else{
    fs.create(name);}}

Good

functioncreateFile(name){
  fs.create(name);}functioncreateTempFile(name){createFile(`./temp/${name}`);}

Tránh những ảnh hưởng không cần thiết

VD1:
Not Good

// Biến toàn cục được tham chiếu bởi hàm dưới đây.// Nếu chúng ta có một hàm khác sử dụng name, nó sẽ trở thành một arraylet name ='Ryan McDermott';functionsplitIntoFirstAndLastName(){
  name = name.split(' ');}splitIntoFirstAndLastName();

console.log(name);// ['Ryan', 'McDermott'];

Good

functionsplitIntoFirstAndLastName(name){return name.split(' ');}const name ='Ryan McDermott';const newName =splitIntoFirstAndLastName(name);

console.log(name);// 'Ryan McDermott';
console.log(newName);// ['Ryan', 'McDermott'];

Đừng Override những function hoặc biến toàn cục

Not Good

Array.prototype.diff=functiondiff(comparisonArray){const hash =newSet(comparisonArray);returnthis.filter(elem=>!hash.has(elem));};

Good

classSuperArrayextendsArray{diff(comparisonArray){const hash =newSet(comparisonArray);returnthis.filter(elem=>!hash.has(elem));}}

Ưu tiên functional programming hơn là imperative programming

Ưu tiên lập trình theo hướng function hơn lập trình theo từng lệnh.
Not Good

const programmerOutput =[{
    name:'Uncle Bobby',
    linesOfCode:500},{
    name:'Suzie Q',
    linesOfCode:1500},{
    name:'Jimmy Gosling',
    linesOfCode:150},{
    name:'Gracie Hopper',
    linesOfCode:1000}];let totalOutput =0;for(let i =0; i < programmerOutput.length; i++){
  totalOutput += programmerOutput[i].linesOfCode;}

Good

const programmerOutput =[{
    name:'Uncle Bobby',
    linesOfCode:500},{
    name:'Suzie Q',
    linesOfCode:1500},{
    name:'Jimmy Gosling',
    linesOfCode:150},{
    name:'Gracie Hopper',
    linesOfCode:1000}];constINITIAL_VALUE=0;const totalOutput = programmerOutput
  .map((programmer)=> programmer.linesOfCode).reduce((acc, linesOfCode)=> acc + linesOfCode,INITIAL_VALUE);

Đóng gói các điều kiện

Not Good

if(fsm.state ==='fetching'&&isEmpty(listNode)){// ...}

Good

functionshouldShowSpinner(fsm, listNode){return fsm.state ==='fetching'&&isEmpty(listNode);}if(shouldShowSpinner(fsmInstance, listNodeInstance)){// ...}

Tránh điều kiện tiêu cực

Not Good

functionisDOMNodeNotPresent(node){// ...}if(!isDOMNodeNotPresent(node)){// ...}

Good

functionisDOMNodePresent(node){// ...}if(isDOMNodePresent(node)){// ...}

Tránh điều kiện

Not Good

classAirplane{// ...getCruisingAltitude(){switch(this.type){case'777':returnthis.getMaxAltitude()-this.getPassengerCount();case'Air Force One':returnthis.getMaxAltitude();case'Cessna':returnthis.getMaxAltitude()-this.getFuelExpenditure();}}}

Good

classAirplane{// ...}classBoeing777extendsAirplane{// ...getCruisingAltitude(){returnthis.getMaxAltitude()-this.getPassengerCount();}}classAirForceOneextendsAirplane{// ...getCruisingAltitude(){returnthis.getMaxAltitude();}}classCessnaextendsAirplane{// ...getCruisingAltitude(){returnthis.getMaxAltitude()-this.getFuelExpenditure();}}

Tránh kiểm tra kiểu

VD1:
Not Good

functiontravelToTexas(vehicle){if(vehicle instanceofBicycle){
    vehicle.peddle(this.currentLocation,newLocation('texas'));}elseif(vehicle instanceofCar){
    vehicle.drive(this.currentLocation,newLocation('texas'));}}

Good

functiontravelToTexas(vehicle){
  vehicle.move(this.currentLocation,newLocation('texas'));}

VD2:
Not Good

functioncombine(val1, val2){if(typeof val1 ==='number'&&typeof val2 ==='number'||typeof val1 ==='string'&&typeof val2 ==='string'){return val1 + val2;}thrownewError('Must be of type String or Number');}

Good

functioncombine(val1, val2){return val1 + val2;}

Xóa dead code

Not Good

functionoldRequestModule(url){// ...}functionnewRequestModule(url){// ...}const req = newRequestModule;inventoryTracker('apples', req,'www.inventory-awesome.io');

Good

functionnewRequestModule(url){// ...}const req = newRequestModule;inventoryTracker('apples', req,'www.inventory-awesome.io');

Objects and Data Structures

Sử dụng getter và setter

Not Good

functionmakeBankAccount(){// ...return{
    balance:0,// ...};}const account =makeBankAccount();
account.balance =100;

Good

functionmakeBankAccount(){// this one is privatelet balance =0;// Một "getter", thiết lập public thông qua đối tượng được trả về dưới đâyfunctiongetBalance(){return balance;}// Một "setter", thiết lập public thông qua đối tượng được trả về dưới đâyfunctionsetBalance(amount){// ... validate before updating the balance
    balance = amount;}return{// ...
    getBalance,
    setBalance,};}const account =makeBankAccount();
account.setBalance(100);

Sử dụng tính bao đóng trong JS

Điều này có thể được thực hiện thông qua closures (cho ES5 và cũ hơn).
Not Good

constEmployee=function(name){this.name = name;};Employee.prototype.getName=functiongetName(){returnthis.name;};const employee =newEmployee('John Doe');
console.log(`Employee name: ${employee.getName()}`);// Employee name: John Doedelete employee.name;
console.log(`Employee name: ${employee.getName()}`);// Employee name: undefined

Good

constEmployee=function(name){this.getName=functiongetName(){return name;};};const employee =newEmployee('John Doe');
console.log(`Employee name: ${employee.getName()}`);// Employee name: John Doedelete employee.name;
console.log(`Employee name: ${employee.getName()}`);// Employee name: John Doe

Classes

Ưu tiên class ES2015/ES6 hơn các function thuần ES5

Not Good

constAnimal=function(age){if(!(thisinstanceofAnimal)){thrownewError('Instantiate Animal with `new`');}this.age = age;};Animal.prototype.move=functionmove(){};constMammal=function(age, furColor){if(!(thisinstanceofMammal)){thrownewError('Instantiate Mammal with `new`');}Animal.call(this, age);this.furColor = furColor;};Mammal.prototype = Object.create(Animal.prototype);Mammal.prototype.constructor = Mammal;Mammal.prototype.liveBirth=functionliveBirth(){};constHuman=function(age, furColor, languageSpoken){if(!(thisinstanceofHuman)){thrownewError('Instantiate Human with `new`');}Mammal.call(this, age, furColor);this.languageSpoken = languageSpoken;};Human.prototype = Object.create(Mammal.prototype);Human.prototype.constructor = Human;Human.prototype.speak=functionspeak(){};

Good

classAnimal{constructor(age){this.age = age;}move(){/* ... */}}classMammalextendsAnimal{constructor(age, furColor){super(age);this.furColor = furColor;}liveBirth(){/* ... */}}classHumanextendsMammal{constructor(age, furColor, languageSpoken){super(age, furColor);this.languageSpoken = languageSpoken;}speak(){/* ... */}}

Xâu chuỗi các hàm

Not Good

classCar{constructor(){this.make ='Honda';this.model ='Accord';this.color ='white';}setMake(make){this.make = make;}setModel(model){this.model = model;}setColor(color){this.color = color;}save(){
    console.log(this.make,this.model,this.color);}}const car =newCar();
car.setColor('pink');
car.setMake('Ford');
car.setModel('F-150');
car.save();

Good

classCar{constructor(){this.make ='Honda';this.model ='Accord';this.color ='white';}setMake(make){this.make = make;// Ghi chú: Trả về this để xâu chuỗi các hàmreturnthis;}setModel(model){this.model = model;// Ghi chú: Trả về this để xâu chuỗi các hàmreturnthis;}setColor(color){this.color = color;// Ghi chú: Trả về this để xâu chuỗi các hàmreturnthis;}save(){
    console.log(this.make,this.model,this.color);// Ghi chú: Trả về this để xâu chuỗi các hàmreturnthis;}}const car =newCar().setColor('pink').setMake('Ford').setModel('F-150').save();

Ưu tiên component hơn là kế thừa

Not Good

classEmployee{constructor(name, email){this.name = name;this.email = email;}// ...}// Không tốt bởi vì Employees "có" dữ liệu thuế.// EmployeeTaxData không phải là một loại của EmployeeclassEmployeeTaxDataextendsEmployee{constructor(ssn, salary){super();this.ssn = ssn;this.salary = salary;}// ...}

Good

classEmployeeTaxData{constructor(ssn, salary){this.ssn = ssn;this.salary = salary;}// ...}classEmployee{constructor(name, email){this.name = name;this.email = email;}setTaxData(ssn, salary){this.taxData =newEmployeeTaxData(ssn, salary);}// ...}

SOLID

Nguyên lí mỗi người một việc (Single Responsibility Principle)

Not Good

classUserSettings{constructor(user){this.user = user;}changeSettings(settings){if(this.verifyCredentials()){// ...}}verifyCredentials(){// ...}}

Good

classUserAuth{constructor(user){this.user = user;}verifyCredentials(){// ...}}classUserSettings{constructor(user){this.user = user;this.auth =newUserAuth(user);}changeSettings(settings){if(this.auth.verifyCredentials()){// ...}}}

Nguyên lí đóng mở (Open/Closed Principle)

Trong ví dụ bạn sẽ thấy ko nên cho các HttpRequester tương tác hoặc biết về sự tồn tại của AjaxAdapter, NodeAdapter mà tất cả chỉ biết và tương tác với nhau thông qua AdapterNot Good

classAjaxAdapterextendsAdapter{constructor(){super();this.name ='ajaxAdapter';}}classNodeAdapterextendsAdapter{constructor(){super();this.name ='nodeAdapter';}}classHttpRequester{constructor(adapter){this.adapter = adapter;}fetch(url){if(this.adapter.name ==='ajaxAdapter'){returnmakeAjaxCall(url).then((response)=>{// transform response and return});}elseif(this.adapter.name ==='httpNodeAdapter'){returnmakeHttpCall(url).then((response)=>{// transform response and return});}}}functionmakeAjaxCall(url){// request and return promise}functionmakeHttpCall(url){// request and return promise}

Good

classAjaxAdapterextendsAdapter{constructor(){super();this.name ='ajaxAdapter';}request(url){// request and return promise}}classNodeAdapterextendsAdapter{constructor(){super();this.name ='nodeAdapter';}request(url){// request and return promise}}classHttpRequester{constructor(adapter){this.adapter = adapter;}fetch(url){returnthis.adapter.request(url).then((response)=>{// transform response and return});}}

Nguyên lí thay thế Liskov (Liskov Substitution Principle)

Not Good

classRectangle{constructor(){this.width =0;this.height =0;}setColor(color){// ...}render(area){// ...}setWidth(width){this.width = width;}setHeight(height){this.height = height;}getArea(){returnthis.width *this.height;}}classSquareextendsRectangle{setWidth(width){this.width = width;this.height = width;}setHeight(height){this.width = height;this.height = height;}}functionrenderLargeRectangles(rectangles){
  rectangles.forEach((rectangle)=>{
    rectangle.setWidth(4);
    rectangle.setHeight(5);const area = rectangle.getArea();// BAD: Will return 25 for Square. Should be 20.
    rectangle.render(area);});}const rectangles =[newRectangle(),newRectangle(),newSquare()];renderLargeRectangles(rectangles);

Good

classShape{setColor(color){// ...}render(area){// ...}}classRectangleextendsShape{constructor(width, height){super();this.width = width;this.height = height;}getArea(){returnthis.width *this.height;}}classSquareextendsShape{constructor(length){super();this.length = length;}getArea(){returnthis.length *this.length;}}functionrenderLargeShapes(shapes){
  shapes.forEach((shape)=>{const area = shape.getArea();
      shape.render(area);});}const shapes =[newRectangle(4,5),newRectangle(4,5),newSquare(5)];renderLargeShapes(shapes);

Nguyên lí phân tách interface (Interface Segregation Principle)

Not Good

classDOMTraverser{constructor(settings){this.settings = settings;this.setup();}setup(){this.rootNode =this.settings.rootNode;this.animationModule.setup();}traverse(){// ...}}const $ =newDOMTraverser({
  rootNode: document.getElementsByTagName('body'),animationModule(){}// Most of the time, we won't need to animate when traversing.// ...});

Good

classDOMTraverser{constructor(settings){this.settings = settings;this.options = settings.options;this.setup();}setup(){this.rootNode =this.settings.rootNode;this.setupOptions();}setupOptions(){if(this.options.animationModule){// ...}}traverse(){// ...}}const $ =newDOMTraverser({
  rootNode: document.getElementsByTagName('body'),
  options:{animationModule(){}}});

Nguyên lí đảo ngược dependency (Dependency Inversion Principle)

Not Good

classInventoryRequester{constructor(){this.REQ_METHODS=['HTTP'];}requestItem(item){// ...}}classInventoryTracker{constructor(items){this.items = items;// Not Good chúng ta đã tạo một phụ thuộc vào một hiện thực của một request cụ thể// Chúng ta nên có những requestItems phụ thuộc vào một hàm request `request`this.requester =newInventoryRequester();}requestItems(){this.items.forEach((item)=>{this.requester.requestItem(item);});}}const inventoryTracker =newInventoryTracker(['apples','bananas']);
inventoryTracker.requestItems();

Good

classInventoryTracker{constructor(items, requester){this.items = items;this.requester = requester;}requestItems(){this.items.forEach((item)=>{this.requester.requestItem(item);});}}classInventoryRequesterV1{constructor(){this.REQ_METHODS=['HTTP'];}requestItem(item){// ...}}classInventoryRequesterV2{constructor(){this.REQ_METHODS=['WS'];}requestItem(item){// ...}}// Bằng cách xây dựng các phụ thuộc ở ngoài và thêm chúng vào, chúng ta có thể// dễ dàng thay thế module request bằng một module mới lạ sử dụng WebSockets.const inventoryTracker =newInventoryTracker(['apples','bananas'],newInventoryRequesterV2());
inventoryTracker.requestItems();

Testing

Một khái niệm duy nhất cho mỗi unit test

Not Good

const assert =require('assert');describe('MakeMomentJSGreatAgain',()=>{it('handles date boundaries',()=>{let date;

    date =newMakeMomentJSGreatAgain('1/1/2015');
    date.addDays(30);
    date.shouldEqual('1/31/2015');

    date =newMakeMomentJSGreatAgain('2/1/2016');
    date.addDays(28);
    assert.equal('02/29/2016', date);

    date =newMakeMomentJSGreatAgain('2/1/2015');
    date.addDays(28);
    assert.equal('03/01/2015', date);});});

Good

const assert =require('assert');describe('MakeMomentJSGreatAgain',()=>{it('handles 30-day months',()=>{const date =newMakeMomentJSGreatAgain('1/1/2015');
    date.addDays(30);
    date.shouldEqual('1/31/2015');});it('handles leap year',()=>{const date =newMakeMomentJSGreatAgain('2/1/2016');
    date.addDays(28);
    assert.equal('02/29/2016', date);});it('handles non-leap year',()=>{const date =newMakeMomentJSGreatAgain('2/1/2015');
    date.addDays(28);
    assert.equal('03/01/2015', date);});});

Concurrency – Xử lí đồng thời

Hãy dùng Promise, đừng dùng callback

Not Good

require('request').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin',(requestErr, response)=>{if(requestErr){
    console.error(requestErr);}else{require('fs').writeFile('article.html', response.body,(writeErr)=>{if(writeErr){
        console.error(writeErr);}else{
        console.log('File written');}});}});

Good

require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin').then((response)=>{returnrequire('fs-promise').writeFile('article.html', response);}).then(()=>{
    console.log('File written');}).catch((err)=>{
    console.error(err);});

Async/Await thì ‘clean’ hơn Promise

Not Good

require('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin').then((response)=>{returnrequire('fs-promise').writeFile('article.html', response);}).then(()=>{
    console.log('File written');}).catch((err)=>{
    console.error(err);});

Good

asyncfunctiongetCleanCodeArticle(){try{const response =awaitrequire('request-promise').get('https://en.wikipedia.org/wiki/Robert_Cecil_Martin');awaitrequire('fs-promise').writeFile('article.html', response);
    console.log('File written');}catch(err){
    console.error(err);}}

Error Handling

Đừng bỏ qua những lỗi đã bắt được

Not Good

try{functionThatMightThrow();}catch(error){
  console.log(error);}

Good

try{functionThatMightThrow();}catch(error){// One option (more noisy than console.log):
  console.error(error);// Another option:notifyUserOfError(error);// Another option:reportErrorToService(error);// OR do all three!}

Đừng bỏ qua những promise bị lỗi (rejected)

Cùng nguyên nhân với phần trên.
Not Good

getdata().then((data)=>{functionThatMightThrow(data);}).catch((error)=>{
  console.log(error);});

Good

getdata().then((data)=>{functionThatMightThrow(data);}).catch((error)=>{// One option (more noisy than console.log):
  console.error(error);// Another option:notifyUserOfError(error);// Another option:reportErrorToService(error);// OR do all three!});

Formatting

Not Good

constDAYS_IN_WEEK=7;const daysInMonth =30;const songs =['Back In Black','Stairway to Heaven','Hey Jude'];const Artists =['ACDC','Led Zeppelin','The Beatles'];functioneraseDatabase(){}functionrestore_database(){}classanimal{}classAlpaca{}

Good

constDAYS_IN_WEEK=7;constDAYS_IN_MONTH=30;const songs =['Back In Black','Stairway to Heaven','Hey Jude'];const artists =['ACDC','Led Zeppelin','The Beatles'];functioneraseDatabase(){}functionrestoreDatabase(){}classAnimal{}classAlpaca{}

Các hàm gọi và hàm được gọi nên nằm gần nhau

Not Good

classPerformanceReview{constructor(employee){this.employee = employee;}lookupPeers(){return db.lookup(this.employee,'peers');}lookupManager(){return db.lookup(this.employee,'manager');}getPeerReviews(){const peers =this.lookupPeers();// ...}perfReview(){this.getPeerReviews();this.getManagerReview();this.getSelfReview();}getManagerReview(){const manager =this.lookupManager();}getSelfReview(){// ...}}const review =newPerformanceReview(user);
review.perfReview();

Good

classPerformanceReview{constructor(employee){this.employee = employee;}perfReview(){this.getPeerReviews();this.getManagerReview();this.getSelfReview();}getPeerReviews(){const peers =this.lookupPeers();// ...}lookupPeers(){return db.lookup(this.employee,'peers');}getManagerReview(){const manager =this.lookupManager();}lookupManager(){return db.lookup(this.employee,'manager');}getSelfReview(){// ...}}const review =newPerformanceReview(employee);
review.perfReview();

Comments

Chỉ nên viết comment cho những thứ có logic phức tạp.

Not Good

functionhashIt(data){// Khai báo hashlet hash =0;// Lấy chiều dài của chuỗiconst length = data.length;// Lặp qua mỗi kí tựfor(let i =0; i < length; i++){// Lấy code của kí tựconst char = data.charCodeAt(i);// Gán value cho hash
    hash =((hash <<5)- hash)+ char;// Chuyển thành định dạng số nguyên 32 bit
    hash &= hash;}}

Good

functionhashIt(data){let hash =0;const length = data.length;for(let i =0; i < length; i++){const char = data.charCodeAt(i);
    hash =((hash <<5)- hash)+ char;// Chuyển thành định dạng số nguyên 32 bit
    hash &= hash;}}

Đừng giữ lại những đoạn code bị comment trong codebase của bạn.

Not Good

doStuff();// doOtherStuff();// doSomeMoreStuff();// doSoMuchStuff();

Good

doStuff();

Đừng viết các comment log

Sử dụng git log để xem lịch sử được mà!
Not Good

/**
 * 2016-12-20: Removed monads, didn't understand them (RM)
 * 2016-10-01: Improved using special monads (JP)
 * 2016-02-03: Removed type-checking (LI)
 * 2015-03-14: Added combine with type-checking (JR)
 */functioncombine(a, b){return a + b;}

Good

functioncombine(a, b){return a + b;}

Tránh những đánh dấu vị trí

Not Good

////////////////////////////////////////////////////////////////////////////////// Scope Model Instantiation////////////////////////////////////////////////////////////////////////////////
$scope.model ={
  menu:'foo',
  nav:'bar'};////////////////////////////////////////////////////////////////////////////////// Action setup////////////////////////////////////////////////////////////////////////////////constactions=function(){// ...};

Good

$scope.model ={
  menu:'foo',
  nav:'bar'};constactions=function(){// ...};

Roundup

Như mọi khi, mình hy vọng bạn thích bài viết này và học thêm được điều gì đó mới.

Cảm ơn và hẹn gặp lại các bạn trong những bài viết tiếp theo! 😍

Nếu bạn thấy Blog này hay xin hãy cho mình một like và đăng ký để ủng hộ mình nhé. Thank you.😉

Ref

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ