Как стать автором
Обновить

Комментарии 32

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

Ещё одна беда многих проектов — дублирование кода. Нужно изначально заложить в архитектуру приложения как можно больше защиты против этого.

Третья беда — отсутствие продуманной процедуры обновления от версии к версии с возможностью отката и отсутствие скриптов для для разворачивания базы данных с нуля.

Частая ошибка — неправильный выбор типа данных для ключа в базе данных. Из-за чего возникают ошибки когда таблица перерастает определённый размер (к примеру 32000 записей для int), либо возникают проблемы с масштабированием. К этой же проблеме отнесём и автогенерацию первичных ключей, которая опять же либо выглядит как костыль, либо страдает от проблем с масштабированием. Логичным выходом является использование GUID, но он медленный и очень неудобен в отладке и написании SQL запросов для поддержки и анализа проблем.

Дополню свой комментарий ещё парой мыслей:

Ошибки выбора типов данных встречаются не только для первичных ключей. Это очень большая проблема для строк (Юникод или однобайтовые строки), для дробных значений (к примеру знаю одну программу для ломбардов, которая считает деньги в float типе, а учитывая то, что проценты считаются по дням и в результате генерируется много записей с небольшими суммами, то ошибка быстро накапливается и приводит к расхождению на несколько рублей в сутки для всего ломбарда). Другая проблема — недостаточная точность. Часто считается, что точности 2 знака после запятой для хранения денег достаточно, но фактически есть операции, где важны значения до 5ого знака. К примеру та же пеня.

Ещё одна ошибка архитектуры — «сделаем прототип, а потом переделаем». Это не работает. Всегда пишите так, как будто этот код — критически важен для проекта. Видел случаи когда пилили прототип, а потом заказчик сказал идти в продакшн. И его можно понять — перед ним рабочая система, но вы говорите ему, что нужно всё переделать и ещё и заплатить за это…

Частая проблема, которую можно видеть особенно в старых проектах, это любовь к универсальным решениям. Вплоть до форм, конфигурируемых с помощью xml и генерации SQL запросов на лету. Это работает для простейших задач, но порождает проблемы удобства использования для клиентов, снижает безопасность системы и порождает различные костыли.
Ой как раз первое приложение было финансовым, и там использовали тип с фиксированной точностью до 4 знаков, и много не было. Когда прочитала про float для финансовых данных аж все сжалось, это прямо «ужас ужас ужас».

Согласна про излишнюю универсальность. Тут очень важно уметь правильно остановится. Иногда решение усложняется в разы, потому что пытаются заложить универсальность, под случаи, которые происходят в 0,03% случаев и в итоге вся система работает медленнее и не если бы только медленнее, но и сложнее.
Всегда пишите так, как будто этот код — критически важен для проекта.
Казалось бы хороший совет, но он не работает.
Высокий приоритет везде = отсутствие приоритета.
Приоритет должен влиять на порядок выполнения задач, но не на качество выполнения.
Видел случаи когда пилили прототип, а потом заказчик сказал идти в продакшн.

а что заказчику обещали? production-ready систему или прототип на-посмотреть?
возможно ожидания у заказчика были выставлены неудачно

Всегда пишите так, как будто этот код — критически важен для проекта.

мне кажется, такой подход плохо сработает, если вы используете новые для себя технологии (библиотеки, инструменты — всё, что относится к разработке). Как бы не был важен этот функционал, будет трудно принимать решения «как лучше его реализовать», потому что в начале не хватает опыта. ИМХО, новая предметная область тоже может влиять — откуда бы мне, разработчику, знать, что вне РФ нет такой сущности как ИНН, так что я честно делаю ИНН ключом:)
я клоню к тому, что вы много времени потратите с таким подходом.

есть же прототипы, которые делаются только с целью proof-of-concept: разработали, научились, собрали ошибки, в следующем прототипе или в новой системе сделаете правильно в заданном контексте. на самом деле этот подход тоже небыстрый, но более эффективный с точки зрения вашего обучения и с большей обратной связью от пользователей/заказчика.
Про «Всегда пишите так, как будто этот код — критически важен для проекта.» — Тут вопрос в качестве и ответственности за код. Часто на начальных стадиях проекта много кода пишется как Proof-of-Concept, но затем к нему уже не возвращаеются и он идёт в продакшн. Сюда же относится создание технического долга с самого начала проекта, притом часто создаются очень болезненные проблемы вроде «дедлайн поджимает, так что давайте вносить изменения в конфигурации CMS-ки на-живую без документирования и создания скриптов — всё равно же у нас один заказчик и базу данных никогда не прийдётся разворачивать с нуля». Вроде разумное решение, но скольно оно может создать проблем в будущем — страшно представить!
smallint (postgres) = -32768..+32768, так что int более 2 млрд строк.
хехе
> Практически во всех канонических учебниках по базам данных описывается, насколько неэффективны искусственные ключи и как прекрасны естественные.
Ровно наоборот, в любом учебнике написано, что эффективны как раз искусственные ключи, а естественные — ужасны.
Это видимо уже писали люди, который достался проект с естественными ключами.
Вопрос интересный, вот где стандартов не хватает.
Всегда стараюсь сделать ключ простым и с использованием простого типа. Даже если есть возможность сделать естественный ключ (простой или составной). Причина очень простая — даже если на текущий момент ключ выглядит уникальным, то в будущем это правило может быть нарушено. Возьмём стандартный пример с людьми: Фамилия, Имя, Отчество опциональны или неуникальны, ИИН и прочие госномера применимы только для конкретных стран и имеют свойство меняться. К примеру через 5 лет примут закон, что в ИИН будет 20 символов длиной и может включать буквы, или вообще их отменят. Что тогда?!
А как насчет UUIDv5 по ИНН + Фамилия + Имя + Отчество + whatever. Каковы минусы такого решения, кроме коллизий?
В MS SQL (да и думаю во всех реляционных БД) индексы по полям простого типа (число, гуид) работают значительно лучше/эффективнее чем по строковым. Значит и джойны по простым полям будут работать лучше.
1. «Фамилия Имя Отчество» могут меняться

2. https://habrahabr.ru/post/146901/
Все это прекрасно, но есть замечательный коммент который хорошо описывает почему так никогда не будет https://habrahabr.ru/post/310310/#comment_9825136

Я раньше поражался тому, как уродливы изнутри «взлетевшие» проекты. Сейчас я знаю: красивые проекты не взлетают, потому что они не успевают взлететь. Пока инженеры в белых халатах прикручивают красивый двигатель к идеальному крылу, бригада взлохмаченных придурков во главе с безумным авантюристом пролетает над ними на конструкции из микроавтобуса, забора и двух промышленных фенов, навстречу второму туру инвестиций. Авантюрист любезно раздаёт восторженным пассажирам талоны и бумажные пакетики.
К сожалению это так — победил не тот кто сделал лучший продукт, а тот кто сделал продукт быстрее или\и смог его побыстрее продать большему количеству людей.
С другой стороны в enterprise на мой взгляд уж очень тяжко все и медленно двигается. Народ может обсуждать и переделывать по 5 раз решение, хотя в это время в проде может быть абсолютная лажа, и любой из новых вариантов был бы лучше, но нет, надо же найти лучшее. В результате вместо 2х дней на изменение тратится от 2х до 3х недель. И это я говорю о простом изменении, если что-то помасшабнее, то вообще все грустно.
В общем во всем нужна мера.
Практически во всех канонических учебниках по базам данных описывается, насколько неэффективны искусственные ключи и как прекрасны естественные. Но мир, обычно, еще не дошел до такого уровня глобализации, чтобы всем можно было бы использовать естественный ключ

У меня есть мысль, что естественных ключей в полном смысле слова не бывает. Бывают некомпьютерные искусственные ключи. Номер паспорта. Это же число, инкрементный идентификатор. И подходит он только для учета самих паспортов. ИНН. Это тоже придуманное число из базы данных налогоплательщиков. Принцип учета не меняется от того, в компьютере у нас база или на бумаге.


Можно использовать один ключ в нескольких базах данных, но от этого он не станет менее искусственным. Это всё потому что у объекта-сущности может измениться любое свойство, но мы все равно будем считать его тем же объектом.

Прямо самая суть! Задача ключа как раз сказать когда мы имеем дело с тем же объектом, а когда это уже другой объект, пусть и с частично совпадающими свойствами. Понятно, что «сферического коня в вакууме» или «идеального ключа» тут не будет, важно выбрать что-то, что будет выполнять задачу идентификации объекта достаточно хорошо, в рамках поставленной задачи. В идеале еще заглянуть в хрустальный шар и посмотреть, как рамки поставленной задачи могут расшириться. Но хрустальные шары иногда мутные, и не всегда видно, как и куда проект пойдет в дальнейшем.

Добавлю свои пять копеек для стартапов:


  • автоматизированный деплоймент и автоматизированный откат деплоймента. Экономит просто гигантское количество времени и нервов, особенно если приложениие нужно обновлять каждый день или оно не обновлялось несколько месяцев. Относится как к деплойменту приложения, так и к базам данных
  • логгирование, алертинг и аналитика. Нужно думать сразу, какая информация нужна для аналитики, какие ошибки требуют немедленной реакции админа, а какие нужно регулярно просмотривать в поисках багов или проблем с приложением.
  • прототипы являются очень полезным инструментом при соблюдении простых правил:
    — прототип должен содержать ровно столько функционала, чтобы впечатлить инвесторов или оценить спрос на идею. Идеальный прототип — лендинг с формой сбора email-ов.
    — прототип не расширяется и не переписывается — он выкидывается. Поэтому его желательно делать с использованием средств быстрой разработки (CMS, фреймворки...)
Соглашусь (и обеими руками поддержу) со всем, но по 4му пункту в части логов уточню:
важно хранить логи действий пользователя в течение 1-2х недель на случай, если он обратится в техническую поддержку. Затем эту информацию можно удалить.

Очень зависит от специфики системы. Действительно, важно понимать ЧТО вы логгируете, не стремясь просто набить терабайт побольше и потом хвалиться ими. Но вот у нас бывают случаи разбора проблем и 3х месячной давности, и тогда только детальные логи помогают понять в чем дело. Иные процессы требуют вообще журналирования более чем на год, пусть и довольно поверхностного.
Спасибо за дополнение, да согласна, ключевая идея — определить срок хранения, даже если это 1 год, 3 года или 5. Если сначала определили какой-то большой срок — например 5 лет иногда возможно посмотреть как часто происходит обращение к этим данным, если к данным старше 1 года никто не обращался ни разу — можно выгрузить эти данные вообще куда-нибудь в файл и оставить на каком-нибудь медленном диске, на случай обращения.
Не соглашусь со статьей в целом. Да, интересно почитать какие задачи были в успешных проектах при росте. Но если их решать сразу в начале, то с огромной вероятностью успешного проекта не получится.

В начале идет большое количество изменений (новый функционал, исправленный старый, эксперименты). Если вместо этого пилить ненужный функционал (закладываться на будущее), то не только стоимость ненужного сейчас функционала и задержка нужного из-за занятости программистов тянут проект к банкротству, но и увеличение стоимости любого функционала из-за ненужного.

Например, локализация, когда достаточно одного языка. Или обрезание логов для двух недель, а потребовалось проанализировать поведение пользователей за больший промежуток времени.
Тут очень важно вовремя остановится, и видимо мне не удалось толком передать этот момент.
Конечно, именно сделать то, что сейчас актуально наиболее важно для проекта. А то так если пилить задачи на будущее, можно прошляпить настоящее.
Дополню про локализацию — нет сразу поддержку всех языков вводить не нужно, это излишний очень большой кусок работы. А вот тип строк юникод — можно выбрать, это объем работы на начальном этапе никак не изменит. Да, это увеличит объем на диске, но в начале данные не занимают много места. Если точно известно что это не стратап или потенциально (пусть и в самых смелых фантазиях) международное приложение, а например, приложение для госсектора — тут можно и юникод не использовать, так как язык ну уже совсем точно будет один.
Про логи — не надо сразу ставить 2 недели, но какой-то срок поставить надо. А главное настроить процедуру их удаления. Ок, если вы не знаете сколько они могут понадобится — поставьте удалять через 3 месяца, через 1 год, через 3. И настройте сразу процедуру. В процессе работы вы поймете как часто и за какой период эта информация нужна. Если не чистить мусор сразу, то через 3 года об удалении обычно никто не помнит, а через 5 лет у вас будет помойка, которую будет тяжело и долго разгребать. В плохом варианте — помоек будет много.
«тут можно и юникод не использовать» — а сейчас точно 2017 год?! Что значит не использовать юникод? Почему? Как?! Типа место экономим? :) Все соврменные средства программирования заточены под юникод, так почему БД не должна его использовать?
Так как у нас 2017 год, то БД практически всегда должна использовать юникод.
Но для хранение юникод данных используется в 2 раза больше места, чем для хранение в локальной кодировке. Я не делала проекты, которые бы могли быть только локальными — мне кажется это может быть госсектор или что то еще только локальное, может быть областное, и оно не предполагает хранения отображаемых данных. Например. названия улиц — потому что могут решить их продублировать на китайском — и будет проблема.
В общем это я к чему, вроде и 2017й год и дисковое пространство дешевле. Но
Например у нас 100 полей со строковыми данными, для простоты размером до 200 символов каждое. Для MS SQL берем Varchar (1 байт) и Nvarchar (2 байта на символ)
Varchar 2000 байт на строку
NVarchar 4000 байт на строку
Вроде мало — какая разница-то?
А теперь представим что у нас добавляется этих строк много.
То есть когда у вас 4 Тб данных или 8 Тб это все таки имеет значение. Опять же тут надо все таки очень сильно думать — будет у вас больше одного языка и латиницы или нет.
И да в 99% надо использовать юникод.
Но тут не забываем про важный момент — сжатие данных. Мощные СУБД умеют оптимизировать хранение данных и сжимать, так что на самом деле разница будет не 4 Тб и 8 Тб, не скажу точно сколько, но всё же не такая.
Например, MS SQL:
All non-East Asian languages and the Thai language store non-Unicode characters in single bytes.
non-Unicode

Речь о кодировках типа Windows-1251 или KOI-8, а не об особых техниках сжатия если БД определит, что мы используем в стоках только русские Unicode символы.

Про локализацию… Все названия, имена, описания — сразу сохраняем в двух языках — локальный и латинский (два поля в БД: NameLoc, NameLat) по минимуму. По максимуму — словарь с языками, ссылки на этот справочник и прочее. Хотя не могу вспомнить систему, где данные (не UI) больше чем на двух языках.

И пользователей заставлять на латыни писать названия и описания? Тут даже поле key (вторичный ключ, чтобы из приложения было удобнее анализировать) они нормально заполнить на английском не могут, а уж всё...

Очень скептически отношусь к идее удаления логов и прочей истории. Другое дело, что нужно регулярно перемещать старые записи из оперативных баз (или таблиц) в архивы.


По поводу времени в UTC — если уж приняли такое решение "на будущее", то всегда понимайте где у вас по бизнес-логике дата, а где датавремя и никогда не надейтесь на автоматическое приведение даты и даты+времени при сравнении, вычислении длительности и т. п. Требуйте от бизнеса явных правил приведения дат ко времени и назад с учетом часового пояса пользователя и офиса, его обслуживающего, если начинаете работать в нескольких часовых поясах, чтобы не получалось что человек оплатил подписку только что, а станет она ему доступна только с полночи в Гринвиче. Или наоборот, оплатил за 30 дней, а получит, например, 29 дней и 20 часов.

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории