Clean code

574 views

Published on

Published in: Technology
  • Be the first to comment

Clean code

  1. 1. { clean code }twitter.com/jirkapenzes
  2. 2. Co je to čistý kód?• Definic je tolik, kolik je vývojářů.• Čistý kód píše pečlivý člověk.• „Čistý kód je jednoduchý a přímočarý. Čistý kód se čte jako dobře napsaná próza. Čistý kód nikdy nezatemňuje záměr návrháře, ale je plný břitkých abstrakcí a přímých toků řízení„ (Grady Booch).
  3. 3. Proč čistý kód?
  4. 4. Proč psát čistý kód?• Chceme na svůj kód být hrdí.• Přehlednost, znovu použitelnost.• Kód se lépe udržuje.• Produktivita, méně stresu.• Zbavit se „wtf“ momentů.• Budete mít ze své práce radost a lepší pocit.• Dokumentace.• Neděláme to jen pro sebe, – občas po nás kód někdo čte.
  5. 5. Jak na čistý kód?
  6. 6. Volit správné názvy
  7. 7. Volit správné názvy• Správná jména metod.• Správná jména tříd.• Správná jména proměnných.• Správná jména výčtových typů.• SPRÁVNÁ JMÉNA.• Největší problém v dějinách programování!
  8. 8. public List<int[]> GetThem() { List<int[]> list1 = new List<int[]>(); foreach(int[] x in theList) if (x[0] == 4) list1.Add(x) return list1; }• Jaký druh položek obsahuje theList?• Jaký je význam nultého indexu položky v theList?• Jaký je význam hodnoty 4?• Jak bych mohl využít vráceného seznamu?• Co ta metoda vůbec dělá??
  9. 9. public List<int[]> GetFlaggedCells(){ List<int[]> list1 = new List<int[]>(); foreach(int[] x in theList) if (x[0] == 4) list1.Add(x) return list1;}
  10. 10. public List<int[]> GetFlaggedCells(){ List<int[]> flaggedCells = new List<int[]>(); foreach(int[] x in theList) if (x[0] == 4) flaggedCells.Add(x) return flaggedCells;}
  11. 11. public List<int[]> GetFlaggedCells(){ List<int[]> flaggedCells = new List<int[]>(); foreach(int[] cell in gameBoard) if (cell[0] == 4) flaggedCells.Add(cell) return flaggedCells;}
  12. 12. public List<int[]> GetFlaggedCells(){ List<int[]> flaggedCells = new List<int[]>(); foreach(int[] cell in gameBoard) if (cell[STATUS_VALUE] == FLAGGED) flaggedCells.Add(cell) return flaggedCells;}
  13. 13. public List<int[]> GetFlaggedCells(){ List<int[]> flaggedCells = new List<int[]>(); foreach(int[] cell in gameBoard) if (cell[STATUS_VALUE] == FLAGGED) flaggedCells.Add(cell) return flaggedCells;}
  14. 14. public List<Cell> getFlaggedCells(){ List<Cell> flaggedCells = new List<Cell>(); foreach(Cell cell in gameBoard) if (cell.IsFlagged) flaggedCells.Add(cell) return flaggedCells;}
  15. 15. Nezkracujte názvyint d = 2; // total daysint d = 2; // diameterint d = 2; // distanceint s = 0;for (int i = 0; i < 10; i++) s += i;String m = "message";
  16. 16. Nezkracujte názvyint totalDays = 2;int diamater = 2;int distance = 2;int suma = 0;for (int index = 0; index < 10; index++) suma += index;String message = "message";if (a > b && a > c && a > d && a > e) max = a ;else if (b > a && b > c && b > d && b > e) max = b ;
  17. 17. Neprotahovat názvyUniqueNamesTableUtils.putPortletRequestIntoResourceRecordLazyLoadAdminTableModelInSession(portletrequest);
  18. 18. Smysluplně se vyjadřovatint days;int daysSinceCreation;int daysSinceLastModification;int daysSinceLastLogin;int daysSinceLastPasswordChange;int durationInDays;
  19. 19. Zřetelnost a výslovnostList<Car> carsList;List<Car> cars;List<Car> newCars;public class DtaRcrd{ private DateTime _geneDtDDMMYYYYhhss; private DateTime _modiDtDDMMYYYYhhss;}public class DataRecord{ private DateTime _generationDate; private DateTime _modificationDate;}
  20. 20. Jak volit správné názvy• Jména musí vysvětlovat význam.• Srozumitelné.• Vyhnout se dezinformacím.• Názvy by neměli být redundantní. – Nezahrnovat do názvu datový typ.• Vyslovitelná jména (DtaRcr).• Dodržování konvencí (?)• Nenutit nikoho přemýšlet.• Názvy z reálného světa.
  21. 21. Jak volit správné názvy• Jména tříd: – Podstatná jména.• Jména metod: – Přístupové metody dle své hodnoty (get, set, is). – Slovesa.• Jedno slovo = jeden pojem.
  22. 22. Datetime tomorrow = GetTomorrow();public DateTime GetTomorrow() { Thread.Sleep(1000*60*60*24); return DateTime.Now;}
  23. 23. OOP
  24. 24. Třídy
  25. 25. Single responsibility principle
  26. 26. public class Employee{ public int Id { get; set; } public String FirstName { get; set; } public String LastName { get; set; } public Money CalculatePay() { ... } public String ReportHours() { ... } ; public Report Save() { ... }}
  27. 27. public class Employee{ public int Id { get; set; } public String FirstName { get; set; } public String LastName { get; set; }}public class PayCalculator{ public Money CalculatePay(Employee employee) { … }}public class EmployeeReporter{ public Report ReportHours(Employee employee) { … }}public class EmployeeRepository{ public void Save() { … }}
  28. 28. 100 řádků v jedné třídě 15 – 30 řádků metody 15 tříd v namespace
  29. 29. Datové třídy Dědictví
  30. 30. Dědictví a datové třídy• Dědíme jen to, co potřebujeme.• Datová třída je pouze nositelem dat. – Entity, kontejnery*• Slouží pro přenos dat (DTO).• Aktivní záznam – save, find, ... (?!)
  31. 31. public void EmailDemo(){ var email = new Email(); email.From = "jirkapenzes@hotmail.com"; email.To = "jirkapenzes@gmail.com"; email.Subject = "Spam"; email.Body = "Posílám tu URL - tinyurl.com/6s6s63p "; email.Send();}var email = new Email();email.From = "jirkapenzes@hotmail.com";email.To = "jirkapenzes@gmail.com";email.Subject = "Spam";email.Body = "Posílám tu URL - tinyurl.com/6s6s63p";var emailSender = new EmailSender();emailSender.Send(email);
  32. 32. Jak na metody a funkce
  33. 33. Pravidla• 1. Metoda musí být malá.• 2. Metoda musí být ještě menší.• 3. Metoda by měla dělat pouze jednu věc.• 4. Volit správný název!• 5. Minimum zanoření (jedno).
  34. 34. Argumenty funkce
  35. 35. Pravidla• Žádný == super.• Jeden == ok.• Dva == dejme tomu.• Tři == raději se tomu vyhnout.• Více == důkladně zdůvodnit, zda je to nutné.• Předávejte objekty.
  36. 36. Vyhnout se příkazu switch Nepoužívat blok ‚else‘
  37. 37. public Record ExecuteCommand(Command command){ switch(command.Type) { case Standard: return ExecuteStandardCommand(command); case Complex: return ExecuteComplexCommand(command); default: throw new InvalidExecuteType(); } }
  38. 38. public abstract class Command { public abstract Record Execute();}
  39. 39. public abstract class Command { public abstract Record Execute();}public interface ICommandFactory { public Command MakeCommand(CommandRecord commandRecord);}
  40. 40. public abstract class Command { public abstract Record Execute();}public interface ICommandFactory { Command MakeCommand(CommandRecord commandRecord);}public class CommandFactory : ICommandFactory { public Command MakeCommand(CommandRecord commandRecord) { switch (commandRecord.Type) { case Standard: return new StandardCommand(commandRecord); case Complex: return new ComplexCommand(commandRecord); default: throw new InvalidExecuteRecordType(); } }}
  41. 41. Command command = commandFactory.MakeCommand(record);Result result = command.Execute();
  42. 42. Command command = commandFactory.MakeCommand(record);Result result = command.Execute();
  43. 43. Neopakovat se
  44. 44. Zpracování chyb
  45. 45. Zásady dobrého zpracování chyb• Používat výjimky!• Nepoužívat návratové kódy.• Nepředávat a nevracet hodnotu null.• Pište defenzivně.• Předávat informace o chybě.• Kontrolované výjimky (Java).
  46. 46. public void Add(Car car) { if (car != null) { CarGarage garage = context.FindCarGarage(); if (garage != null) { garage.Add(car); } }}public void Add(Car car) { CarGarage garage = context. FindCarGarage(); garage.Add(car);}
  47. 47. List<Car> cars = GetCars();if (cars != null) for(Car car : cars) { Repair(car); }List<Car> cars = GetCars();for(Car car : cars) { Repair(car);}
  48. 48. Komentáře(self documentation)
  49. 49. Práce s datyObjekty a struktury
  50. 50. Práce s daty• Při práci s daty se snažit o nezávislost.• Odstínění datového zdroje.• Repository pattern, DAO.
  51. 51. const string query= "select name, isbn from book where year = @year";using (var connection = new SqlConnection(connectionString)){ connection.Open(); var sqlCommand = new SqlCommand(query, connection); sqlCommand.Parameters.AddWithValue("@year", year); var reader = sqlCommand.ExecuteReader(); while (reader.Read()) { var book = new Book { Name = reader["name"], Isbn = reader["isbn"] }; Display(book); }}
  52. 52. const string query= MakeSqlQuery(BookQuery.FindBooksByYear);using (var connection = new SqlConnection(connectionString)){ connection.Open(); var sqlCommand = new SqlCommand(query, connection); sqlCommand.Parameters.AddWithValue("@year", year); var reader = sqlCommand.ExecuteReader(); while (reader.Read()) { var book = new User { Name = reader["name"], Isbn = reader["isbn"] }; Display(book); }}
  53. 53. var books = bookRepository.FindByYear(2002);foreach (var book in books) Display(book);public interface IBookRepository{ Book FindById(long id); IEnumerable<Book> FindAll(); IEnumerable<Book> FindByCategory(Category category); IEnumerable<Book> FindByAuthor(Author author); IEnumerable<Book> FindByTag(string tag);}var books = bookDao.Fetch(new BookByYearQuery(2002));foreach (var book in books) Display(book);
  54. 54. Refactoring
  55. 55. double CalculatePrice(){ // price is base price - quantity discount + shipping return _quantity * _itemPrice - Math.Max(0, _quantity - 500) * _itemPrice * 0.05 + Math.Min(_quantity * _itemPrice * 0.1, 100.0);}
  56. 56. double CalculatePrice(){ // price is base price - quantity discount + shipping double basePrice = _quantity * _itemPrice; return _quantity * _itemPrice - Math.Max(0, _quantity - 500) * _itemPrice * 0.05 + Math.Min(_quantity * _itemPrice * 0.1, 100.0);}
  57. 57. double CalculatePrice(){ // price is base price - quantity discount + shipping double basePrice = _quantity * _itemPrice; return basePrice - Math.Max(0, _quantity - 500) * _itemPrice * 0.05 + Math.Min(_quantity * _itemPrice * 0.1, 100.0);}
  58. 58. double CalculatePrice(){ // price is base price - quantity discount + shipping double basePrice = _quantity * _itemPrice; return basePrice - Math.Max(0, _quantity - 500) * _itemPrice * 0.05 + Math.Min(basePrice * 0.1, 100.0);}
  59. 59. double CalculatePrice(){ // price is base price - quantity discount + shipping double basePrice = _quantity * _itemPrice; double quantityDiscount = Math.Max(0, _quantity - 500) * _itemPrice * 0.05; return basePrice - quantityDiscount + Math.Min(basePrice * 0.1, 100.0);}
  60. 60. double CalculatePrice(){ // price is base price - quantity discount + shipping double basePrice = _quantity * _itemPrice; double quantityDiscount = Math.Max(0, _quantity - 500) * _itemPrice * 0.05; double shipping = Math.Min(basePrice * 0.1, 100.0); return basePrice - quantityDiscount + shipping;}
  61. 61. double CalculatePrice(){ // price is base price - quantity discount + shipping double basePrice = _quantity * _itemPrice; double quantityDiscount = Math.Max(0, _quantity - 500) * _itemPrice * 0.05; double shipping = Math.Min(basePrice * 0.1, 100.0); return basePrice - quantityDiscount + shipping;}
  62. 62. double CalculatePrice(){ return basePrice() - quantityDiscount() + shipping();}private double quantityDiscount() { return Math.Max(0, _quantity - 500) * _itemPrice * 0.05;}private double shipping() { return Math.Min(basePrice() * 0.1, 100.0);}private double basePrice() { return _quantity * _itemPrice;}
  63. 63. double CalculatePrice(){ return basePrice() - quantityDiscount() + shipping();}double CalculatePrice(){ // price is base price - quantity discount + shipping return _quantity * _itemPrice - Math.Max(0, _quantity - 500) * _itemPrice * 0.05 + Math.Min(_quantity * _itemPrice * 0.1, 100.0);}
  64. 64. Refactoring• Neměnit logiku aplikace.• Rozházet kód do tříd a metod.• Provádět iterativně.• Pozor na názvy. – Zloději, loupežníci, banditi, zločinci, rafani, …
  65. 65. Formátování a konvence
  66. 66. Formátování a konvence• 1. Formátovat.• 2. Dodržovat jazykové konvence.• Konvence pro přístupové metody.• Velikost písmen.• Týmové konvence.
  67. 67. Další zdroje?
  68. 68. Shrnutí• Déle přemýšlet nad názvy.• Zkusit kód častěji formátovat.• Držet se konvencí.• Testování.• Nestačí, aby to jen fungovalo …
  69. 69. Q&Ajirkapenzes@hotmail.com twitter.com/jirkapenzes

×