ORGPROG Telegram 356
Программирование на флагах

Недавно я упомянул этот термин в одном и постов и получил неожиданно большое количество комментариев "что это?". Тема заслуживает раскрытия, поэтому пост.

Возьмем пример с sql:


SELECT *
FROM users
WHERE active = 1;


Почти наверняка это поле из двух состояний активен/не активен (1/0), где активность определяется подтверждением емейла. В Postgresql это было бы true/false.

В целом, этот код выглядит совершенно нормально и очень хорошо работает. До поры до времени. А потом выясняется, что «неактивный» бывает как «удалённый», так и «заблокированный». Или, например, мы (бизнес) захотим давать работать на сайте тем кто зарегистрировался, но не подтвердил емейл. Подтверждение емейла будет работать как способ получить больше функций. В сумме мы получаем:

⁃ зарегистрированный
⁃ активный (подтвержден емейл)
⁃ удаленный
⁃ забаненный

Поскольку в базе уже есть active, то разарботчик, вероятно, пойдет по наиболее легкому пути - начнет добавлять новые флаги. Это просто и не требует хитрых миграций, чтобы обеспечивать обратную совместимость (для zero downtime). В итоге в базе появятся флаги:

active, email_convirmed, banned, deleted

и с этого момента начинается то самое программирование на флагах.

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

Комбинаторный взрыв состояний - пользователь может быть active = true, но при этом banned = true и deleted = true. Что это значит? Он активен или нет?
Неявные правила - чтобы понять, что такое «активный пользователь», нужно лезть в код и смотреть, как именно проверяются флаги (active && !deleted && !banned && email_confirmed)
Сложность изменений - добавление нового флага или изменение бизнес-логики требует правок во множестве мест, потому что условия размазаны по коду и SQL-запросам.
Повышенный риск багов - достаточно забыть один флаг в проверке и все, приплыли.

Самое главное, что состояния в рамках одного процесса будут требовать синхронного изменения. Если меняется один, то надо не забыть поменять другой. Например если мы человека вводим в бан, то надо не забыть снять активность.

Более универсальный и безопасный для расширения способ в таком случае, это не флаги, а одно свойство определяющее состояние нашей сущности.

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


type UserState = 'active' | 'banned' | 'deleted' | 'waiting_email_confirmation'


Фактически такой подход гораздо лучше ложится на то, как мы думаем об этом, чем флаги. Более того, это и намного нагляднее с точки зрения кода. Таким образом мы сразу решаем проблему синхронизации, переход из одного состояния в другое это одно действие и отсутствие багов в стиле "флаги не согласованы"

Есть еще один немаловажный плюс. Допустим у нас изначально два состояния и мы решили, что не будем бежать впереди паровоза. Мы делаем в базе boolean и попадаем в ситуацию, что когда добавится третье состояние, придется менять тип колонки на строку и все значения внутри него. Опытные разработчики сразу будут этому сопротивляться, потому что ломать обратную совместимость в базе нельзя, поэтому правильным способом, будет создать новую колонку и выполнить миграцию туда. Оно нам надо? То есть использования состояния это безопасно и расширяемо в отличие от флагов.

Но даже этого может быть недостаточно. Следующим шагом будет использование конечных автоматов https://github.com/eram/typescript-fsm (в том случае если нужна реакция на переходы, а сама структура переходов не линейная)

Ссылки: Телеграм | Youtube | VK
1👍14131🔥13🤔3👀1



tgoop.com/orgprog/356
Create:
Last Update:

Программирование на флагах

Недавно я упомянул этот термин в одном и постов и получил неожиданно большое количество комментариев "что это?". Тема заслуживает раскрытия, поэтому пост.

Возьмем пример с sql:


SELECT *
FROM users
WHERE active = 1;


Почти наверняка это поле из двух состояний активен/не активен (1/0), где активность определяется подтверждением емейла. В Postgresql это было бы true/false.

В целом, этот код выглядит совершенно нормально и очень хорошо работает. До поры до времени. А потом выясняется, что «неактивный» бывает как «удалённый», так и «заблокированный». Или, например, мы (бизнес) захотим давать работать на сайте тем кто зарегистрировался, но не подтвердил емейл. Подтверждение емейла будет работать как способ получить больше функций. В сумме мы получаем:

⁃ зарегистрированный
⁃ активный (подтвержден емейл)
⁃ удаленный
⁃ забаненный

Поскольку в базе уже есть active, то разарботчик, вероятно, пойдет по наиболее легкому пути - начнет добавлять новые флаги. Это просто и не требует хитрых миграций, чтобы обеспечивать обратную совместимость (для zero downtime). В итоге в базе появятся флаги:

active, email_convirmed, banned, deleted

и с этого момента начинается то самое программирование на флагах.

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

Комбинаторный взрыв состояний - пользователь может быть active = true, но при этом banned = true и deleted = true. Что это значит? Он активен или нет?
Неявные правила - чтобы понять, что такое «активный пользователь», нужно лезть в код и смотреть, как именно проверяются флаги (active && !deleted && !banned && email_confirmed)
Сложность изменений - добавление нового флага или изменение бизнес-логики требует правок во множестве мест, потому что условия размазаны по коду и SQL-запросам.
Повышенный риск багов - достаточно забыть один флаг в проверке и все, приплыли.

Самое главное, что состояния в рамках одного процесса будут требовать синхронного изменения. Если меняется один, то надо не забыть поменять другой. Например если мы человека вводим в бан, то надо не забыть снять активность.

Более универсальный и безопасный для расширения способ в таком случае, это не флаги, а одно свойство определяющее состояние нашей сущности.

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


type UserState = 'active' | 'banned' | 'deleted' | 'waiting_email_confirmation'


Фактически такой подход гораздо лучше ложится на то, как мы думаем об этом, чем флаги. Более того, это и намного нагляднее с точки зрения кода. Таким образом мы сразу решаем проблему синхронизации, переход из одного состояния в другое это одно действие и отсутствие багов в стиле "флаги не согласованы"

Есть еще один немаловажный плюс. Допустим у нас изначально два состояния и мы решили, что не будем бежать впереди паровоза. Мы делаем в базе boolean и попадаем в ситуацию, что когда добавится третье состояние, придется менять тип колонки на строку и все значения внутри него. Опытные разработчики сразу будут этому сопротивляться, потому что ломать обратную совместимость в базе нельзя, поэтому правильным способом, будет создать новую колонку и выполнить миграцию туда. Оно нам надо? То есть использования состояния это безопасно и расширяемо в отличие от флагов.

Но даже этого может быть недостаточно. Следующим шагом будет использование конечных автоматов https://github.com/eram/typescript-fsm (в том случае если нужна реакция на переходы, а сама структура переходов не линейная)

Ссылки: Телеграм | Youtube | VK

BY Организованное программирование | Кирилл Мокевнин




Share with your friend now:
tgoop.com/orgprog/356

View MORE
Open in Telegram


Telegram News

Date: |

Polls The administrator of a telegram group, "Suck Channel," was sentenced to six years and six months in prison for seven counts of incitement yesterday. best-secure-messaging-apps-shutterstock-1892950018.jpg 5Telegram Channel avatar size/dimensions Telegram iOS app: In the “Chats” tab, click the new message icon in the right upper corner. Select “New Channel.”
from us


Telegram Организованное программирование | Кирилл Мокевнин
FROM American