awfun

Пикабушник
28К рейтинг 90 подписчиков 12 подписок 84 поста 30 в горячем
Награды:
10 лет на Пикабу
17

Простые требования легче реализовывать

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

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

  • integer, числовая последовательность: 0001, 0002, ...

  • UUID.random() : 8c061868-5bbd-4ea7-824f-d8640fb4f6e3, ...

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

Так как эти уникальные значения можно сравнивать, то можно привести их к полному порядку - отсортировать и расположить в виде структуры с эффективным доступом (например, дерево со сложностью logN).

Числовая последовательность обеспечивает не какой-то порядок - он еще и совпадает с порядком добавления записей в таблицу. Если в конце месяца мы захотим подарить подарок 1000-му пользователю сервиса, то это можно сделать если исходный порядок сохранен.

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

main: (0001, 0002, 0003)
replica: (0001, 0002)

Если основной узел выйдет из строя, то дальше все операции по записям возьмет на себя реплика. В указанном случае она будет выдавать идентификаторы далее: 0003, 0004, ... . Получается, у разных узлов будет разное представление об операции с id = 0003 - это создаст конфликт, если первый узел вернется к жизни.

Можно было бы вместо этого выбирать тысячную запись не по id, а по времени создания. В этом случае можно использовать UUID как идентификатор, и добавлять время создания записи, чтобы позже по нему выявить 1000-го пользователя. В случае падения основного узла конфликта с id не будет, но на разных узлах может не совпадать время - а это бывает при проблемах с ntp сервисами. Например, во время выхода из строя основного узла время на нем было 15:20, а на реплике 15:12, и у новых пользователей время будет меньше чем у существующих.

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

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

Показать полностью
14

Онбординг для программиста

Всем привет, работаю java разработчиком 10 лет, хотел бы рассказать как обычно происходит введение в должность нового сотрудника, aka онбординг.

Вы получили пропуск, технику, пароль от учетки, познакомились с командой проекта. Один из команды становится ответственным за то чтобы направить вас на начальных этапах, он называется buddy.

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

Нужно чтобы вас добавили в общие чаты, общие емейлы и встречи команды. Тут же могут подсказать чат с мемами, чат обеда и прочие места интересов.

Требуется ознакомиться также с административными системами - таск трекер, учет времени, hr системы.

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

Далее сложность задач будет идти по нарастающей, и buddy будет участвовать всё меньше.

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

Отдельно выделю важность документации по предоставлению доступов. После увольнения сотрудника желательно "прибрать" за ним, пройдя по списку доступов и деактивировав их.

Всем удачных трудоустройств!

Показать полностью
12

Скорость работы программ

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

С технической точки зрения, программы нужны для обработки данных - получить, вычислить, сохранить и передать дальше. Часть этих данных нужна сразу - например, при запросе пользователем страницы интернет-магазина. Часть данных должна рассчитываться с задержкой - например, клиринг должен выполняться после завершения финансового дня. И есть еще ситуации, которые допускают небольшой лаг: например, пользователь скорее всего не заметит, что после совершения покупки электронный чек пришел с десятиминутной задержкой. С этой точки зрения, сервисы решают онлайн задачи и задачи с отложенным выполнением (см OLTP и OLAP для баз данных).

Для онлайн сервисов довольно важной характеристикой является длительность времени ответа. Долгая загрузка сайта создает негативный пользовательский опыт.

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

Получается, что нет единого понятия скорости, а есть конкурирующие: предел потока запросов и длительность формирования ответа. Это так называемые нефункциональные требования. Длительность ответа представлена распределением, поэтому к нему может применяться агрегирующая функция, например: длительность обработки не больше 1 сек для 90% запросов.

Для формирования отчетов и аналитики используются сервисы с отложенным расчетом. Их преимущество - использование пакетных (batch) операций. Например, когда в поликлинике вы ждете перед кабинетом, а раз в полчаса медсестра забирает у всех карты чтобы поставить печать - это пакетная операция. Выгоднее сделать один запрос к базе и получить данные 100 пользователей, чем сделать 100 запросов по каждому пользователю - но размер батча ограничен (памятью, буфером). Скорость таких сервисов можно измерять как количество обработанных значений в единицу времени.

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

Показать полностью
26

Типичный backend сервис

Всем привет, работаю java разработчиком 10 лет. Хотел бы в этом посте показать, как выглядит типичный backend сервис на проекте среднего размера.

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

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

Сервисы могут выполнять разные задачи. Одни сервисы запускаются раз в день, чтобы сформировать отчет или выполнить клиринговые операции. Другие сервисы используются для технических нужд. Но самым частым случаем в моей практике является то что принято называть web-сервисом. Такой сервис обслуживает онлайн запросы пользователей, и во взаимодействии с другими сервисами выполняет какие-то бизнес процессы. Приведу диаграмму, как выглядит мир со стороны такого сервиса:

Типичный backend сервис IT, Разработка, Программирование, Java, Онлайн-сервис

Стрелки показывают, кто инициирует взаимодействие. Другие сервисы выглядят плюс-минус аналогично. Более того, сервисы вокруг проекта выглядят похоже - например, сборка логов реализована с помощью kafka и специализированной субд.

Если будет интересно, могу дальше рассказать как разрабатывать api тесты для такого сервиса.

Показать полностью 1
29

Проблемы чисел с плавающей точкой

Всем привет, работаю java разработчиком уже 10 лет, в этом посте хотел бы привести пример, почему нужно с опаской подходить к использованию чисел с плавающей точкой. Проблемы возникают из-за двух ограничений:

  • невозможности представить некоторые дробные числа в конечном виде в двоичной кодировке;

  • ограниченного объема памяти, выделенного для хранения значения.

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

double little1 = 0.0000000000000000000000000000000000000001;
double little2 = 0.0000000000000000000000000000000000000002;
print(little1 == little2); //false

Далее попробуем сложить эти два числа с большим, и проверим, совпадают ли суммы:

double big = 10000000000000000000000000000000000000.0;

print(big + little1 == big + little2); //true

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

Тем кто вынужден работать с нецелыми числами, рекомендую присмотреться к BigDecimal. Всем удачи!

3

Ответ на пост «Про суетливого работника, который вечно всех торопит и напрягает»4

Ответ больше на басню, чем на историю из поста. Работаю разработчиком в финтехе, последние несколько лет выполняю обязанности тимлида. В проектах среднего размера существует определенный порядок выполнения задач: выяснение требований, разработка, тестирование, эксплуатация. При этом часто возникает перекос в штате сотрудников и в рабочих обязанностях - например, единственный qa не успевает закрыть все обязанности по тестированию, что тормозит весь проект.

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

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

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

  • аналитик выбрал неправильную модель, реализация приведет к костылям в коде

  • на тестовом стенде доступы есть, а для продакшена требуется заказывать за два месяца

  • постоянно приходят новые требования и т.д.

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

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

Каждый выбирает как ему работать сам, будет он расширять свою зону ответственности или нет. При текущем порядке отношений it сотрудников и компаний, вознаграждение не всегда пропорционально вкладу, по моему опыту наблюдений - но может быть длительной инвестицией. Лично я придерживаюсь такого правила - освоил сам, автоматизировал или написал инструкцию и передал другому. Если перекладывать басню на офисный манер - это был бы вопрос "что мне делать чтобы дорасти до CTO и зарабатывать больше".

Показать полностью
37

Зачем нужна замыкающая запятая

Всем привет, работаю java разработчиком почти 10 лет, хотел бы рассказать зачем нужна замыкающая запятая, по-английски trailing comma.

В некоторых C-подобных языках элементы массива или перечисления разделяются запятыми:

colors = ["red", "green", "blue"]

При этом есть возможность добавить запятую перед закрывающей скобкой, и это будет валидный синтаксис:

colors = ["red", "green", "blue", ]

Оказывается, это не рудимент прародителя языка, а вполне функциональная особенность. Системы контроля версий предоставляют удобную возможность посмотреть изменения в коде - а также кто их совершал и в разрезе какой задачи. И эта информация отображается в привязке к строке кода - если вы поменяете хоть один символ, то будете значиться как последний редактор:

Зачем нужна замыкающая запятая Разработка, Программирование

Таким образом, если вы планируете расширять содержимое массива, то можно записать его в столбик и добавить замыкающую запятую:

colors = [

"red",

"green",

"blue",

]

И если вы захотите добавить новую строку "yellow", то вам не придется добавлять запятую на строку с "blue", что позволит сохранить у этой строки оригинальные задачу и автора изменений:

colors = [

"red",

"green",

"blue", //строка не изменилась

"yellow", //строка добавилась

]

Надеюсь кому-то будет полезно. Объяснение на stackoverflow - ссылка

Показать полностью 1
61

Что программиста спрашивают про базы данных на собеседовании

Всем привет, работаю бекенд разработчиком почти 10 лет и за это время прошел порядка 150 собеседований. Сейчас есть тренд на использование набора различных СУБД в одном проекте: в зависимости от задач используются реляционные, key-value, документные базы. В этом посте я хотел бы поделиться самыми частыми темами с собеседований, они касаются в основном реляционных (aka sql) баз данных.

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

Связи между данными и поддержка инвариантов. Нужно понимать что такое primary key, foreign key, constraint-ы. Надеюсь, нет необходимости вставлять сюда переводы этих понятий;

Уметь объяснить, что такое нормализация, почему может потребоваться использовать ненормализованные данные;

Знать что такое индекс, составной ключ, потренироваться использовать команду explain для построения плана запроса;

В общих чертах требуется понимать эффекты, которые происходят в распределенных системах при потери связи или выходе узла из строя. Рассуждая на эти темы, могут затронуть CAP теорему, согласованность в конечном счете;

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

Нужно понимать что такое параметризированный запрос, как он защищает от sql-инъекций.

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

Всем удачных собесов!

Показать полностью
Отличная работа, все прочитано!