awfun

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

Сколько языков знает программист

Всем привет, работаю java разработчиком больше 10 лет. Так как сейчас высок спрос на обучение, есть и предложение - периодически встречаю на авито анкеты репетиторов / менторов по программированию. Заметил довольно много анкет преподов, которые готовы обучать нескольким языкам. Хотел бы в этом посте выразить своё мнение по этому феномену.

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

Сколько языков знает программист Программирование, IT, Разработка, Обучение, Длиннопост

Технологии, сгруппированные по слоям

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

Это приводит к формированию т.н. T-shaped наборов умений, когда разработчик является экспертом в одной-двух технологиях, и немного работал со множеством смежных. Вот примеры типичных стеков:

  • Java / Spring Boot; Postgres; k8s и gitlab ci на уровне пользователя

  • LAMP

  • MEAN

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

А вот использование нескольких языков на проекте обычно бывает избыточным. И типичное распределение языков в проекте выглядит как-то так:

Сколько языков знает программист Программирование, IT, Разработка, Обучение, Длиннопост

Основной язык для бекенда, шаблоны в HTML, немного SQL, пара скриптов на bash/Python, настройки сборщика/докера/деплоя

Иногда приходится дорабатывать проекты других команд, либо разгребать легаси в собственном проекте, и тогда может потребоваться разобраться с другим языком программирования. Мне приходилось править баги в JS коде, переписывать Scala сервис, несколько месяцев разрабатывать на Go. Каждый раз кроме языка приходилось разбираться в сборке проекта и запуске тестов. Это требует затрат внимания, и если нет цели сменить стек, то лучшим выбором становится минимизировать погружение.

Есть отдельные сильные специалисты, которые имеют широкий кругозор и профильное образование. Есть фулстеки, которые работали с 2-3 языками (JS + перешли с PHP на Go). Но у большинства программистов есть какой-то один язык, который он использует на постоянке.

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

  • трем или более языкам одного стека (C++, C#, Java, PHP, Python)

  • разным стекам (бекенд + фронтенд + мобайл + data science + unity + ...)

  • по ставке меньшей чем у разработчика соответствующего уровня

Сколько языков знает программист Программирование, IT, Разработка, Обучение, Длиннопост

Пример объявления, предлагающего обучение

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

Желаю всем желающим вкатиться в it офферов и интересных проектов!

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

Программист про (преждевременную) оптимизацию

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

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

List<String> visitorIds;
Set<String> visitorIds;
print(visitorIds.contains("123"));

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

Сложнее обстоит дело с индексами в БД - есть инструменты чтобы выбрать правильные индексы, но этот вопрос нужно решать на месте. Не добавил индекс - будет медленное чтение, добавил индекс - медленная запись и повышенное потребление диска. Потребовалось добавить индекс на большом размере данных - нужно останавливать сервис.

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

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

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

  • перенести всю логику из java в sql (код админки, нагрузка ~100 запросов в день)

  • ускорить расчет закрытия предыдущего дня (при том что расчет не нуждался в ускорении)

  • использовать параллелизацию (что ломает компоненты, ориентированные на thread per request подход)

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

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

Пример задачи с собеседования

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

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

abc, acb - является

abba, abab - является

abb, aab - не является

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

abb -> [a=1, b=2]

aab -> [a=2, b=1]

Количество соответствующих символов не совпадает

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

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

Всем удачи на собеседованиях и работе!

53

Разработчик о командной работе в it

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

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

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

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

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

Писать инструкции. Если с одним вопросом сталкиваются многие сотрудники, эффективнее будет закрепить порядок его решения в текстовом виде. Когда лень писать инструкцию самому, хорошим решением будет заставить написать инструкцию того, кто обратился с вопросом.

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

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

Буду рад, если эти приемы пригодятся и в вашей работе, удачных проектов и команд!

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

Использование Docker для локального тестирования

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

Средний корпоративный код содержит не очень много логики, но множество интеграций с другими сервисами, несколько баз данных (postgres, кеш в redis, поиск в elastic), очередь (kafka), хранилище документов (s3) итд. Хотелось бы иметь возможность тестировать приложение на локальной машине, без необходимости доставки каждого изменения до общего dev стенда.

Чтобы не разворачивать весь стек технологий на рабочем ноуте, используют Docker контейнеры. Часто образ контейнера содержит минимальную сборку linux (alpine) и сам сервис, например postgres. Внутри контейнера сервис доступен по своему стандартному порту (5432 для postgres), но обратиться напрямую к нему нельзя - на время работы контейнера Docker будет предоставлять внешний порт

Использование Docker для локального тестирования Разработка, Программирование, IT, Docker, Тестирование

Postgres поднят, но порт 5432 доступен только внутри контейнера

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

Для запуска Docker на рабочей машине можно установить Docker desktop. Для поддержки Docker в CI может потребоваться конфигурация dind (docker in docker). При разработке в компании также потребуется указывать корпоративный репозиторий образов. Версия в образе должна соответствовать используемой на продакшене версии сервиса.

Для автоматизации работы с Docker из java тестов я использую библиотеку testcontainers:

@Container
@ServiceConnection
static PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres");

Здесь postgres - имя контейнера без указания версии. Аннотация Container указывает на необходимость запустить Docker до старта теста. Аннотация ServiceConnection позволяет java узнать внешний порт сервиса и подставить в свой конфиг.

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

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

Императивный и декларативный код

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

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

Задан список чисел, на примере:

List<Integer> input = List.of(1, 2, 3, 4, 5);

Нужно найти сумму квадратов чётных чисел - значений элементов массива. Чётные числа это такие числа, которые делятся нацело на 2, то есть остаток от деления числа на два равен нулю. Чётные числа здесь 2 и 4. Их квадраты это 4 и 16. Искомая сумма 4 + 16 = 20.

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

int sumEven = 0;

for (Integer x : input) { //пройти по всем элементам

__ if (x % 2 == 0) { //для четных

____ sumEven += x * x; //посчитать квадрат и добавить к сумме

__ }

}

assertEquals(sumEven, 20);

Декларативный подход можно показать на примере использования апи java.util.stream. Последовательно указываются инструкции для фильтрации, преобразования и аккумуляции результата:

int sumEven = input.stream()
__ .filter(x -> x % 2 == 0)
__ .map(x -> x * x)
__ .reduce(0, Integer::sum);
assertEquals(sumEven, 20);

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

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

Самолет в США совершил экстренную посадку после того, как у него отпала часть корпуса1

Самолет в США совершил экстренную посадку после того, как у него отпала часть корпуса Гражданская авиация, Самолет

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

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

Идемпотентные операции в программировании

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

Пусть исходными данными будет число 5, а операцией будет "умножить на 2". В зависимости от количества n применений операции будем получать разный результат:

n = 0 -> 5
n = 1 -> 10
n = 2 -> 20 и так далее

Ничего удивительного. Но если возьмем операцию "умножить на 0" то результат будет следующий:

n = 0 -> 5
n = 1 -> 0
n = 2 -> 0 и так далее

Видно, что после n = 1 результат не меняется. Свойство операции давать одинаковый результат при однократном и многократном применении называется идемпотентностью. Получается, что операция "умножить на 0" идемпотентна, а "умножить на 2" нет.

Рассмотрим более близкую к бизнесу ситуацию. За баланс пользователя сотового оператора отвечает один сервис, а обработкой платежей занимается другой. Пользователь хочет пополнить телефон, деньги с карты уже списали, и осталось дождаться когда увеличится баланс. Нужно чтобы сервис баланса выполнил операцию "зачислить пользователю Васе 100р", а поручение на это дает сервис платежей:

Идемпотентные операции в программировании IT, Программирование, Разработка, Операция, Финтех, Длиннопост

Подача поручения и успешный ответ

Но что делать сервису платежей, если он не получил положительный ответ от сервиса баланса? Сетевое подключение не стабильно, и проблема может произойти:

  • в момент отправки поручения - тогда Вася не увидит свои 100р, будет писать в техподдержку

  • в момент доставки ответа - тогда пользователь увидит зачисление

Проблема в том, что сервис платежей не может достоверно понять, было обработано поручение или нет. Он видит только что не пришел положительный ответ. Сетевые проблемы исчезают так же быстро как появляются, и можно было бы попробовать отправить поручение еще раз (retry). Но что если в первый раз поручение таки было успешно обработано, и в случае ретрая баланс пользователя будет увеличен еще раз, в сумме на 200р?

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

Чтобы операция пополнения баланса стала идемпотентной, нужно сначала предусмотреть возможность установить уникальность операции. Если Вася пополнял баланс на 100р дважды - вчера и сегодня - то такие операции должны интерпретироваться как разные. Получается, можно было бы различать операции по такому набору атрибутов: {имя пользователя, сумма, дата}. Еще лучше использовать синтетический идентификатор, например id операции списания с карты.

Идемпотентные операции в программировании IT, Программирование, Разработка, Операция, Финтех, Длиннопост

Итак, сервис платежей, помимо бизнес атрибутов, передает технический атрибут - id. Сервис баланса запоминает id обработанных ранее поручений, и игнорирует повторную обработку, в любом случае возвращая успешный ответ. Усилиями двух сервисов операция зачисления стала идемпотентной.

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

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