[JAM 1.1] Clean Code (Paul Malikov)

1,049 views

Published on

Clean Code

Published in: Technology
  • Be the first to comment

[JAM 1.1] Clean Code (Paul Malikov)

  1. 1. Понятный кодPaul Malikov
  2. 2. содержание• в чем проблема?• названия• функции• комментарии• форматирование• классы
  3. 3. в чем проблема?
  4. 4. в чем проблема?
  5. 5. в чем проблема?
  6. 6. в чем проблема?
  7. 7. содержательные именаимя должно передавать намерение программиста // elapsed time in days int elapsedTimeInDays; int d; int daysSinceCreation; int dd; int daysSinceModification; int d2; int fileAgeInDays;
  8. 8. Явный код Неявный код лучше неявногоpublic List<int[]> getThem() { List<int[]> list1 = public List<int[]> getFlaggedCells() { new ArrayList<int[]>(); List<int[]> flaggedCells = new ArrayList<int[]>(); for (int[] x : theList) for (int[] cell : gameBoard) if (x[0] == 4) if (cell[STATUS_VALUE] == FLAGGED) list1.add(x); flaggedCells.add(cell); return flaggedCells; return list1; }}1. Что хранится в theList? public List<Cell> getFlaggedCells() {2. Почему так важен нулевой List<Cell> flaggedCells = new ArrayList<Cell>();элемент x[0]? for (Cell cell : gameBoard)3. Что означает 4? if (cell.isFlagged()) flaggedCells.add(cell);4. Как использовать return flaggedCells;возвращаемое значение? }
  9. 9. Явный код Неявный код лучше неявногоpublic List<int[]> getThem() { List<int[]> list1 = public List<int[]> getFlaggedCells() { new ArrayList<int[]>(); List<int[]> flaggedCells = new ArrayList<int[]>(); for (int[] x : theList) for (int[] cell : gameBoard) if (x[0] == 4) if (cell[STATUS_VALUE] == FLAGGED) list1.add(x); flaggedCells.add(cell); return flaggedCells; return list1; }}1. Что хранится в theList? public List<Cell> getFlaggedCells() {2. Почему так важен нулевой List<Cell> flaggedCells = new ArrayList<Cell>();элемент x[0]? for (Cell cell : gameBoard)3. Что означает 4? if (cell.isFlagged()) flaggedCells.add(cell);4. Как использовать return flaggedCells;возвращаемое значение? }
  10. 10. избегайте дезинформации• избегайте названий, значение которых зависит от контекста hp - hipotenuse aix - augmentationIndex sco - spaceControlOficer• hp, aix, sco - названия Unix платформ
  11. 11. избегайте дезинформации• аккуратно используйте специфические программерские названия accountList - type of List<T>?• используйте альтернативные названия accountGroup bunchOfAccounts accounts
  12. 12. избегайте дезинформации• избегайте слабо отличающихся имен XYZControllerForHandlingOfStrings XYZControllerForStorageOfStrings
  13. 13. избегайте дезинформации • не используйте последовательную нумерациюpublic static void copyChars(char a1[], char a2[]) { for (int i = 0; i < a1.length; i++) { a2[i] = a1[i]; }}public static void copyChars( char source[], char destination[]) { for (int i = 0; i < source.length; i++) { destination[i] = source[i]; }}
  14. 14. избегайте дезинформации• не используйте лишние слова (noise words) ProductInfo - Product theMessage - message moneyAmount - money accountData - account
  15. 15. используйте произносимые имена• humans are good in words class DtaRcrd102 { private Date genymdhms; private Date modymdhms; private final String pszqint = "102"; }; class Customer { private Date generationTimestamp; private Date modificationTimestamp; private final String recordId = "102"; };
  16. 16. используйте имена, удобные для поиска• используйте имена переменных из одной буквы только в локальной области видимости в маленьких методахe - самая встречаемая буква алфавита• не используйте численные константы MAX_CLASSES_PER_STUDENT вместо 7
  17. 17. используйте имена, удобные для поискаfor (int j=0; j<34; j++) { s += (t[j]*4)/5;}int realDaysPerIdealDay = 4;const int WORK_DAYS_PER_WEEK = 5;int sum = 0;for (int j=0; j < NUMBER_OF_TASKS; j++) { int realTaskDays = taskEstimate[j] * realDaysPerIdealDay; int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK); sum += realTaskWeeks;}
  18. 18. названия методов• должны выражать действие• с перегруженными конструкторами можно использовать static factory методы с названиями, описывающими агрументыComplex fulcrumPoint = new Complex(23.0);Complex fulcrumPoint = Complex.FromRealNumber(23.0);
  19. 19. размер методов• методы должны быть маленкими• еще меньше!• это подразумевает однострочные if, esle, while (названия методов отлично документируют ветвление)• и вложенные структуры не глубже второго уровня
  20. 20. public static String renderPageWithSetupsAndTeardowns( PageData pageData, boolean isSuite) throws Exception { boolean isTestPage = pageData.hasAttribute("Test"); if (isTestPage) { WikiPage testPage = pageData.getWikiPage(); StringBuffer newPageContent = new StringBuffer(); includeSetupPages(testPage, newPageContent, isSuite); newPageContent.append(pageData.getContent()); includeTeardownPages(testPage, newPageContent, isSuite); pageData.setContent(newPageContent.toString()); } return pageData.getHtml();}public static String renderPageWithSetupsAndTeardowns( PageData pageData, boolean isSuite) throws Exception { if (isTestPage(pageData)) includeSetupAndTeardownPages(pageData, isSuite); return pageData.getHtml();}
  21. 21. правило одной операции• функция должна выполнять только одну операцию• она должна выполнять ее хорошо• и ничего другого она делать не должна• один уровень абстракции на функцию
  22. 22. private void includeSetupAndTeardownPages() { includeSetupPages(); includePageContent(); includeTeardownPages(); updatePageContent();}private void includeSetupPages() { if (isSuite) includeSuiteSetupPage(); includeSetupPage();}private void includeSuiteSetupPage() { include(SuiteResponder.SUITE_SETUP_NAME, "-setup");}private void includeSetupPage() { include("SetUp", "-setup");}private void includePageContent() { newPageContent.append(pageData.getContent());}
  23. 23. аргументы функции• zero (niladic) - наилучший вариант• one (monadic)• two (dyadic)• three (triadic)• more (polyadic) - следует избегать
  24. 24. аргументы функции• с точки зрения тестирования малое количество аргументов упрощает перебор комбинаций• использование выходных аргументов нарушает общую идею подачи исходных данных в качестве аргументов и получение результата через возвращаемое значение функции
  25. 25. niladicvoid saveTheMankind()
  26. 26. типичные случаи monadic• проверка условия, связанного с аргументом boolean contains(“MyValue”)• обработка аргумента, его преобразование и возвращение InputStream fileOpen(“MyFile”)• сообщение о событии void passwordAttemptFailedNtimes(int attempts)
  27. 27. типичные случаи monadic• старайтесь избегать выходных аргументов void transform(StringBuffer out)• используйте возвращаемое значение StringBuffer transform(StringBuffer in)
  28. 28. monadicMrs marry(Miss girl)
  29. 29. типичные случаи diadic• более сложны для понимания writeField(outputStream, name) -> outputStream.writeField(name)• подходят для агрументов с естественным порядком Point p = new Point(x,y);
  30. 30. типичные случаи diadic• если порядок не известен, можно преобразовать в monadiccompare(expected, actual) -> object.compare(expected)
  31. 31. diadiccompare(expected, actual)
  32. 32. разделение команд и запросов • функция должна либо делать что-то, либо отвечать на какой-то вопрос, но не оба действия вместе public boolean set(String attribute, String value); if (set("username", "unclebob"))... • метод устанавливает атрибут? • или метод проверяет значение атрибута?
  33. 33. разделение команд и запросов public boolean setAndCheckIfExists(String attribute, String value); if (attributeExists("username")) { setAttribute("username", "unclebob"); ... }
  34. 34. использование исключений• старайтесь использовать исключения вместо кодов ошибок в качестве возвращаемого значения
  35. 35. if (deletePage(page) == E_OK) { if (registry.deleteReference(page.name) == E_OK) { if (configKeys.deleteKey(page.name.makeKey()) == E_OK) { logger.log("page deleted"); } else { logger.log("configKey not deleted"); } } else { logger.log("deleteReference from registry failed"); }} else { logger.log("delete failed"); return E_ERROR;}try { deletePage(page); registry.deleteReference(page.name); configKeys.deleteKey(page.name.makeKey());} catch (Exception e) { logger.log(e.getMessage());}
  36. 36. комментарии • не делают плохой код лучше • объясняйте при помощи кода// Check to see if the employee is eligible for full benefitsif ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) ...if (employee.isEligibleForFullBenefits()) ...boolean isEligibleForFullBenefits = (employee.flags & HOURLY_FLAG) && (employee.age > 65);if (isEligibleForFullBenefits) ...
  37. 37. комментарии• закомментированный код должен удаляться• для читателя такой код означает, что есть серьезная причина, по которой этот код не был удален
  38. 38. форматирование• вертикальное форматирование и метафора газетной статьи• первый параграф дает вам общее описание статьи• прочитав его, вы определяете, та ли это статья, которая вам нужна• чем дальше, тем больше дателей• газета состоит из статей маленьких и побольше• если бы газета состояла из одной большой статьи, ее невозможно было бы читать
  39. 39. классы• классы должны быть маленькие• еще меньше!• единица измерения - количество обязанностей (responsibility count)
  40. 40. название класса• должно выражать его обязанность• название, по сути, один из первых способов определить размер класса• слова Processor, Manager, Super указывают на совмещение обязанностей• опишите класс в 25 словах, не употребляя “если”, “и”, “или”, “но”
  41. 41. Single Responsibility Principle• утверждает, что класс или модуль должен иметь одну и только одну причину для изменения• наиболее часто игнорируется программистами, т.к. считают, что их работа закончена после того, как код начал работать
  42. 42. public class SuperDashboard { public Component getLastFocusedComponent(); public void setLastFocused(Component lastFocused); public int getMajorVersionNumber(); public int getMinorVersionNumber(); public int getBuildNumber()}public class Version { public int getMajorVersionNumber(); public int getMinorVersionNumber(); public int getBuildNumber();}
  43. 43. связность• классы должны иметь небольшое количество переменных экземпляра• каждый метод класса должен оперировать с этими переменными• чем больше переменных, с которыми оперируют методы (для каждого метода), тем выше связность
  44. 44. public class Stack { private int topOfStack = 0; List<Integer> elements = new LinkedList<Integer>(); public int size() { return topOfStack; } public void push(int element) { topOfStack++; elements.add(element); } public int pop() throws PoppedWhenEmpty { if (topOfStack == 0) throw new PoppedWhenEmpty(); int element = elements.get(--topOfStack); elements.remove(topOfStack); return element; }}
  45. 45. связность• разбиение функций ведет к снижению связности• если классы утрачивают связность, разбейте их!
  46. 46. что еще в этой книге?• обработка ошибок• модульные тесты• системы• формирование архитектуры• многопоточность• smells and heruistics
  47. 47. литература• Robert C. Martin, Clean Code. A Handbook of Agile Software Craftsmanship - ISBN-13: 978-0-13-235088-4• Robert C. Martin, Agile Principles, Patterns, and Practices ISBN-13: 978-0135974445• Martin Fowler, Refactoring: Improving the Design of Existing Code ISBN-13: 978-0201485677

×