Skip to content

Commit 0701543

Browse files
committed
WIP
1 parent 4c06209 commit 0701543

File tree

3 files changed

+71
-20
lines changed

3 files changed

+71
-20
lines changed

content/010-arguments.md

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ $fileSystem->write(
2222

2323
### Необязательные аргументы — в конец
2424

25+
При проектировании методов порядок аргументов имеет значение.
26+
Один из самых простых и эффективных способов сделать его чище — располагать необязательные параметры в конце.
27+
28+
Рассмотрим пример:
2529
```php
2630
// Плохо ❌
2731
$fileSystem->write(
@@ -30,6 +34,9 @@ $fileSystem->write(
3034
'Пример данных для записи.', // Содержимое
3135
);
3236
```
37+
Чтобы просто записать файл, нам приходится явно указывать `null` — значение, которое на самом деле нам не нужно.
38+
39+
Куда лучше такой вариант:
3340

3441
```php
3542
// Хорошо ✅
@@ -39,20 +46,41 @@ $fileSystem->write(
3946
);
4047
```
4148

49+
А если нужно изменить поведение по умолчанию, мы просто добавим третий параметр:
50+
51+
```php
52+
// Плохо ❌
53+
$fileSystem->write(
54+
'/path/to/file.txt', // Путь до файла
55+
'Пример данных для записи.', // Содержимое
56+
true, // Перезаписать файл, если он существует
57+
);
58+
```
59+
60+
В этом случае метод будет принимать только обязательные параметры, а необязательные будут в конце. Это делает код чище и понятнее. Так как их можно не указывать, если они не нужны.
61+
4262
### Как поступить, если аргументов много?
4363

44-
Используйте именованные аргументы
64+
Иногда метод требует не один-два, а сразу пять или больше параметров. Передавать всё списком в строго заданном порядке — не лучшая идея. Легко перепутать аргументы, особенно если они одного типа. К тому же вызов такого метода выглядит пугающе и плохо читается.
65+
66+
Первое, что приходит на ум это использование ассоциативного массива:
4567

4668
```php
47-
// Хорошо ✅
69+
// Плохо ❌
4870
$fileSystem->write(
4971
'/path/to/file.txt',
5072
'Пример данных для записи.',
51-
debug: true, // Именованный параметр
73+
[
74+
'encoding' => 'UTF-8',
75+
'overwrite' => true,
76+
'debug' => true,
77+
]
5278
);
5379
```
5480

55-
Если параметры логически связаны, создайте объект, инкапсулирующий их. Например:
81+
Это отвратительный способ. Такой подход не даёт информации о том, какие параметры действительно ожидаются, и не позволяет IDE подсказывать возможные опции. Более того, здесь нет проверки типов — любые ошибки проявятся только во время выполнения. Это усложняет отладку и увеличивает вероятность багов.
82+
83+
Другая популярная попытка — создать объект, инкапсулирующий значения. Например:
5684

5785
```php
5886
$config = new Config($encoding, $overwrite, $debug);
@@ -65,10 +93,31 @@ $fileSystem->write(
6593
);
6694
```
6795

68-
Такой подход упрощает передачу параметров, делает код самодокументируемым и облегчает переиспользование.
96+
Это лишь видимость решения. Мы создали объект, который сам по себе бессмысленен: он не содержит поведения и не добавляет никакой бизнес-логики. Фактически, это тот же массив, только завернутый в класс. Польза от него — разве что автодополнение в IDE. Но теперь мы должны создавать или таскать этот объект везде, где вызываем метод `write`, что только усложняет код.
6997

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+
Это объект, методы которого возвращают самого себя, позволяя вызывать их цепочкой:
72121

73122
```php
74123
// Хорошо ✅
@@ -80,11 +129,11 @@ $fileSystem
80129
->write('Пример данных для записи.');
81130
```
82131

132+
В этом подходе сразу видно, что происходит. Каждый шаг отделён, названия методов описывают действия, и вся цепочка читается как связный набор настроек. Такой стиль легко расширяется, хорошо покрывается тестами и открывает дорогу к более гибкой архитектуре.
83133

134+
### Предпочитайте объекты
84135

85-
### Предпочитайте обьекты
86-
87-
Строки, булевые, числа очень удобны в начале разработки, но проект раснет, логика усложняется, и эти простые значения не справляются.
136+
Строки, булевые, числа очень удобны в начале разработки, но с течением времени, логика усложняется, и эти простые значения не справляются.
88137

89138
Что раньше было флагом `true`, теперь требует дополнительных условий:
90139
*если админ*, *если включён режим отладки*, *если пользователь подтвердил e-mail*.

content/011-remove.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636

3737
```php
3838
// Плохо ❌
39-
class AuthService
39+
class Auth
4040
{
41-
public function generateAccessToken(int $userId): string
41+
public function generateAccessToken(): string
4242
{
43+
$userId = $this->user->getKey(),
44+
4345
// Log::info("Generating token for user: $userId");
4446

4547
$payload = [
@@ -82,12 +84,12 @@ class AuthService
8284

8385
```php
8486
// Хорошо ✅
85-
class AuthService
87+
class Auth
8688
{
87-
public function generateAccessToken(int $userId): string
89+
public function generateAccessToken(): string
8890
{
8991
return $this->signToken([
90-
'sub' => $userId,
92+
'sub' => $this->user->getKey(),
9193
'exp' => $this->calculateExpiration(),
9294
]);
9395
}

content/014-tests.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
# Тесты
22

3-
Мне не нравится, как испортили слово **тестирование**.
4-
5-
Тестирование испортили. Изуродовали. Потому что часто под этим подразумевают ручную проверку, что продукт работает как задумано после изменений. Это не то, что нужно разработчику, нам нужен контроль качества.
3+
Слово **тестирование** испортили и изуродовали. Потому что часто под этим подразумевают ручную проверку, что задача которую делал разработчик работает как задумано после изменений. Это не то что нужно разработчику, нам нужен контроль качества.
64

75
Многие до сих пор думают, что тестированием занимается кто-то другой: тестировщик, QA-инженер, автоматизатор или великий господин начальник. Это не так.
86

@@ -11,7 +9,7 @@
119

1210
### Больше юнит-тестов, меньше всего остального
1311

14-
В мире тестирования есть много терминов: интеграционные, e2e, smoke, UI, acceptance, snapshot, regression… Становится страшно даже начинать.
12+
В мире тестирования есть много терминов: интеграционные, e2e, smoke, UI, acceptance, snapshot, regression… Становится страшно даже начинать перечислять. Но непосредственно на качество кода влияет только один вид тестов — юнит-тесты.
1513

1614
Почему? Потому что они:
1715
- Проверяют маленькие части кода (функции, методы, классы).
@@ -47,7 +45,9 @@ public function test_returns_moon_phase_data(): void
4745

4846
```
4947

50-
Но как именно работает функция, вычисляющая фазу Луны? Как она получает данные о Луне? Как она обрабатывает дату? И вроде бы всё хорошо, но это обманка. Такой тест ничего не говорит о логике внутри. Он — витрина. Он проверяет фасад, но не фундамент. Он проверяет только конечный результат.
48+
Это хороший тест, который проверяет, что API возвращает правильные данные для известной даты. Он проверяет, что ответ содержит нужные поля и что значения в них соответствуют ожидаемым.
49+
50+
Но как именно работает функция, вычисляющая фазу Луны? Как она получает данные о Луне? Как она обрабатывает дату? И вроде бы всё хорошо, но это обманка. Такой тест ничего не говорит о логике внутри. Он — витрина. Он проверяет фасад, но не фундамент. Он проверяет только конечный результат, это должно быть как вишенка на торте, а не основа.
5151

5252
Мы можем написать в код прямо контроллере и добавить туда с десяток функций, которые будут вызывать другие функции, и в итоге получим правильный ответ. Но это фигня.
5353

0 commit comments

Comments
 (0)