You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: content/010-arguments.md
+59-10Lines changed: 59 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -22,6 +22,10 @@ $fileSystem->write(
22
22
23
23
### Необязательные аргументы — в конец
24
24
25
+
При проектировании методов порядок аргументов имеет значение.
26
+
Один из самых простых и эффективных способов сделать его чище — располагать необязательные параметры в конце.
27
+
28
+
Рассмотрим пример:
25
29
```php
26
30
// Плохо ❌
27
31
$fileSystem->write(
@@ -30,6 +34,9 @@ $fileSystem->write(
30
34
'Пример данных для записи.', // Содержимое
31
35
);
32
36
```
37
+
Чтобы просто записать файл, нам приходится явно указывать `null` — значение, которое на самом деле нам не нужно.
38
+
39
+
Куда лучше такой вариант:
33
40
34
41
```php
35
42
// Хорошо ✅
@@ -39,20 +46,41 @@ $fileSystem->write(
39
46
);
40
47
```
41
48
49
+
А если нужно изменить поведение по умолчанию, мы просто добавим третий параметр:
50
+
51
+
```php
52
+
// Плохо ❌
53
+
$fileSystem->write(
54
+
'/path/to/file.txt', // Путь до файла
55
+
'Пример данных для записи.', // Содержимое
56
+
true, // Перезаписать файл, если он существует
57
+
);
58
+
```
59
+
60
+
В этом случае метод будет принимать только обязательные параметры, а необязательные будут в конце. Это делает код чище и понятнее. Так как их можно не указывать, если они не нужны.
61
+
42
62
### Как поступить, если аргументов много?
43
63
44
-
Используйте именованные аргументы
64
+
Иногда метод требует не один-два, а сразу пять или больше параметров. Передавать всё списком в строго заданном порядке — не лучшая идея. Легко перепутать аргументы, особенно если они одного типа. К тому же вызов такого метода выглядит пугающе и плохо читается.
65
+
66
+
Первое, что приходит на ум это использование ассоциативного массива:
45
67
46
68
```php
47
-
// Хорошо ✅
69
+
// Плохо ❌
48
70
$fileSystem->write(
49
71
'/path/to/file.txt',
50
72
'Пример данных для записи.',
51
-
debug: true, // Именованный параметр
73
+
[
74
+
'encoding' => 'UTF-8',
75
+
'overwrite' => true,
76
+
'debug' => true,
77
+
]
52
78
);
53
79
```
54
80
55
-
Если параметры логически связаны, создайте объект, инкапсулирующий их. Например:
81
+
Это отвратительный способ. Такой подход не даёт информации о том, какие параметры действительно ожидаются, и не позволяет IDE подсказывать возможные опции. Более того, здесь нет проверки типов — любые ошибки проявятся только во время выполнения. Это усложняет отладку и увеличивает вероятность багов.
82
+
83
+
Другая популярная попытка — создать объект, инкапсулирующий значения. Например:
56
84
57
85
```php
58
86
$config = new Config($encoding, $overwrite, $debug);
@@ -65,10 +93,31 @@ $fileSystem->write(
65
93
);
66
94
```
67
95
68
-
Такой подход упрощает передачу параметров, делает код самодокументируемым и облегчает переиспользование.
96
+
Это лишь видимость решения. Мы создали объект, который сам по себе бессмысленен: он не содержит поведения и не добавляет никакой бизнес-логики. Фактически, это тот же массив, только завернутый в класс. Польза от него — разве что автодополнение в IDE. Но теперь мы должны создавать или таскать этот объект везде, где вызываем метод `write`, что только усложняет код.
69
97
70
-
Но есть и намного лучше вариант, использоваение fluent-интерфейс.
71
-
Это это объект, методы которого возвращают самого себя, позволяя вызывать методы цепочкой:
98
+
99
+
Если язык поддерживает именованные аргументы и их количество очень-очень ограничено, стоит использовать их:
100
+
```php
101
+
$fileSystem->write(
102
+
'/path/to/file.txt',
103
+
'Пример данных для записи.',
104
+
debug: true, // Именованный параметр
105
+
);
106
+
```
107
+
Это уже лучше: вызов становится самодокументируемым, и порядок аргументов не имеет значения.
108
+
109
+
В случае языков с поддержкой именованных аргументов, можно использовать их:
110
+
111
+
```php
112
+
$fileSystem->write(
113
+
'/path/to/file.txt',
114
+
'Пример данных для записи.',
115
+
debug: true, // Именованный параметр
116
+
);
117
+
```
118
+
119
+
Но есть гораздо более выразительный и управляемый способ — **fluent-интерфейс**.
120
+
Это объект, методы которого возвращают самого себя, позволяя вызывать их цепочкой:
72
121
73
122
```php
74
123
// Хорошо ✅
@@ -80,11 +129,11 @@ $fileSystem
80
129
->write('Пример данных для записи.');
81
130
```
82
131
132
+
В этом подходе сразу видно, что происходит. Каждый шаг отделён, названия методов описывают действия, и вся цепочка читается как связный набор настроек. Такой стиль легко расширяется, хорошо покрывается тестами и открывает дорогу к более гибкой архитектуре.
83
133
134
+
### Предпочитайте объекты
84
135
85
-
### Предпочитайте обьекты
86
-
87
-
Строки, булевые, числа очень удобны в начале разработки, но проект раснет, логика усложняется, и эти простые значения не справляются.
136
+
Строки, булевые, числа очень удобны в начале разработки, но с течением времени, логика усложняется, и эти простые значения не справляются.
88
137
89
138
Что раньше было флагом `true`, теперь требует дополнительных условий:
90
139
*если админ*, *если включён режим отладки*, *если пользователь подтвердил e-mail*.
Copy file name to clipboardExpand all lines: content/014-tests.md
+5-5Lines changed: 5 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,6 @@
1
1
# Тесты
2
2
3
-
Мне не нравится, как испортили слово **тестирование**.
4
-
5
-
Тестирование испортили. Изуродовали. Потому что часто под этим подразумевают ручную проверку, что продукт работает как задумано после изменений. Это не то, что нужно разработчику, нам нужен контроль качества.
3
+
Слово **тестирование** испортили и изуродовали. Потому что часто под этим подразумевают ручную проверку, что задача которую делал разработчик работает как задумано после изменений. Это не то что нужно разработчику, нам нужен контроль качества.
6
4
7
5
Многие до сих пор думают, что тестированием занимается кто-то другой: тестировщик, QA-инженер, автоматизатор или великий господин начальник. Это не так.
8
6
@@ -11,7 +9,7 @@
11
9
12
10
### Больше юнит-тестов, меньше всего остального
13
11
14
-
В мире тестирования есть много терминов: интеграционные, e2e, smoke, UI, acceptance, snapshot, regression… Становится страшно даже начинать.
12
+
В мире тестирования есть много терминов: интеграционные, e2e, smoke, UI, acceptance, snapshot, regression… Становится страшно даже начинать перечислять. Но непосредственно на качество кода влияет только один вид тестов — юнит-тесты.
15
13
16
14
Почему? Потому что они:
17
15
- Проверяют маленькие части кода (функции, методы, классы).
@@ -47,7 +45,9 @@ public function test_returns_moon_phase_data(): void
47
45
48
46
```
49
47
50
-
Но как именно работает функция, вычисляющая фазу Луны? Как она получает данные о Луне? Как она обрабатывает дату? И вроде бы всё хорошо, но это обманка. Такой тест ничего не говорит о логике внутри. Он — витрина. Он проверяет фасад, но не фундамент. Он проверяет только конечный результат.
48
+
Это хороший тест, который проверяет, что API возвращает правильные данные для известной даты. Он проверяет, что ответ содержит нужные поля и что значения в них соответствуют ожидаемым.
49
+
50
+
Но как именно работает функция, вычисляющая фазу Луны? Как она получает данные о Луне? Как она обрабатывает дату? И вроде бы всё хорошо, но это обманка. Такой тест ничего не говорит о логике внутри. Он — витрина. Он проверяет фасад, но не фундамент. Он проверяет только конечный результат, это должно быть как вишенка на торте, а не основа.
51
51
52
52
Мы можем написать в код прямо контроллере и добавить туда с десяток функций, которые будут вызывать другие функции, и в итоге получим правильный ответ. Но это фигня.
0 commit comments