Есть у нас, допустим, компьютерная игра с разнополыми персонажами. Пол персонажа будет храниться в поле gender. Можно сделать это поле целым числом или строкой, но хороший программист стремится сделать некорректные состояния объектов невыразимыми, и поэтому, скорее всего, заведёт для пола enum. Теперь сделать персонажа с неправильным полом просто невозможно!
А ещё в игре есть база данных, в которой хранятся все игроки, и туда тоже нужно записывать, какого они пола. Было бы неплохо сделать так, чтобы персонажа с некорректным полом в базу данных добавить было нельзя, потому что с ней будет работать не только код, в котором для полов ничего, кроме enum, не предусмотрено, но ещё и живые люди. А живые люди, как известно, так и норовят вписать в базу данных то, что туда вписывать не надо.
К счастью, специально для таких случаев во многих СУБД также есть возможность делать колонки типа enum, тем самым ограничивая диапазон значений, которые могут иметь данные в такой колонке. Чем и воспользуется опытный разработчик, который не желает, чтобы в его проекте что-то было не по фэншую.
На клиенте программист тоже не дурак и тоже знает, что некорректные состояния должны быть невыразимы, и что для этого пол персонажа должен быть enum.
Идеально!
Однако если присмотреться, то можно обнаружить один небольшой изъян, который в итоге приведёт к проблемам. Поле, в котором хранится пол, называется не sex, а gender, а значит, к нему уже подбирается гейм-дизайнер. Рано или поздно он узнает, что гендеров, в отличии от полов, существенно больше двух, и захочет добавить гендер GENERIC_TEEN. Тут-то всем и поплохеет.
Первыми под удар попадут ребята, которые писали клиентский код, потому что некорректные значения параметра гендер начнут приходить с сервера по каждому чиху. А когда с сервера придёт персонаж с гендером о существовании которого клиент не знает, то игра, как и хотел программист на клиенте, просто не запустится. Теперь при появлении новых гендеров необходимо релизить новые версии клиентов и запускать принудительные обновления, которые мы все так сильно любим.
На сервере enum — добро, потому что если там обнаружено какое-то неизвестное значение, то это явно ошибка, которую надо найти и исправить, а вот на клиенте появление неизвестного значения — штатная ситуация, которая будет регулярно случаться на устаревших версиях клиента, и поэтому там enum — зло, которое надо искоренить и уничтожить как можно скорее.
Кроме того, согласно рекомендациям лучших собаководов, новый код должен уметь работать со старой схемой данных, а тут получается, что вся система может развалиться только из-за того, что в код добавили новый гендер.
Поэтому, в базе данных enum нам мешает, и в данном случае надо хранить в поле строки, или инты, или что угодно, во что при необходимости можно записать значение, не предусмотренное заранее.
И кто-то скажет: ладно, ладно, на клиенте enum вредит, и в базе данных он больше мешает, чем помогает, но в серверном коде-то enum приносит большую пользу. Он же не будет предлагать убрать enum из кода на сервере? Будет!
Нынче программисту рекомендуется не только писать код так, чтобы он нормально работал со старой базой данных, но и развивать схему данных так, чтобы немного устаревший код тоже мог нормально с ней работать.
А если на сервере для гендера использовать enum, то всё опять развалится, только уже после того, как выяснится, что с новым кодом что-то не то и надо немедленно откатить всё до предыдущей версии, а новые гендеры в базу данных уже попали.
И поэтому enum из серверного кода мерным солдатским шагом идут куда-то в направлении ближайшего лесного массива, чтобы никогда оттуда не вернуться, ибо всё, что может развалить систему в неподходящий момент — зло, а злу не место в нашем уютном коде.
Короче, как сказал бы Винни-Пух – это какие-то неправильные енамы, и это они провоцируют программиста писать неправильный код! В enum надо помещать действительно незыблемые и фундаментальные вещи, которые не меняются годами, а не гендеры, которые добавляются и исчезают каждый релиз! Каждой задаче – свой инструмент, и enum – это не тот инструмент, который нужно использовать для хранения значений, возможный спектр которых постоянно расширяется.
Если переменная может принимать только какие-то заранее известные значения и всё, что не входит в эти значения, должно приводить к ошибке, то использовать enum – хорошая идея, но если это не так, если непредусмотренные значения регулярно будут попадать в переменную, то использовать enum равно выстрелить себе в ногу, и лучше этого не делать, если вы, конечно не мазохист.
Эта конкретная ситуация интересна тем, что ничто не предвещало добавления в enum новых значений, не говоря уже о том, что новые значения будут появляться регулярно. Откуда нам вообще было знать, что полов будет больше двух?
Поэтому, согласно принципу KISS, enum на первом этапе – хороший и правильный выбор. Опытный программист сделает enum и зафиксирует, что при появлении дополнительного значения нужно немедленно запустить мероприятия, необходимые для того, чтобы enum из кода исчез.
К сожалению, практика показывает, что на самом деле добавлением нового гендера будет заниматься кто-то другой, и он, недолго думая, добавит в enum новое значение, a на этом успокоится. Так что если есть какие-то сомнения, лучше следовать простому правилу: хранится где-то, кроме кода – значит, не enum, и на этом точка.
Несмотря на то, что я сейчас наговорил, enum в коде всё равно могут быть очень полезными, даже если в них находятся значения, которые попадают в базу данных. Не надо только использовать их для того, чтобы хранить значения, которые вытаскиваются из БД, надо сравнивать то, что пришло из БД с желаемым значением. Например, когда программист хочет написать, что если гендер персонажа – GENERIC_TEEN, то ему нельзя класть в инвентарь спиртные напитки, можно завести enum Gender с методом value, возвращающим строку, и написать код который будет проверять, равенство поля gender у персонажа и Gender.GENERIC_TEEN.value() и это будет хорошо, потому что не даст программисту сделать ошибку в значении статуса.
Решения, хорошо служившие нам в какой-то момент, могут стать неудобными по прошествии времени. И нужно следить за тем, чтобы код отражал текущее состояние проекта, а не был набором костылей, с помощью которых решение, созданное на коленке пару лет назад, натягивается на “здесь и сейчас”. В противном случае он будет неисчерпаемым источником факапов и лулзов для всех, кто хоть как-то связан с проектом, будь то разработчик, тестировщик или непосредственный потребитель.
К сожалению, не доступен сервер mySQL