55
Понятный код Paul Malikov

[JAM 1.1] Clean Code (Paul Malikov)

Embed Size (px)

DESCRIPTION

Clean Code

Citation preview

Page 1: [JAM 1.1] Clean Code (Paul Malikov)

Понятный код

Paul Malikov

Page 2: [JAM 1.1] Clean Code (Paul Malikov)

содержание

• в чем проблема?

• названия• функции• комментарии• форматирование• классы

Page 3: [JAM 1.1] Clean Code (Paul Malikov)
Page 4: [JAM 1.1] Clean Code (Paul Malikov)
Page 5: [JAM 1.1] Clean Code (Paul Malikov)
Page 6: [JAM 1.1] Clean Code (Paul Malikov)
Page 7: [JAM 1.1] Clean Code (Paul Malikov)
Page 8: [JAM 1.1] Clean Code (Paul Malikov)
Page 9: [JAM 1.1] Clean Code (Paul Malikov)
Page 10: [JAM 1.1] Clean Code (Paul Malikov)
Page 11: [JAM 1.1] Clean Code (Paul Malikov)

в чем проблема?

Page 12: [JAM 1.1] Clean Code (Paul Malikov)

в чем проблема?

Page 13: [JAM 1.1] Clean Code (Paul Malikov)

в чем проблема?

Page 14: [JAM 1.1] Clean Code (Paul Malikov)

в чем проблема?

Page 15: [JAM 1.1] Clean Code (Paul Malikov)

содержательные имена

// elapsed time in daysint d;int dd;int d2;

int elapsedTimeInDays; int daysSinceCreation;int daysSinceModification; int fileAgeInDays;

имя должно передавать намерение программиста

Page 16: [JAM 1.1] Clean Code (Paul Malikov)

public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>(); for (int[] x : theList) if (x[0] == 4) list1.add(x); return list1;}

Неявный код

1. Что хранится в theList?2. Почему так важен нулевой элемент x[0]?3. Что означает 4?4. Как использовать возвращаемое значение?

public List<int[]> getFlaggedCells() { List<int[]> flaggedCells = new ArrayList<int[]>(); for (int[] cell : gameBoard) if (cell[STATUS_VALUE] == FLAGGED) flaggedCells.add(cell); return flaggedCells;}

public List<Cell> getFlaggedCells() { List<Cell> flaggedCells = new ArrayList<Cell>(); for (Cell cell : gameBoard) if (cell.isFlagged()) flaggedCells.add(cell); return flaggedCells;}

Явный код лучше неявного

Page 17: [JAM 1.1] Clean Code (Paul Malikov)

public List<int[]> getThem() { List<int[]> list1 = new ArrayList<int[]>(); for (int[] x : theList) if (x[0] == 4) list1.add(x); return list1;}

Неявный код

1. Что хранится в theList?2. Почему так важен нулевой элемент x[0]?3. Что означает 4?4. Как использовать возвращаемое значение?

public List<int[]> getFlaggedCells() { List<int[]> flaggedCells = new ArrayList<int[]>(); for (int[] cell : gameBoard) if (cell[STATUS_VALUE] == FLAGGED) flaggedCells.add(cell); return flaggedCells;}

public List<Cell> getFlaggedCells() { List<Cell> flaggedCells = new ArrayList<Cell>(); for (Cell cell : gameBoard) if (cell.isFlagged()) flaggedCells.add(cell); return flaggedCells;}

Явный код лучше неявного

Page 18: [JAM 1.1] Clean Code (Paul Malikov)

избегайте дезинформации

• избегайте названий, значение которых зависит от контекста

• hp, aix, sco - названия Unix платформ

hp - hipotenuseaix - augmentationIndexsco - spaceControlOficer

Page 19: [JAM 1.1] Clean Code (Paul Malikov)

избегайте дезинформации

• аккуратно используйте специфические программерские названия

• используйте альтернативные названияaccountList - type of List<T>?

accountGroupbunchOfAccounts

accounts

Page 20: [JAM 1.1] Clean Code (Paul Malikov)

избегайте дезинформации

• избегайте слабо отличающихся имен

XYZControllerForHandlingOfStringsXYZControllerForStorageOfStrings

Page 21: [JAM 1.1] Clean Code (Paul Malikov)

избегайте дезинформации

• не используйте последовательную нумерацию

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]; }}

Page 22: [JAM 1.1] Clean Code (Paul Malikov)

избегайте дезинформации

• не используйте лишние слова (noise words)

ProductInfo - ProducttheMessage - messagemoneyAmount - money

accountData - account

Page 23: [JAM 1.1] Clean Code (Paul Malikov)

используйте произносимые имена

• 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";};

Page 24: [JAM 1.1] Clean Code (Paul Malikov)

используйте имена, удобные для поиска

• используйте имена переменных из одной буквы только в локальной области видимости в маленьких методах

• не используйте численные константыMAX_CLASSES_PER_STUDENT вместо 7

e - самая встречаемая буква алфавита

Page 25: [JAM 1.1] Clean Code (Paul Malikov)

используйте имена, удобные для поиска

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;}

Page 26: [JAM 1.1] Clean Code (Paul Malikov)

названия методов

• должны выражать действие

• с перегруженными конструкторами можно использовать static factory методы с названиями, описывающими агрументы

Complex fulcrumPoint = new Complex(23.0);

Complex fulcrumPoint = Complex.FromRealNumber(23.0);

Page 27: [JAM 1.1] Clean Code (Paul Malikov)

размер методов

• методы должны быть маленкими

• еще меньше!• это подразумевает однострочные if, esle,

while (названия методов отлично документируют ветвление)

• и вложенные структуры не глубже второго уровня

Page 28: [JAM 1.1] Clean Code (Paul Malikov)

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();}

Page 29: [JAM 1.1] Clean Code (Paul Malikov)

правило одной операции

• функция должна выполнять только одну операцию

• она должна выполнять ее хорошо• и ничего другого она делать не должна

• один уровень абстракции на функцию

Page 30: [JAM 1.1] Clean Code (Paul Malikov)

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());}

Page 31: [JAM 1.1] Clean Code (Paul Malikov)

аргументы функции

• zero (niladic) - наилучший вариант

• one (monadic)

• two (dyadic)

• three (triadic)

• more (polyadic) - следует избегать

Page 32: [JAM 1.1] Clean Code (Paul Malikov)

аргументы функции

• с точки зрения тестирования малое количество аргументов упрощает перебор комбинаций

• использование выходных аргументов нарушает общую идею подачи исходных данных в качестве аргументов и получение результата через возвращаемое значение функции

Page 33: [JAM 1.1] Clean Code (Paul Malikov)

niladic

void saveTheMankind()

Page 34: [JAM 1.1] Clean Code (Paul Malikov)

типичные случаи monadic

• проверка условия, связанного с аргументом

• обработка аргумента, его преобразование и возвращение

• сообщение о событии

boolean contains(“MyValue”)

InputStream fileOpen(“MyFile”)

void passwordAttemptFailedNtimes(int attempts)

Page 35: [JAM 1.1] Clean Code (Paul Malikov)

типичные случаи monadic

• старайтесь избегать выходных аргументов

• используйте возвращаемое значениеStringBuffer transform(StringBuffer in)

void transform(StringBuffer out)

Page 36: [JAM 1.1] Clean Code (Paul Malikov)

monadic

Mrs marry(Miss girl)

Page 37: [JAM 1.1] Clean Code (Paul Malikov)

типичные случаи diadic

• более сложны для понимания

• подходят для агрументов с естественным порядком

writeField(outputStream, name) -> outputStream.writeField(name)

Point p = new Point(x,y);

Page 38: [JAM 1.1] Clean Code (Paul Malikov)

типичные случаи diadic

• если порядок не известен, можно преобразовать в monadic

compare(expected, actual) -> object.compare(expected)

Page 39: [JAM 1.1] Clean Code (Paul Malikov)

diadic

compare(expected, actual)

Page 40: [JAM 1.1] Clean Code (Paul Malikov)

разделение команд и запросов

• функция должна либо делать что-то, либо отвечать на какой-то вопрос, но не оба действия вместе

• метод устанавливает атрибут?• или метод проверяет значение атрибута?

public boolean set(String attribute, String value);

if (set("username", "unclebob"))...

Page 41: [JAM 1.1] Clean Code (Paul Malikov)

public boolean setAndCheckIfExists(String attribute, String value);

if (attributeExists("username")) { setAttribute("username", "unclebob"); ...}

разделение команд и запросов

Page 42: [JAM 1.1] Clean Code (Paul Malikov)

использование исключений

• старайтесь использовать исключения вместо кодов ошибок в качестве возвращаемого значения

Page 43: [JAM 1.1] Clean Code (Paul Malikov)

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());}

Page 44: [JAM 1.1] Clean Code (Paul Malikov)

комментарии

• не делают плохой код лучше• объясняйте при помощи кода

// Check to see if the employee is eligible for full benefits if ((employee.flags & HOURLY_FLAG) && (employee.age > 65)) ...

if (employee.isEligibleForFullBenefits()) ...

boolean isEligibleForFullBenefits = (employee.flags & HOURLY_FLAG) && (employee.age > 65);

if (isEligibleForFullBenefits) ...

Page 45: [JAM 1.1] Clean Code (Paul Malikov)

комментарии

• закомментированный код должен удаляться

• для читателя такой код означает, что есть серьезная причина, по которой этот код не был удален

Page 46: [JAM 1.1] Clean Code (Paul Malikov)

форматирование

• вертикальное форматирование и метафора газетной статьи

• первый параграф дает вам общее описание статьи

• прочитав его, вы определяете, та ли это статья, которая вам нужна

• чем дальше, тем больше дателей

• газета состоит из статей маленьких и побольше• если бы газета состояла из одной большой статьи, ее невозможно было бы читать

Page 47: [JAM 1.1] Clean Code (Paul Malikov)

классы

• классы должны быть маленькие

• еще меньше!• единица измерения - количество обязанностей (responsibility count)

Page 48: [JAM 1.1] Clean Code (Paul Malikov)

название класса

• должно выражать его обязанность• название, по сути, один из первых способов определить размер класса

• слова Processor, Manager, Super указывают на совмещение обязанностей

• опишите класс в 25 словах, не употребляя “если”, “и”, “или”, “но”

Page 49: [JAM 1.1] Clean Code (Paul Malikov)

Single Responsibility Principle

• утверждает, что класс или модуль должен иметь одну и только одну причину для изменения

• наиболее часто игнорируется программистами, т.к. считают, что их работа закончена после того, как код начал работать

Page 50: [JAM 1.1] Clean Code (Paul Malikov)

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();}

Page 51: [JAM 1.1] Clean Code (Paul Malikov)

связность

• классы должны иметь небольшое количество переменных экземпляра

• каждый метод класса должен оперировать с этими переменными

• чем больше переменных, с которыми оперируют методы (для каждого метода), тем выше связность

Page 52: [JAM 1.1] Clean Code (Paul Malikov)

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; }}

Page 53: [JAM 1.1] Clean Code (Paul Malikov)

связность

• разбиение функций ведет к снижению связности

• если классы утрачивают связность, разбейте их!

Page 54: [JAM 1.1] Clean Code (Paul Malikov)

что еще в этой книге?

• обработка ошибок• модульные тесты• системы• формирование архитектуры• многопоточность• smells and heruistics

Page 55: [JAM 1.1] Clean Code (Paul Malikov)

литература

• 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