Pull to refresh

Что нужно учесть при проектировании системы, чтобы не было мучительно больно?

Reading time 8 min
Views 22K
В статье описаны проблемы при проектировании баз данных и немного всего приложения, которые потом с ростом проекта все сложнее и сложнее решить. Моменты, которые важно учесть на этапе дизайна, и не задумываться о них в последствии. Ну или задумываться за чашкой чая и фразой «А помнишь, как мы решили это сделать сразу? Сколько времени мы этим себе сэкономили!», а не с ощущением зубной боли и болезненном вздрагивании при каждом воспоминании. По мере роста системы и числа пользователей, дизайн базы все сложнее и сложнее изменить, и масштаб изменений становится все более глобальным и трудоемким.

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

Я работала в 2х стартап-проектах, которые выстрелили и выросли в большие компании с миллионами пользователей из маленьких региональных проектов, и сейчас являются высоконагруженными. К моему удивлению я увидела, что есть много общих проблем, хотя приложения писались разными командами и для разных пользователей. Видны общие проблемы в базах данных, которые являются наследием стартапа, такими детскими проблемами роста, которые показывают, что изначально проект был запланирован маленьким.



Нет необходимости сразу создавать проект международного масшатаба, но важно заложить базовый функционал, который при необходимости облегчит и поможет преобразовать проект в международную высоконагруженную систему.

И так, основные ошибки:

  1. Отсутствие возможности локализации.

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

    • Часовые пояса

      Необходимо сделать хранение даты и времени либо в формате UTC, либо с учетом часового пояса клиента. При этом важно помнить, что все серверные даты тоже нужно будет переводить в часовой пояс клиента при отображении. Вот выглядит смешно и очевидно, а однако изначально, один из проектов, когда мы предложили владельцу заложить поддержку для других регионов, он сказал, что он не планирует такого роста. А потом рост был. И выдранные волосы по поводу того что не заложили сразу тоже.

    • Разные языки

      При выборе текстовых полей следует использовать формат Unicode или тип NVarchar, впоследствии это облегчит работу с приложением. Необходимо обратить внимание на правила сортировки и сравнения строк в вашей БД. Убедитесь, что Вы выбрали не сортировку (Collation) по умолчанию, а сортировку, которая будет корректно работать при сравнении диакритических знаков, иероглифов и символов нестандартной ширины, при условии, что конечный пользователь вводит какую-либо информацию. Скажете ваше приложение будет работать только для США или только для Европы? Тогда нужно спросить себя – будут ли там данные, которые может ввести конечный пользователь. Хотя бы что-то строка комментария или какую то информацию для себя? Если такая возможность есть – сделайте хранение строк в Unicode. Мир уже давно перемешался и вы не застрахованы, от того, что человек, пользующийся японским что-то внесет в вашу БД как пользователь. Конечная цель в том, чтобы данные пользователя правильно сохранились и потом корректно выводились.

    • Валюта

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

    • Естественные ключи

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

      Например, в одном из проектов мы думали использовать ИНН в качестве естественного ключа для контрагентов, но отказалась от этой идеи. Не могу описать словами, как мы в последствии радовались этому, так как компания начала развиваться и сотрудничать с юридическими лицами за пределами России.

  2. Типы данных

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

    Например, при создании таблицы со списком сотрудников только Вашей компании, допустимо использовать первичный ключ типа INT, так как вероятность роста компании до 2млд человек очень мала. Однако, если Вы создаете БД сотрудников компаний Ваших клиентов, необходимо использовать тип данных большей размерности, например, BIGINT, так как есть вероятность, что 500 тыс. сотрудников при условии смены работы четыре раза создадут 2 млн. записей в вашей БД, и таблица для хранения списка сотрудников компаний-клиентов, при наличии большого количества клиентов, вполне может разрастись и превысить 2 млрд. Это же правило действует для таблиц, которые хранят логи пользователей, и другие бизнес операции, которые с ростом приложения могут увеличиться в миллионы раз.

  3. Синхронная реакция на действия пользователя

    При проектировании системы важно продумать, какие из действий пользователей будут касаться изменения или удаления большого количества объектов системы, если система увеличится. Например, если у пользователя 2000 контактов, и он отправляет им приглашение, будет система рассылать данное приглашение немедленно, либо отобразит сообщение пользователю, о том, что его запрос обрабатывается, и затем обновит статус на выполнено, когда действие будет обработано.

    Если обработка будет немедленной, то при росте системы в дальнейшем возможны проблемы с производительностью сервера. Также, рабочая нагрузка системы при обработке всех запросов синхронно будет напрямую зависеть от действий пользователей. Например, при стандартной загрузке, системе хватает 10% ресурсов для обработки всех запросов в штатном режиме. При появлении пользовательского супер-запроса, такого как приглашение 500 тысячам пользователей одновременно, загрузка системы может возрасти до 100%. Пример несколько синтетический, но, думаю, суть понятна. При этом система перестанет штатно обрабатывать запросы остальных отдельных пользователей, пока не завершит обработку данного огромного запроса.

    Подумайте, какие действия пользователей могут быть масштабными, и сделайте их асинхронными. В примере с приглашениями система не начинает отправку немедленно, а создает новое задание «отправка приглашений пользователям». Когда задача создана, система в фоновом режиме осуществляет отправку приглашений и сообщает пользователю о выполнении задачи по ее завершению. Для удобства пользователя также немало важным является его уведомление о действиях системы, которая работает в асинхронном режиме.

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

  4. Накопление ненужных данных

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

    Например, важно хранить логи действий пользователя в течение 1-2х недель на случай, если он обратится в техническую поддержку. Затем эту информацию можно удалить. Поэтому важно продумать и сразу ввести процесс удаления старых данных до того как таких данных накопится слишком много. Если сразу не прописать данный процесс, то есть большая вероятность столкнуться с проблемой, когда в БД добавляется огромный поток новых данных, и система не справляется с удалением ненужных данных. Необходимо продумать эффективную систему удаления старых данных, такую, чтобы она не только превосходила по скорости новый поток данных, но и смогла в обозримые сроки удалить огромный массив информации за прошлые годы работы.

    Правило удаления старых ненужных данных должно касаться и всех новых функций.

  5. Отсутствие тестов и документации

    Обычно стратап-проекты спешат запуститься побыстрее. Также обычно стратапы реализует сравнительно небольшая команда разработчиков, которая знает наизусть всю бизнес логику приложения и не понимает, зачем терять время на написание документации, а иногда и тестов. Работа идет по принципу «сейчас запустимся, а потом напишем». Однако, как только система запускается, появляется огромное количество новых задач, и времени на написание документации не остается.

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

    Настоятельно рекомендуем писать документацию сразу. Впоследствии это окупится сполна.
    Что касается тестов, как только команда разработчиков увеличивается, необходимо убедиться, что разработка новых функций или доработка/изменение существующих не оказывают негативного влияния на весь остальной существующий функционал системы. Тесты – самый простой и эффективный способ проверки функциональности.

  6. Масштабирование

    При возрастании нагрузки на систему, возникает необходимость ее масштабирования. Следовательно, во время проектирования системы необходимо продумать возможности масштабирования системы при увеличении нагрузки, например, в 10 раз. Продуманный под возможность масштабирования дизайн облегчит последующие изменения под новые реалии растущей системы.

    Было бы хорошо задать себе и разработчикам следующие вопросы:

    • Как увеличится производительность системы, если нарастить мощность оборудования?

    • Можно ли создать копию системы на другом сервере и включить его в работу? Если нет, что нужно изменить в дизайне, чтобы это стало возможным?

    • Насколько большой масштаб изменений нужен для разбиения системы на несколько частей и перестройки архитектуры с использованием принципов SOA или микросервисов?

    Это не значит, что систему необходимо проектировать сразу крупномасштабной, но важно заложить фундамент дальнейшего масштабирования системы. Соломку стелите тонким слоем, не надо сразу везде снопы складывать.

Итак, на начальных стадиях проектирования системы важно соблюдать баланс между работой на будущее и работой на настоящее. И настоящее важнее, потому что существуют конкретные требования и задачи, которые необходимо реализовать, обычно в сжатые сроки. Будущее может и не наступить, или предстать совершенно иным, изначально ожидалось. Если у вас попросили сделать городской автобус, совсем не нужно сразу делать возможность преобразования его в космический корабль, ведь этого будущего у городского автобуса может и не случиться. Поэтому идеальным является заложить основу дальнейшего разделения системы, которая впоследствии будет использована для разнесения на сервисы и модули.
Tags:
Hubs:
+32
Comments 32
Comments Comments 32

Articles