Границы применимости Tuple и Pair в разработке.md
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
b0049d8c75
commit
0bb526597a
142
dev/java/Границы применимости Tuple и Pair в разработке.md
Normal file
142
dev/java/Границы применимости Tuple и Pair в разработке.md
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
---
|
||||||
|
aliases:
|
||||||
|
tags:
|
||||||
|
- maturity/🌱
|
||||||
|
- type/opinion
|
||||||
|
date: 2024-09-17
|
||||||
|
zero-link:
|
||||||
|
- "[[../../meta/zero/00 Java разработка|00 Java разработка]]"
|
||||||
|
parents:
|
||||||
|
linked:
|
||||||
|
---
|
||||||
|
## Тезисы
|
||||||
|
- Публичные методы интерфейсов должны быть самодокументируемыми и понятными без дополнительных комментариев.
|
||||||
|
- `Tuple` в публичных методах снижает читаемость и может запутать других разработчиков.
|
||||||
|
- `Tuple` в аргументах метода также может снизить ясность и увеличить вероятность ошибок.
|
||||||
|
- В приватных методах `Tuple` допустим, если используется внутри класса и не нарушает ясность.
|
||||||
|
- В реактивных пайпах `Tuple` могут быть полезны для временного объединения значений.
|
||||||
|
- Извлечение данных из `Tuple` в локальные переменные улучшает читаемость реактивных пайпов.
|
||||||
|
- Если вы на проекте один и никто другой код читать не будет, можете использовать `Tuple` как угодно 😁
|
||||||
|
***
|
||||||
|
Некоторые языки программирования, такие как Go, позволяют возвращать из функции несколько значений сразу. В Java, однако, метод может вернуть только одно значение, и зачастую хочется вернуть сразу два — например, пару связанных данных. Конечно, правильный подход — создать объект с двумя полями, но часто на практике оказывается, что проще и быстрее использовать готовые решения вроде классов `Tuple` и `Pair`, которые служат обертками.
|
||||||
|
|
||||||
|
Но прежде чем полагаться на эти классы, важно понять их границы применимости. Для упрощения дальнейшего объяснения я буду использовать `Tuple` как пример, но все сказанное ниже также относится и к `Pair`.
|
||||||
|
## Возвращаем Tuple в публичном методе
|
||||||
|
Публичные методы интерфейсов — это своего рода контракты между вами, разработчиком функциональности, и клиентом, то есть другим разработчиком, который будет использовать ваш код для решения своих задач.
|
||||||
|
|
||||||
|
==Так как большую часть времени разработчик не пишет, а читает чужой код, важно, чтобы этот контракт был понятен без дополнительных пояснений и комментариев.==
|
||||||
|
|
||||||
|
Представим, что вам нужно вернуть имя пользователя и его возраст. На первый взгляд, использование `Tuple` может показаться удобным решением: не нужно создавать новый класс, а возвращать сразу несколько значений — легко и быстро.
|
||||||
|
|
||||||
|
И ваш контракт (интерфейс) выглядит следующим образом:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public interface UserService {
|
||||||
|
Tuple<String, Integer> getUserData(String userId);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Посмотрев на контакт `getUserData(userId)` сможет ли другой разработчик сказать какие результаты он получит? Вряд ли.
|
||||||
|
|
||||||
|
Недостатки такого использования:
|
||||||
|
- **Снижение читабельности кода:** Клиенту интерфейса будет неочевидно, что именно содержится в возвращаемом `Tuple`. В отличие от специально созданного класса с понятными именами полей, `Tuple` не говорит напрямую, что первое значение — это имя, а второе — возраст. Это усложняет понимание и использование метода.
|
||||||
|
- **Отсутствие самодокументируемости:** Хорошо продуманные классы и методы сами по себе выступают как документация, тогда как `Tuple<String, Integer>` требует дополнительных пояснений или комментариев, чтобы разработчики понимали, что происходит. ==Вы заставляете других разработчиков тратить больше времени на понимание логики метода.==
|
||||||
|
- **Повышенная вероятность ошибок:** Использование неименованных полей увеличивает риск случайных ошибок, например, при изменении порядка полей. Разработчики могут легко перепутать значения и передать их неправильно. Особенно если тип у значений совпадает.
|
||||||
|
- **Сложности с расширяемостью:** Если в будущем потребуется расширить возвращаемые данные, интерфейс с `Tuple` станет менее гибким.
|
||||||
|
## Tuple в аргументах метода
|
||||||
|
Когда методы принимают несколько параметров, иногда может возникнуть желание объединить их в `Tuple`, чтобы упростить сигнатуру метода или передать параметры в одном объекте. На первый взгляд, это кажется удобным, особенно если типы данных уже известны, и не хочется создавать отдельный класс.
|
||||||
|
|
||||||
|
Особенно сильно такое желание возникает, когда вы вызываете публичный метод, который возвращает `Tuple`, и вам нужны все его результаты. В таких ситуациях кажется логичным продолжать работать с `Tuple`, чтобы избежать излишней детализации и создавать меньше кода. [[../../psychology/Нисходящая спираль|Нисходящая спираль]] закручивается 😊
|
||||||
|
|
||||||
|
Представим, что ваш метод выглядит следующим образом. И в этот метод приходит другой разработчик, которому нужно добавить новую фичу или исправить баг и он видит вот это:
|
||||||
|
|
||||||
|
```java
|
||||||
|
public void processUserData(Tuple<String, Integer> userData) {
|
||||||
|
// Логика обработки данных
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Какие проблемы могут возникнуть при таком подходе. На самом деле все те же:
|
||||||
|
- **Пониженная читаемость и ясность кода:** Как и в случае с возвращаемыми значениями, использование `Tuple` не даёт ясности о том, что именно передаётся в метод. Из сигнатуры метода непонятно, что строка представляет имя пользователя, а целое число — возраст.
|
||||||
|
- **Нарушение принципа самодокументируемого кода
|
||||||
|
- **Увеличение вероятности ошибок**
|
||||||
|
- **Сложности с изменениями и расширением кода**
|
||||||
|
## Возвращаем Tuple в приватном методе
|
||||||
|
В отличие от публичных методов, приватные методы находятся внутри границ одного класса и, не участвуют в контрактах. Это дает больше свободы в выборе структур данных для внутренних операций.
|
||||||
|
|
||||||
|
Возвращение `Tuple` из приватного метода может оказаться разумным решением, когда нужно быстро вернуть несколько значений без создания дополнительных классов. Например:
|
||||||
|
|
||||||
|
```java
|
||||||
|
private Tuple<String, Integer> fetchUserData() {
|
||||||
|
// Логика получения данных
|
||||||
|
return new Tuple<>("John Doe", 30);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Когда использовать `Tuple` уместно:
|
||||||
|
- Если данные возвращаются только внутри приватного метода и используются в узком контексте, где значение каждого элемента `Tuple` очевидно из контекста вызова.
|
||||||
|
- Если метод временный и планируется рефакторинг, или когда требуется быстрое прототипирование.
|
||||||
|
|
||||||
|
Преимущества использования `Tuple` в приватных методах:
|
||||||
|
- **Удобство и скорость реализации:** Использование `Tuple` может значительно сократить время на реализацию, особенно когда речь идет о простых данных и методах, которые используются в узких контекстах.
|
||||||
|
- **Снижение избыточности кода:** Если данные нужны только внутри класса и их использование ограничено несколькими методами, создание отдельного класса может казаться избыточным. `Tuple` позволяет избежать ненужной сложности и дополнительных файлов.
|
||||||
|
|
||||||
|
Тем не менее, стоит помнить о проблемах Tuple. Если логика метода со временем усложниться, читаемость кода может понизится.
|
||||||
|
|
||||||
|
**Когда стоит задуматься о создании отдельного класса:**
|
||||||
|
- Если структура данных становится сложной или используется в нескольких местах внутри класса.
|
||||||
|
- Если потребуется передавать данные в другие классы в будущем.
|
||||||
|
- Если работа с данными требует дополнительной логики, такой как валидация или преобразование.
|
||||||
|
## Tuple в реактивном программировании
|
||||||
|
В [[../../../../knowledge/dev/Реактивное программирование|реактивном программировании]], особенно с использованием [[../../meta/zero/00 Quarkus|Quarkus]] и Mutiny, часто возникает необходимость передачи нескольких значений между стадиями реактивного потока данных. `Tuple` может быть удобным решением для объединения значений, особенно когда результат остаётся внутри потока и не становится частью публичного API.
|
||||||
|
|
||||||
|
Например, в реактивных пайпах могут использоваться такие структуры, как `Tuple2`, `Tuple3` и далее:
|
||||||
|
|
||||||
|
```java
|
||||||
|
Uni<User> userUni = getUser()
|
||||||
|
...
|
||||||
|
.onItem().invoke(tuple -> {
|
||||||
|
String name = tuple.getItem1();
|
||||||
|
int age = tuple.getItem2();
|
||||||
|
// Дальнейшая обработка
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Здесь `Tuple2` используется для объединения имени и возраста пользователя, ==и значения извлекаются в локальные переменные с понятными именами.== Если нужно объединить больше значений, можно использовать `Tuple3`, `Tuple4` и так далее:
|
||||||
|
|
||||||
|
```java
|
||||||
|
Uni<Order> orderUni = getOrder()
|
||||||
|
...
|
||||||
|
.onItem().invoke(tuple -> {
|
||||||
|
String orderId = tuple.getItem1();
|
||||||
|
double total = tuple.getItem2();
|
||||||
|
LocalDate date = tuple.getItem3();
|
||||||
|
// Дальнейшая обработка
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Когда использование различных Tuple оправдано:
|
||||||
|
- **Переходные стадии в пайпах:** Внутри реактивных потоков, `Tuple2`, `Tuple3` и другие позволяют временно объединять нужное количество значений для обработки, сохраняя компактность и удобство.
|
||||||
|
- **Локальные переменные для улучшения читаемости:** Извлечение значений `Tuple` в локальные переменные с осмысленными именами значительно улучшает читаемость кода и упрощает понимание логики.
|
||||||
|
|
||||||
|
Ограничения:
|
||||||
|
- **Сложность при увеличении количества элементов:** Чем больше значений объединяется в `Tuple` (например, `Tuple4`, `Tuple5` и далее), тем сложнее становится поддерживать и понимать код. В таких случаях лучше рассмотреть создание именованных классов.
|
||||||
|
- **Не использовать в публичных методах:** Если `Tuple` выходит за границы класса, в публичные методы или интерфейсы, использование именованных структур данных предпочтительнее для улучшения читаемости и поддержки.
|
||||||
|
## Заключение
|
||||||
|
Использование `Tuple` в различных сценариях — будь то публичные методы, приватные методы или реактивные пайпы — всегда требует баланса между удобством и читаемостью кода. `Tuple` может быть полезным инструментом в определённых ситуациях, но стоит помнить, что ясность и поддерживаемость кода зачастую важнее мгновенного выигрыша в скорости разработки. Создание именованных классов или record помогает сделать код самодокументируемым, снижает вероятность ошибок и упрощает дальнейшую поддержку.
|
||||||
|
|
||||||
|
Однако, если вы на проекте один и точно уверены, что других разработчиков там никогда не появится, то можете использовать Tuple как хотите 😁
|
||||||
|
|
||||||
|
Но в большинстве случаев, лучше следовать правилам и заботиться о тех, кто будет работать с вашим кодом в будущем. Ведь читаемость и ясность всегда остаются ключевыми аспектами качественного программирования.
|
||||||
|
***
|
||||||
|
## Мета информация
|
||||||
|
**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]]
|
||||||
|
**Родитель**::
|
||||||
|
**Источник**::
|
||||||
|
**Создана**:: [[2024-09-17]]
|
||||||
|
**Автор**::
|
||||||
|
### Дополнительные материалы
|
||||||
|
-
|
||||||
|
|
||||||
|
### Дочерние заметки
|
||||||
|
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
@ -25,6 +25,7 @@ title: Java разработка
|
|||||||
- [Сравнение enum в Java](../../dev/java/Сравнение%20enum%20в%20Java.md)
|
- [Сравнение enum в Java](../../dev/java/Сравнение%20enum%20в%20Java.md)
|
||||||
- [Не используйте @Data](../../dev/java/Не%20используйте%20@Data.md)
|
- [Не используйте @Data](../../dev/java/Не%20используйте%20@Data.md)
|
||||||
- [Возвращайте пустую коллекцию вместо null](../../dev/java/Возвращайте%20пустую%20коллекцию%20вместо%20null.md)
|
- [Возвращайте пустую коллекцию вместо null](../../dev/java/Возвращайте%20пустую%20коллекцию%20вместо%20null.md)
|
||||||
|
- [[../../dev/java/Границы применимости Tuple и Pair в разработке|Границы применимости Tuple и Pair в разработке]]
|
||||||
## Версии Java
|
## Версии Java
|
||||||
- [[Java 1]]
|
- [[Java 1]]
|
||||||
- [Java 7](Java%207.md)
|
- [Java 7](Java%207.md)
|
||||||
|
26
psychology/Восходящая спираль.md
Normal file
26
psychology/Восходящая спираль.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
aliases:
|
||||||
|
tags:
|
||||||
|
- maturity/🌱
|
||||||
|
date: "[[2023-10-24]]"
|
||||||
|
zero-link:
|
||||||
|
- "[[../meta/zero/00 Психология|00 Психология]]"
|
||||||
|
- "[[../meta/zero/00 Продуктивность|00 Продуктивность]]"
|
||||||
|
parents:
|
||||||
|
linked:
|
||||||
|
- "[[Нисходящая спираль]]"
|
||||||
|
author:
|
||||||
|
- "[[Алекс Корб]]"
|
||||||
|
---
|
||||||
|
Восходящая спираль - это цепочка событий, в которых одно хорошее решение приводит к следующему. Например, вы хорошо выспались, поэтому чувствовали себя лучше и продуктивнее в течение дня, что позволило вам сделать зарядку, а зарядка помогла лучше заснуть.
|
||||||
|
***
|
||||||
|
## Мета информация
|
||||||
|
**Область**:: [[../meta/zero/00 Продуктивность|00 Продуктивность]], [[../meta/zero/00 Психология|00 Психология]]
|
||||||
|
**Родитель**::
|
||||||
|
**Источник**::
|
||||||
|
**Автор**:: [[../../../wiki/people/Алекс Корб|Алекс Корб]]
|
||||||
|
**Создана**:: [[2023-10-24]]
|
||||||
|
### Дополнительные материалы
|
||||||
|
- [[Нисходящая спираль]]
|
||||||
|
### Дочерние заметки
|
||||||
|
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
29
psychology/Нисходящая спираль.md
Normal file
29
psychology/Нисходящая спираль.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
---
|
||||||
|
aliases:
|
||||||
|
- нисходящая спираль
|
||||||
|
- замкнутый круг
|
||||||
|
tags:
|
||||||
|
- maturity/🌱
|
||||||
|
date: "[[2023-10-24]]"
|
||||||
|
zero-link:
|
||||||
|
- "[[../meta/zero/00 Продуктивность|00 Продуктивность]]"
|
||||||
|
- "[[../meta/zero/00 Психология|00 Психология]]"
|
||||||
|
parents:
|
||||||
|
linked:
|
||||||
|
- "[[Восходящая спираль]]"
|
||||||
|
author:
|
||||||
|
- "[[Алекс Корб]]"
|
||||||
|
---
|
||||||
|
Нисходящая спираль это цепочка событий, в которых ==одно деструктивное действие ведет к другому==, и с каждым витком становится все хуже. Например, вы не выспались, на следующий день были разбиты, поэтому не сделали зарядку, да еще и переели, расстроились из-за этого легли спать позже и так далее.
|
||||||
|
***
|
||||||
|
## Мета информация
|
||||||
|
**Область**:: [[../meta/zero/00 Продуктивность|00 Продуктивность]], [[../meta/zero/00 Психология|00 Психология]]
|
||||||
|
**Родитель**::
|
||||||
|
**Источник**::
|
||||||
|
**Автор**:: [[../../../wiki/people/Алекс Корб|Алекс Корб]]
|
||||||
|
**Создана**:: [[2023-10-24]]
|
||||||
|
### Дополнительные материалы
|
||||||
|
- [[Восходящая спираль]]
|
||||||
|
### Дочерние заметки
|
||||||
|
<!-- QueryToSerialize: LIST FROM [[]] WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) -->
|
||||||
|
|
Loading…
Reference in New Issue
Block a user