├── README.md ├── clases ├── avoid primitive obsession use clases to return.js ├── clases dont be redundant.js ├── clases extract class or method.js └── functions avoid too many arguments use clases.js ├── conditionals ├── avoid magic numbers.js ├── conditionals dont be anti-negative.js ├── conditionals should be positive.js ├── conditionals use functions to clarify.js ├── use direct comparison.js └── use ternary operator.js ├── functions ├── function avoid arrow code.js ├── function avoid flag arguments.js ├── function avoid redundant comments.js └── function extract methods.js └── naming ├── naming be simetric.js ├── naming booleans should answer questions.js ├── naming do only one thing.js ├── naming dont use abrevations.js ├── naming dont use and or if.js ├── naming dont use prefixes.js ├── naming intention.js ├── naming use intermediate variables.js └── naming user noun verb.js /README.md: -------------------------------------------------------------------------------- 1 | # Set of examples used in [Front-end Developers Madrid](https://www.meetup.com/es-ES/Front-end-Developers-Madrid/) talk 2 | 3 | Slides are [here](https://www.slideshare.net/leomicheloni/clean-code-javascript) 4 | 5 | Also here's the recording: https://www.youtube.com/watch?v=C5IrXwu6nSQ&list=PLLJikjug8HYAkS92pbon_m0zHilqxidSY 6 | -------------------------------------------------------------------------------- /clases/avoid primitive obsession use clases to return.js: -------------------------------------------------------------------------------- 1 | //// Clases, avoid primitive return types, use clases 2 | // Mal 3 | function registerUser(user){ 4 | // ... 5 | return json; 6 | } 7 | // Bien 8 | function registerUser(user){ 9 | return { 10 | success: true, 11 | userId : 123, 12 | welcomeDiscount: 10 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /clases/clases dont be redundant.js: -------------------------------------------------------------------------------- 1 | //// Clases, don't be redundant 2 | // Mal 3 | const Car = { 4 | carMake: 'Honda', 5 | carModel: 'Accord', 6 | carColor: 'Blue' 7 | }; 8 | // Bien 9 | const Car = { 10 | make: 'Honda', 11 | model: 'Accord', 12 | color: 'Blue' 13 | }; -------------------------------------------------------------------------------- /clases/clases extract class or method.js: -------------------------------------------------------------------------------- 1 | //// Clases, extract clases, mantain SRP 2 | // Mal 3 | function Receipt() { 4 | this.aDiscounts = []; 5 | this.aItemTotals = []; 6 | } 7 | Receipt.prototype.calculateGrandTotal = function () { 8 | var nSubTotal = 0, 9 | nTax, 10 | nTotal, 11 | nLenTotals = this.aItemTotals.length, 12 | nItemValue, 13 | nDiscount, 14 | nLenDiscounts = this.aDiscounts.length, 15 | nDiscountValue; 16 | for (nTotal = 0; nTotal < nLenTotals; nTotal++) { 17 | nItemValue = this.aItemTotals[nTotal]; 18 | nSubTotal += nItemValue; 19 | } 20 | if (nLenDiscounts > 0) { 21 | for (nDiscount = 0; nDiscount < nLenDiscounts; nDiscount++) { 22 | nDiscountValue = this.aDiscounts[nDiscount]; 23 | nSubTotal -= nDiscountValue; 24 | } 25 | } 26 | nTax = nSubTotal * 0.065; 27 | nSubTotal += nTax; 28 | return nSubTotal 29 | }; 30 | // Bien 31 | function Receipt() { 32 | this.aDiscounts = []; 33 | this.aItemTotals = []; 34 | } 35 | Receipt.prototype.calculateGrandTotal = function () { 36 | var nSubTotal = this.calculateSubtotal(); 37 | nSubTotal = this.calculateDiscounts(nSubTotal); 38 | nSubTotal = this.calculateTax(nSubTotal); 39 | return nSubTotal; 40 | }; 41 | Receipt.prototype.calculateTax = function (nSubTotal) { 42 | var nTax = nSubTotal * 0.065; 43 | nSubTotal += nTax; 44 | return nSubTotal; 45 | }; 46 | Receipt.prototype.calculateDiscounts = function (nSubTotal) { 47 | var nDiscount, 48 | nLenDiscounts = this.aDiscounts.length, 49 | nDiscountValue; 50 | if (nLenDiscounts) { 51 | for (nDiscount = 0; nDiscount < nLenDiscounts; nDiscount++) { 52 | nDiscountValue = this.aDiscounts[nDiscount]; 53 | nSubTotal -= nDiscountValue; 54 | } 55 | } 56 | return nSubTotal; 57 | }; 58 | Receipt.prototype.calculateSubtotal = function () { 59 | var nSubTotal = 0, 60 | nTotal, 61 | nLenTotals = this.aItemTotals.length, 62 | nItemValue; 63 | for (nTotal = 0; nTotal < nLenTotals; nTotal++) { 64 | nItemValue = this.aItemTotals[nTotal]; 65 | nSubTotal += nItemValue; 66 | } 67 | return nSubTotal; 68 | }; 69 | 70 | // Mal 71 | function CustomerService() { 72 | } 73 | CustomerService.prototype.calculateOrderDiscount = function (aProducts, oCustomer) { 74 | // do work 75 | }; 76 | CustomerService.prototype.isValidCustomer = function (oCustomer, oOrder) { 77 | // do work 78 | }; 79 | CustomerService.prototype.gatherOrderErrors = function (aProducts, oCustomer) { 80 | // do work 81 | }; 82 | CustomerService.prototype.register = function (oCustomer) { 83 | // do work 84 | }; 85 | CustomerService.prototype.forgotPassword = function (oCustomer) { 86 | // do work 87 | }; 88 | // Bien 89 | function CustomerRegistrationService() { 90 | } 91 | CustomerRegistrationService.prototype.register = function () { 92 | // do work 93 | }; 94 | CustomerRegistrationService.prototype.forgotPassword = function () { 95 | // do work 96 | }; 97 | function CustomerOrderService() { 98 | } 99 | CustomerOrderService.prototype.calculateOrderDiscount = function (aProducts, oCustomer) { 100 | // do work 101 | }; 102 | CustomerOrderService.prototype.isValidCustomer = function (oCustomer, oOrder) { 103 | // do work 104 | }; 105 | CustomerOrderService.prototype.gatherOrderErrors = function (aProducts, oCustomer) { 106 | // do work 107 | }; 108 | -------------------------------------------------------------------------------- /clases/functions avoid too many arguments use clases.js: -------------------------------------------------------------------------------- 1 | //// Functions, avoid too many arguments, use clases instead 2 | // Mal 3 | function register(name, lastName, age, email, country){ 4 | // ... 5 | } 6 | // Bien 7 | class User{ 8 | constructor(name, lastName, age, email, country){ 9 | this.name = name; 10 | this.lastName = lastName; 11 | this.age = age; 12 | this.email = email; 13 | this.country = countr; 14 | } 15 | } 16 | function registerUser(User){ 17 | // ... 18 | } -------------------------------------------------------------------------------- /conditionals/avoid magic numbers.js: -------------------------------------------------------------------------------- 1 | //// Conditionals, don't use magic numbers 2 | // Mal 3 | if(user.age > 18){ 4 | // ... 5 | } 6 | // Bien 7 | var validAge = 18; 8 | if(user.age > validAge){ 9 | // ... 10 | } 11 | 12 | // Mal 13 | setTimeout(blastOff, 86400000); 14 | // bien 15 | const MILLISECONDS_IN_A_DAY = 86400000; 16 | setTimeout(blastOff, MILLISECONDS_IN_A_DAY); 17 | 18 | // Mal 19 | if(userStatus = -1){ // new user 20 | // .... 21 | } 22 | // Bien 23 | var UserStatusNew = -1; 24 | if(userStatus = UserStatusNew){ 25 | // .... 26 | } -------------------------------------------------------------------------------- /conditionals/conditionals dont be anti-negative.js: -------------------------------------------------------------------------------- 1 | //// Conditionals, don't be "anti-negative" 2 | // Mal 3 | if(!isNotValid()){ 4 | // ... 5 | } 6 | // Bien 7 | if(isValid()){ 8 | // ... 9 | } -------------------------------------------------------------------------------- /conditionals/conditionals should be positive.js: -------------------------------------------------------------------------------- 1 | //// Conditionals, be "positive" 2 | // Mal 3 | if(isNotValid()){ 4 | // ... 5 | } 6 | // Bien 7 | if(isValid()){ 8 | // ... 9 | } -------------------------------------------------------------------------------- /conditionals/conditionals use functions to clarify.js: -------------------------------------------------------------------------------- 1 | //// Conditional, use functions to clarify conditions 2 | // Mal 3 | if (fsm.state === 'fetching' && isEmpty(listNode)) { 4 | // ... 5 | } 6 | // Bien 7 | function shouldShowSpinner(fsm, listNode) { 8 | return fsm.state === 'fetching' && isEmpty(listNode); 9 | } 10 | if (shouldShowSpinner(fsmInstance, listNodeInstance)) { 11 | // ... 12 | } -------------------------------------------------------------------------------- /conditionals/use direct comparison.js: -------------------------------------------------------------------------------- 1 | //// Conditionals, use direct comparison 2 | // Mal 3 | if(isValid() == true){ 4 | // ... 5 | } 6 | // Bien 7 | if(isValid()){ 8 | // ... 9 | } -------------------------------------------------------------------------------- /conditionals/use ternary operator.js: -------------------------------------------------------------------------------- 1 | //// Conditionals, assign using ternary operator 2 | var message = ""; 3 | 4 | if(isValid()){ 5 | validationOk = "Welcome!"; 6 | }else{ 7 | var validationOk = "Go Away"; 8 | } 9 | // Bien 10 | var validationOk = isValid() ? "Welcome!": "Go Away"; -------------------------------------------------------------------------------- /functions/function avoid arrow code.js: -------------------------------------------------------------------------------- 1 | //// Conditionals, avoid arrow code 2 | // MAL 3 | var result = ""; 4 | 5 | if(!user.isRegistered()){ 6 | if(user.name.length < 3){ 7 | result = "the name is too short"; 8 | }else{ 9 | if(user.password.lenght < 4){ 10 | result = "the passwork is too short"; 11 | }else{ 12 | if(user.age < 18){ 13 | result = "you must be over 18 in order to register my friend"; 14 | }else{ 15 | if(user.gender == ""){ 16 | result = "A gender must be specified"; 17 | }else{ 18 | if(user.country == ""){ 19 | result = "Please select a country from the list"; 20 | }else{ 21 | if(user.hasValidEmail()){ 22 | result = "Welcome man"; 23 | }else{ 24 | result = "The email is not valid"; 25 | } 26 | } 27 | } 28 | } 29 | } 30 | } 31 | } 32 | else{ 33 | result = "This user is already registered"; 34 | } 35 | return result; 36 | 37 | // Bien 38 | if(user.isRegistered()) 39 | return "This user is already registered"; 40 | 41 | if(user.name.length < 3) 42 | return "The name is too short"; 43 | 44 | if(user.password.lenght < 4){ 45 | return "the passwork is too short"; 46 | 47 | if(user.age < 18) 48 | return "you must be over 18 in order to register my friend"; 49 | 50 | if(user.gender == ""){ 51 | return "A gender must be specified"; 52 | 53 | if(user.country == "") 54 | return "Please select a country from the list"; 55 | 56 | if(user.hasValidEmail()) 57 | return "The email is not valid"; 58 | 59 | return "Welcome man"; -------------------------------------------------------------------------------- /functions/function avoid flag arguments.js: -------------------------------------------------------------------------------- 1 | //// Functions, don't use flag arguments 2 | // Mal 3 | function createFile(name, temp) { 4 | if (temp) { 5 | fs.create(`./temp/${name}`); 6 | } else { 7 | fs.create(name); 8 | } 9 | } 10 | // Bien 11 | function createFile(name) { 12 | fs.create(name); 13 | } 14 | function createTempFile(name) { 15 | createFile(`./temp/${name}`); 16 | } -------------------------------------------------------------------------------- /functions/function avoid redundant comments.js: -------------------------------------------------------------------------------- 1 | //// Naming, avoid dedundant comments 2 | function selectPaymentMethod(control, applicationId) { 3 | ///Selects the payment method 4 | } 5 | -------------------------------------------------------------------------------- /functions/function extract methods.js: -------------------------------------------------------------------------------- 1 | //// Function, extract methods, avoid flag arguments 2 | // Mal 3 | function createTask(description, priority, preview, email){ 4 | var task = TaskFactory.new(); 5 | task.status = "open"; 6 | task.description = description; 7 | task.priority = priority; 8 | 9 | if(!preview == true){ 10 | task.save(); 11 | if(email == true){ 12 | mailSender.send(task); 13 | } 14 | }else{ 15 | mailSender.send(task, false); 16 | } 17 | } 18 | // Bien 19 | function createTask(description, priority){ 20 | var task = TaskFactory.new(description, priority); 21 | task.save(); 22 | return task; 23 | } 24 | function previewTask(description, priority){ 25 | var task = TaskFactory.new(description, priority); 26 | return task; 27 | } 28 | function notifyTaskCreation(task){ 29 | emailSender.notifyCreation(task); 30 | } 31 | function notifyTaskPreview(task){ 32 | emailSender.notifyCreation(task); 33 | } -------------------------------------------------------------------------------- /naming/naming be simetric.js: -------------------------------------------------------------------------------- 1 | //// Naming, be simetric 2 | // Mal 3 | function start(){ 4 | // ... 5 | } 6 | function finish(){ 7 | // ... 8 | } 9 | // Bien 10 | function start(){ 11 | // ... 12 | } 13 | function stop(){ 14 | 15 | } 16 | 17 | // Mal 18 | var on = true; 19 | var down = false; 20 | 21 | // Bien 22 | var on = true; 23 | var off = false; 24 | -------------------------------------------------------------------------------- /naming/naming booleans should answer questions.js: -------------------------------------------------------------------------------- 1 | // Naming, boolean should answer question 2 | // Mal 3 | function valid(){ 4 | // ... 5 | } 6 | // Bien 7 | function isValidSubmision(){ 8 | // ... 9 | } 10 | 11 | // Mal 12 | var valid = true; 13 | // Bien 14 | var isValid = true; 15 | 16 | // Mal 17 | var registered = false; 18 | // Bien 19 | var isRegistered = false; 20 | 21 | // Mal 22 | var notValid = false; 23 | // Bien 24 | var isValid = true; 25 | -------------------------------------------------------------------------------- /naming/naming do only one thing.js: -------------------------------------------------------------------------------- 1 | // Naming, do only one thing 2 | // Mal 3 | function mail(){ 4 | // ... 5 | } 6 | // Bien 7 | function sendMail(){ 8 | 9 | } 10 | 11 | // Mal 12 | function process(){ 13 | // ... 14 | } 15 | // Bien 16 | function processUserRequest(){ 17 | // ... 18 | } -------------------------------------------------------------------------------- /naming/naming dont use abrevations.js: -------------------------------------------------------------------------------- 1 | //// Naming, don't use abrevatinos 2 | // Mal 3 | var usrPwd = // .... 4 | // Bien 5 | var userPasswork = // -------------------------------------------------------------------------------- /naming/naming dont use and or if.js: -------------------------------------------------------------------------------- 1 | //// Naming, don't use AND, OR, IF 2 | function validateAndSave(user){ 3 | // ... 4 | } 5 | 6 | function addOrCreate(file){ 7 | // ... 8 | } 9 | 10 | function saveOrUpdate(){ 11 | // ... 12 | } 13 | -------------------------------------------------------------------------------- /naming/naming dont use prefixes.js: -------------------------------------------------------------------------------- 1 | //// Naming, don't use prefixes or subfixes 2 | var sName = 'Chespirito'; 3 | 4 | var divContenedor = $("#div1"); 5 | 6 | if(bExiste == true){ 7 | // ... 8 | } -------------------------------------------------------------------------------- /naming/naming intention.js: -------------------------------------------------------------------------------- 1 | //// Naming intention 2 | // Mal 3 | const d = moment().format('YYYY/MM/DD'); 4 | // bien 5 | const currentDate = moment().format('YYYY/MM/DD'); 6 | 7 | // Mal 8 | function save(){ 9 | // ... 10 | } 11 | // Bien 12 | function saveUserStatus(){ 13 | // ... 14 | } 15 | 16 | // Mal 17 | var a = ['Ford', 'Rena', 'Citroen', 'Mazda']; 18 | a.forEach(element => { 19 | // ... 20 | }); 21 | // Bien 22 | var carMakers = ['Ford', 'Rena', 'Citroen', 'Mazda']; 23 | carMakers.forEach(maker => { 24 | // ... 25 | }); 26 | -------------------------------------------------------------------------------- /naming/naming use intermediate variables.js: -------------------------------------------------------------------------------- 1 | //// Naming, use intermediate variables 2 | var isValidOrNew = user == null || user.isValid(); -------------------------------------------------------------------------------- /naming/naming user noun verb.js: -------------------------------------------------------------------------------- 1 | //// Naming use noun + verb in functions 2 | // Mal 3 | function Do(u, c){ 4 | // ... 5 | } 6 | // Bien 7 | function RegisterUser(user, credentials){ 8 | // ... 9 | } 10 | 11 | // Mal 12 | function get(){ 13 | // .... 14 | } 15 | // Bien 16 | function getRegisterUsers(){ 17 | // .... 18 | } 19 | --------------------------------------------------------------------------------