Организованное программирование | Кирилл Мокевнин
11.4K subscribers
65 photos
243 links
Как из джуниора дойти до мидла, а потом и до синьора
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
加入频道
Дефолты в базе данных могут усложнить вам жизнь

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

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

Вторая проблема связанна с тем, что если в дефолты засунуть данные, которые фактически имеют отношение к бизнес-логике и могут поменяться, то мы получим проблемы при апдейтах. При Zero Downtime Deploy обновление происходит без остановки сериса. В этот момент сначала поднимается новая версия кода, а после кладется старая. В небольшой промежуток времени эти версии работают одновременно на одной базе данных. Представьте что ваш дефолт поменялся, так как изменились бизнес-требования. Если вы поменяете дефолт в самой базе, то может начать неверно работать старая версия кода. Поэтому будет лучше задавать дефолты из кода, через ORM.

А сталкивались ли вы с какими-то подобными ситуациями?
👍193🤔1
Серебряной пули нет
Такую статью написал Фредерик Брукс, аж в 1986 году, где он утверждает, что, даже в отдаленном будущем, никакая технология, техника менеджмента или способ разработки не улучшат производительность, надежность и простоту разработки ПО. Подробнее об этом можно почитать на вики https://en.wikipedia.org/wiki/No_Silver_Bullet но так как этого все равно никто не сделает, я поделюсь его ключевыми мыслями, так как это очень совпадает с моими представлениями о том, как оно работает.

Если кратко, Брукс определяет два вида сложности: случайная и необходимая.

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

С необходимой сложностью все не так просто. Необходимая сложность определяется бизнес задачами. Если наша программа должна делать 30 разных штук, то мы будем должны эти 30 штук написать. И у нас не будет возможность этого избежать, так как само оно делаться не начнет. Нужно считать зарплату? Придется писать код. Нужно строить отчет? Мы будем писать код, который готовит этот отчет.

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

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

А что насчет искуственного интелекта? Тоже самое, большинство фич, которые не являются примитивными крудами, не содержатся где-то в одном месте, как единый кусок кода. Обычно это работа с очередьми, интеграция с внешними источниками, конкретная структура базы, асинхронное выполнение, отправка писем и многое другое, что в сумме может написать только человек. Все остальное всего лишь более умный автокомплит и рефакторинг.
👍23🔥11🤔1🙏1
Стейтфул vs Стейтлесс на примере “PHP против всех”

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

Это рождает много неудобств, особенно если выполнять задачу перезапуска руками. Фактически после каждой правки нужно делать остановку, сборку и запуск. Так можно сойти с ума от ожидания. Продвинутые инструменты решают эту проблему из коробки, они сами следят за изменением файлов и рестартуют приложение. Так могут делать практически все полновесные бекенд-фреймворки типа Django, Rails или Spring Boot. В других, особенно микрофреймворках, подобная функциональность достигается сторонними библиотеками, типа nodemon, которые следят за нужными файлами и выполняют рестарт нужного приложения, причем само приложение может быть написано на любом языке.

Но есть один язык, который кардинально отличается от других, когда речь идет про разработку бекендов веб-приложений и это PHP. С момента своего создания, PHP работал по модели CGI (современный fastcgi в php это фейк). То есть каждый запрос к бекенду поднимает все заново. Для многих, кто с ним не работал это шок, я помню однажды, когда устраивался после PHP на Ruby, я рассказал про эту особенность на собесе, чем парализовал работу офиса на 10 минут, пока там все ходили перепроверять мои слова. Под все заново, имеется ввиду что каждый запрос приводит к чтению файлов с исходным кодом и полному выполнению процесса инициализации на каждый запуск.

У такого подхода, есть одно неоспоримое достоинство. Любое изменение исходников, при следующем запросе отразится в ответе. Для этого ничего не надо специально делать. Подобная схема работы, нередко используется для отладки прямо в продакшене, когда разработчики меняют файлы на живом сайте и тут же проверяют. Это многие наблюдали своими собственными глазами, когда видели на определенных страницах ошибки PHP прямо на сайте. С другими языками такого не случается (js console не считается, это фронтенд).

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

p.s. Еще одно важное преимущество подхода PHP в том, что большую часть времени у маленьких сайтов ничего не приосходит, а значит память свободна. То есть PHP позволяет держать на одном сервере тысячи и десятки тысяч небольших динамических сайтов. На других языках такое невозможно.
👍28🔥13🤯72🤔2
Недавно наткнулся на канал Антона Околелова https://yangx.top/crossjoin где он делится богатым опытом разработки. Много интересных и глубоких мыслей, рекомендую подписаться =>
🔥8🤔1
Forwarded from Cross Join - канал о разработке (Anton Okolelov)
В разработке ПО существует одно неразрешимое противоречие - это оценка сроков.

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

С другой стороны, разработка порою в душе не е**т вообще не знает, сколько надо времени, особенно если
- новая функциональность нетипична
- есть зависимости на другие команды
- будет задействована новая технология
- ТЗ надо сильно уточнять
- надо разобраться в логике легаси-кода

Часто, для того, чтобы точно оценить сроки, нужно, собственно, сделать половину работы. Чем точнее надо оценить сроки, тем больше надо на это затратить времени, что приводит к суммарному увеличению time-to-market, причем все равно без гарантий.

Всё это помножается на когнитивные искажения (необъяснимый оптимизм разработчиков и заказчиков), и в результате оценка становится еще хуже.

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

Самый рабочий подход - это делать фичи как можно меньше, чтобы "от балды" было в меньшем диапазоне, но не всегда так можно, да и гарантии всё равно нет и не будет. Поэтому есть ли смысл упарываться с оценкой? Проще оценивать в "майках": small, medium, large и помолиться Ктулху, чтобы хотя бы так сработало.

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

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

В итоге просто называешь какую-то магическую цифру и молишься Ктулху.

Вишенка на торте - это похвала или премия за то, что успел в срок. Т.е. по сути за то, что угадал, ткнув пальцем в небо. Навык предсказателя-хироманта. Ну молодец, чо 🙂
19👏5😢3🔥1🤔1
График моих выступлений на ближайшие месяцы
Давно не выступал по серьезному, а тут как-то налетело, что не могу не поделиться. Буду выступать онлайн и офлайн. Приходите посмотреть:

17 августа вебинар в Alpina Digital. Доступен для тех, является корп подписчиком на их библиотеку (если ничего не путаю).

Тема: 5 способов сделать программистов эффективнее

Мы поговорим про:
Экстремальное программирование (Заказчик рядом, сборка/тесты, парное программирование)
Деплоим 5 раз в день без предупржедения. Как перестать беспокоиться и начать катить
Trunk-based development. Есть ли жизнь за пределами пулреквестов?
Отказ от стейджинга. Почему и как это делают крупные компании и к чему это приводит
Девопс и все все все

30 сентября онлайн на конференции Ruby Russia

Тема: Как мы боролись с проблемами фабрик и в конце концов пришли к фикстурам

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

7 октября оффлайн в Алматы на конференции Kolesa Conf’23

Тема: Конечные автоматы, как способ значительно упростить логику и понимание кода

В этом докладе, мы увидим, что практически любая бизнес-логика в коде укладывается в модель конечного автомата, то есть состоит из набора состояний и переходов между ними. Такой взгляд на происходящее, позволит изменить подход к проектированию и реализации наших приложений. Для этого мы рассмотрим множество реальных примеров, поговорим про опыт внедрения, посмотрим на примеры реализации в разных языках программирования и для разных направлений (бекенд, фронтенд и т.п.)
🔥28👍6🤔1💩1
Качество кода: Сверху или снизу?
Ко мне недавно обратились ребята, которые разрабатывают финансовый сервис с просьбой провести консультацию на тему того, как улучшить качество кода. У ребят были всякого рода сомнения в том что текущий код хорош и были мысли над чем надо поработать. Основная идея заключалась в том, что сначала нужно посмотреть на систему сверху, определить концептуально слои приложения и правильно по ним все распределить.

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

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

После этого я немного поразмышлял над тем, как все это можно объяснить. Почему нужно идти с этой позиции и как это можно объяснять другим. В результате мне в голову пришла такая аналогия. Грубо говоря разделение по слоям, это уровень выполнения сложных технических элементов в любом виде спорта, например троюков на велосипеде. В свою очередь грамотное создание функций, организаций объектов, работа с состоянием, автоматами, это базовая техника, без которой не получится делать что-то сложное. То есть нельзя всего этого не уметь классно делать, но при этом быть способным отлично раскладывать систему на слои и/или сервисы.
16👍8🤔3👎1
Насколько процентов (примерно) ваша компания соответствует практикам описанным в этой статье https://guides.hexlet.io/ru/check-list-of-engineering-practices/
Anonymous Poll
12%
90-100
6%
80-90
16%
70-80
15%
60-70
15%
50-60
5%
40-50
7%
30-40
7%
20-30
2%
10-20
15%
< 10
3👍2🥰1🤔1🤗1
Итоги вебинара в альпине. О чем молчат программисты

На днях я проводил вебинар для программистов, лидов и тех директоров для клиентов корпоративных библиотек альпины. Было около 100 человек и мы довольно плотно пообщались полтора часа. Говорили о всяких техниках, которые позволяют уменьшить time to market способами, которые либо не очевидны, либо идут в разрез с общепринятыми концепциями. Здесь я поделюсь теми концепциями, которые вызывали наибольший интерес и дискуссию.

Большая часть того, что описывалась в докладе, базируется на том как устроен инжиниринг в букинге https://apptractor.ru/develop/kak-ustroen-inzhiniring-v-booking-com.html Главная идея там, это то, что мы двигаемся быстро, но по пути можем что-то ломать. Остальное придется прочитать по ссылке выше 🙂

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

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

Если вам нужно больше доказательств, то пожалуйста https://news.ycombinator.com/item?id=30899362 в фейсбуке стейджинг не используется. https://refactoring.fm/p/do-you-need-staging большая и классная статья про это же. Вообще если погуглитть, окажется что подобных статей и примеров отказа от стейджинга очень много.

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

А у вас есть стейджинг?
👍12🔥5🤔1
Канареечный релиз



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

Zero Downtime Deploy
Подход при котором запуск новой версии кода происходит без остановки старой. С точки зрения пользователя выглядит так, что сайт не останавливается, а при очередном обновлении страницы начинает работать новая версия. Для реализации требуется правильная работа с балансировщиком нагрузки. Лучше всего такой вид деплоя автоматизирован в Kubernetes, который позволяет настроить его буквально несколькими настройками. Все остальные способы как правило более затратны и требуют либо ручных действий, либо необходимости написания автоматизации самостоятельно.

Обратная совместимость по структурам данных в базах, очередях и т.п.
Zero Downtime Deploy, а следовательно и Канареечный Релиз не может работать без изменения подходов в разработке. Например в таком случае нельзя делать изменения в базе данных без обратной совместимости, иначе будет невозможно одновременно запустить старую и новую версию кода. Совместимость нужна не постоянная, а только на ближайший релиз. Дальше можно менять или удалять то что требовалось для предыдущих релизов.

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

В итоге если новый релиз и содержит ошибки, то это коснется только небольшой части пользователей, а хорошо настроенный мониторинг и автоматизация позволят быстро переключить пользователей на старую версию кода.
👍26👨‍💻31🔥1💋1
Коллекторы ошибок

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

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

1. Если ошибка произошла первый раз, то отправляем нотификацию с учетом настроек, может письмо, может в слак может еще как.
2. Вторая ошибка и дальше никак не показываются, так как мы уже оповестили команду
3. Если ошибка произошла 10 раз после деплоя, то вероятно она важная и надо сообщить еще раз
4. Если ошибка произошла 100 раз, потом 1000, то тоже надо отправлять, так повышается приоритет

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

Если вы все еще деплоитесь без такого сервиса, то самое время подключить его. Самым популярным является https://sentry.com (и вроде как у него есть бесплатный тариф). Для тех кому не подходит облачная версия, можно поставить self-hosted.

Какой коллектор используется у вас?
👍11🤔6🔥2
Откатывай!

Но что делать, если все таки деплой пошел не по плану?

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

Правило номер два: Отката не существует. Как это? Вспомним, что при правильно настроенной системе, у нас реализован Zero Downtime Deploy с базой только вперед. Миграции только накатываются, а следующая версия базы всегда совместима с текущей. Это значит что при откате на предыдущую версию, с базой ничего не происходит. Тут все хорошо.

А что с кодом? С точки зрения системы деплоя не должно быть разницы куда мы идем, вперед или назад. Деплой это замена текущего кода, на какой-то другой, даже если это предыдущий релиз. То есть получается что мы просто выполняем еще один деплой, но предыдущей версии.

Из этого следует важный вывод. В системе не должна присутствовать особая процедура отката. Если она есть, значит в проекте есть пространство для улучшения.
👍415🤡32
Пирамида тестирования была ошибкой


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

Когда-то очень много лет назад, я пошел по этому же пути, но быстро понял что фокус на юнит тестах не самое эффективное вложение. Сейчас об этом уже говорят многие и пишут тоже https://kentcdodds.com/blog/the-testing-trophy-and-testing-classifications Если вы не знакомы с Кентом, то обязательно посмотрите, он говорит о сдвиге парадигмы (хотя откровенно говоря, для меня подобная структура всегда была более естественной). Но есть и другой Кент, на которого очень любят ссылаться все кто пишут тесты. А вот что он сказал в 2005 году:

I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence (I suspect this level of confidence is high compared to industry standards, but that could just be hubris). If I don’t typically make a kind of mistake (like setting the wrong variables in a constructor), I don’t test for it. I do tend to make sense of test errors, so I’m extra careful when I have logic with complicated conditionals. When coding on a team, I modify my strategy to carefully test code that we, collectively, tend to get wrong.
Different people will have different testing strategies based on this philosophy, but that seems reasonable to me given the immature state of understanding of how tests can best fit into the inner loop of coding. Ten or twenty years from now we’ll likely have a more universal theory of which tests to write, which tests not to write, and how to tell the difference. In the meantime, experimentation seems in order.

И я с ним согласен
22👍5🤔3
This media is not supported in your browser
VIEW IN TELEGRAM
👍62🤔1
Производительный программист. Переоткрываем Oh My Zsh

Одна из моих любых тем, это эффективное рабочее окружение. И сегодня я хочу поговорить про Oh My Zsh, который значительно поднимает эффективность работы в командной строке, причем не только личную, но и командную.

В двух словах что это если вы не знакомы. Oh My Zsh это система плагинов + набор плагинов добавляющая разные фичи в zsh (если вы на баше, то стоит перейти). По умолчанию включено всего лишь несколько плагинов, среди них git, который автоматически начинает показывать текущую ветку в git как на скрине выше.

Многие на этом останавливаются, думая что это все возможности Oh My Zsh, но мякотка находится дальше. Я сам не сразу понял это. Дело в том, что каждый плагин Oh My Zsh связан с какой-то утилитой, для которой, помимо прочего, он добавляет алиасы. Например правильный способ сливать изменения из origin в git это команда git pull —rebase. Поставив Oh My Zsh вы можете сразу же начать использовать сокращение gupa. Посмотрите в документацию: https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/git этих комбинаций сотни! Все их запомнить невозможно, но достаточно взять самые используемые. Благодаря этому я полностью поменял свою работу в git, docker, docker compose и других инструментах.

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

Домашнее задание: Поищите среди плагинов те, что вам интересны и попробуйте потыкать их горячие клавиши https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins
❤‍🔥29👍123🤔2🥴1
Как TypeScript выпиливали из Turbo
Неделю назад отшумела история, с тем что ребята из basecamp выпилили typescript из их библиотеки Turbo. И что тут началось. DHH аж пришлось писать еще один пост https://world.hey.com/dhh/open-source-hooliganism-and-the-typescript-meltdown-a474bfda где он офигивает и немного негодует от происходящего.

Если она прошла мимо вас, обязательно посмотрите, это классный кейс в копилку нашей биологии) Кстати забавно, я в Твиттере про это тоже написал и мне тут же прилетел вопрос “а что ты думаешь по этому поводу?”. Подозреваю если бы я дал неправильный ответ, то мог бы попасть.

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

Я не понимаю этих людей

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

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

Они не разбираются

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

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

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

p.s. Буду иногда пробовать формат не трансляции моих знаний и опыта из разработки и связанных тем, а комментирование каких-то интересных мне событий и новостей. Если что подкидывайте материалы.
👍442🤔1
Фильтрация данных: язык вместо кода

Хочу рассказать про интересное решение, которое позволяет унифицировать и значительно упростить фильтрацию данных в api или при обычных запросах с параметрами запроса.

Обычно подобная фильтрация выглядит так: site.com/items?size=5&city=london

Как правило, реализация подобных фильтров делается руками. Мы придумываем набор полей, по которым надо фильтровать и дальше в бекенде формируем sql запрос через билдер.


app.get('/employees', (req, res) => {
  const { firstName, lastName, age } = req.query;
  let results = [...employees];
  if (firstName) {
    results = results.filter(r => r.firstName === firstName);
  }
  if (lastName) {
    results = results.filter(r => r.lastName === lastName);
  }
  if (age) {
    results = results.filter(r => +r.age === +age);
  }
  res.json(results);
});


Самая мякотка в этой системе появляется тогда, когда у нас не просто совпадение по значению, а разнообразные предикаты в стиле “больше”, “меньше равно”, “содержит”, поиск по связным сущностям и так далее. В большинстве случаев такой код пишется прямо под конкретную ситуацию на бекенде. В интернете немало статей про это: graphql https://www.apollographql.com/blog/graphql/filtering/how-to-search-and-filter-results-with-graphql/ java https://medium.com/@cmmapada/advanced-search-and-filtering-using-spring-data-jpa-specification-and-criteria-api-b6e8f891f2bf

Но существует и более интересный подход, который позволяет автоматизировать задачу практически на 100%, убрать написание большей части предикатов и получить возможность реализовывать фильтры высокой сложности за полчаса работы. Познакомился я с этим подходом в библиотеке ransack, которая автоматически встраивается в Rails ORM. Работа этой библиотеки с точки зрения сервера сводится буквально к одной строчке: Model.ransack(params). А дальше начинается самое интересное. Концепция этой библиотеки состоит в том, что вместо императивного описания что делать на бекенде, мы декларативно описываем как фильтровать через правильное именование параметров.

Например, если мы хотим точное соответствие по полю name, то мы должны назвать параметр name_eq, если мы хотим искать по вхождению то name_cont. Тоже самое с числами. Если нам нужен возраст старше или равно, то мы пишем age_gt (greater than). Если мы хотим тоже самое но по связанным сущностям, то тогда описываем имя через связь user__name_eq (то есть ищем по имени пользователя, где пользователь это связь).


<input type="text" name="q[first_name_or_last_name_cont]">
<input type="text" name="q[email_cont]">


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

Дока по предикатам: https://activerecord-hackery.github.io/ransack/getting-started/using-predicates/
Демо Ransack: http://ransack-demo.herokuapp.com/users/advanced_search

Домашнее задание: Подобные библиотеки существуют и в других языках, но не все о них знают. Попробуйте найти библиотеку для своего стека и сбросьте в комментарии ссылку на гитхаб
🔥335👍3🤔1
Что не так с юнит-тестами


Помните мой недавний пост про изменении концепции тестирования на trophy? Там мы видим что количество юнит-тестов сведено к минимуму, что идет в разрез с общепринятым “пишем в первую очередь юниты”. И в этом посте я хочу рассказать про проблемы юнитов, которые существовали всегда и многие опытные разработчики на это не раз натыкались.

Часто говорят, что юниты помогают рефакторить код. Я же скажу, что именно юниты мешают его рефакторить. Полезный рефакторинг, как правило это не изменение того как написан, например, конкретный цикл, это переработка абстракций, выделение слоев, перемещение кода, перераспределение кода между функциями и методами. Что происходит с юнитами в таком случае? Правильно, они становятся полностью бесполезными, так как их придется переписывать. В моей практике была ситуация, когда 35 000 строк кода юнит тестов просто выкинули, так как в проекте делался важный рефакторинг и команда поняла что просто не потянет апгрейд тестов (по факту написание их с нуля).

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

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

Ответом может быть: но они же быстрые. В реальности, в современных фреймворках скорость выполнения интеграционных тестов достаточно быстрая, чтобы не испытывать проблем. Да, при этом есть определенные техники работы с базой данных (не Моки!) которые надо соблюдать, но это уже давно отработанная история. Медленно же выполняются e2e тесты, но они пишутся независимо от юнит тестов, поэтому тут даже нет выбора.

p.s. Какие тесты в основном пишут в вашем проекте?
👍57👎27🤡71🤔1
Когда стоит писать юниты

То есть юниты не нужны совсем?

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

Но и тут есть детали. Понимание того, что является юнитом, а что не является – довольно не простой вопрос, на который по разному ответят разные программисты. Кто-то скажет что юнит это отдельный модуль в их системе. Кто-то скажет что это код, который включает в себя небольшой кусок кода, скажем один метод или класс, кто то скажет что юнит, это скорее когда мы все замокали так, что не вызывается ничего кроме нашего кода. Кто-то скажет что в юнитах можно делать запросы к базе данных, кто-то скажет что нет. Об этом мы поговорим в следующем посте и потом тему с тестами временно закроем)
👍35🔥3🤔1