15. содержательные имена
имя должно передавать намерение программиста
// elapsed time in days int elapsedTimeInDays;
int d; int daysSinceCreation;
int dd; int daysSinceModification;
int d2; int fileAgeInDays;
16. Явный код
Неявный код
лучше неявного
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;
возвращаемое значение? }
17. Явный код
Неявный код
лучше неявного
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;
возвращаемое значение? }
18. избегайте дезинформации
• избегайте названий, значение которых
зависит от контекста
hp - hipotenuse
aix - augmentationIndex
sco - spaceControlOficer
• hp, aix, sco - названия Unix платформ
19. избегайте дезинформации
• аккуратно используйте специфические
программерские названия
accountList - type of List<T>?
• используйте альтернативные названия
accountGroup
bunchOfAccounts
accounts
23. используйте произносимые
имена
• 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";
};
24. используйте имена, удобные
для поиска
• используйте имена переменных из одной
буквы только в локальной области
видимости в маленьких методах
e - самая встречаемая буква алфавита
• не используйте численные константы
MAX_CLASSES_PER_STUDENT вместо 7
25. используйте имена, удобные
для поиска
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;
}
26. названия методов
• должны выражать действие
• с перегруженными конструкторами
можно использовать static factory
методы с названиями, описывающими
агрументы
Complex fulcrumPoint = new Complex(23.0);
Complex fulcrumPoint = Complex.FromRealNumber(23.0);
27. размер методов
• методы должны быть маленкими
• еще меньше!
• это подразумевает однострочные if, esle,
while (названия методов отлично
документируют ветвление)
• и вложенные структуры не глубже
второго уровня
29. правило одной операции
• функция должна выполнять только одну
операцию
• она должна выполнять ее хорошо
• и ничего другого она делать не должна
• один уровень абстракции на функцию
31. аргументы функции
• zero (niladic) - наилучший вариант
• one (monadic)
• two (dyadic)
• three (triadic)
• more (polyadic) - следует избегать
32. аргументы функции
• с точки зрения тестирования малое
количество аргументов упрощает
перебор комбинаций
• использование выходных аргументов
нарушает общую идею подачи исходных
данных в качестве аргументов и
получение результата через
возвращаемое значение функции
34. типичные случаи monadic
• проверка условия, связанного с
аргументом
boolean contains(“MyValue”)
• обработка аргумента, его
преобразование и возвращение
InputStream fileOpen(“MyFile”)
• сообщение о событии
void passwordAttemptFailedNtimes(int attempts)
35. типичные случаи monadic
• старайтесь избегать выходных
аргументов
void transform(StringBuffer out)
• используйте возвращаемое значение
StringBuffer transform(StringBuffer in)
37. типичные случаи diadic
• более сложны для понимания
writeField(outputStream, name) ->
outputStream.writeField(name)
• подходят для агрументов с естественным
порядком
Point p = new Point(x,y);
38. типичные случаи diadic
• если порядок не известен, можно
преобразовать в monadic
compare(expected, actual) -> object.compare(expected)
40. разделение команд и запросов
• функция должна либо делать что-то,
либо отвечать на какой-то вопрос, но не
оба действия вместе
public boolean set(String attribute, String value);
if (set("username", "unclebob"))...
• метод устанавливает атрибут?
• или метод проверяет значение атрибута?
41. разделение команд и запросов
public boolean setAndCheckIfExists(String attribute,
String value);
if (attributeExists("username")) {
setAttribute("username", "unclebob");
...
}
44. комментарии
• не делают плохой код лучше
• объясняйте при помощи кода
// 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) ...
45. комментарии
• закомментированный код должен
удаляться
• для читателя такой код означает, что есть
серьезная причина, по которой этот код
не был удален
46. форматирование
• вертикальное форматирование и метафора
газетной статьи
• первый параграф дает вам общее описание
статьи
• прочитав его, вы определяете, та ли это статья,
которая вам нужна
• чем дальше, тем больше дателей
• газета состоит из статей маленьких и побольше
• если бы газета состояла из одной большой
статьи, ее невозможно было бы читать
47. классы
• классы должны быть маленькие
• еще меньше!
• единица измерения - количество
обязанностей (responsibility count)
48. название класса
• должно выражать его обязанность
• название, по сути, один из первых
способов определить размер класса
• слова Processor, Manager, Super указывают
на совмещение обязанностей
• опишите класс в 25 словах, не
употребляя “если”, “и”, “или”, “но”
49. Single Responsibility Principle
• утверждает, что класс или модуль должен
иметь одну и только одну причину для
изменения
• наиболее часто игнорируется
программистами, т.к. считают, что их
работа закончена после того, как код
начал работать
50. 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();
}
51. связность
• классы должны иметь небольшое
количество переменных экземпляра
• каждый метод класса должен
оперировать с этими переменными
• чем больше переменных, с которыми
оперируют методы (для каждого
метода), тем выше связность
52. 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;
}
}
54. что еще в этой книге?
• обработка ошибок
• модульные тесты
• системы
• формирование архитектуры
• многопоточность
• smells and heruistics
55. литература
• 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