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 Adapter
Not 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