Информация о канале
2pegramming
Подписчиков: 692
Стоимость рекламы: 0 руб.
Описание канала: Грустно о программировании. Все проблемы сюда: @davydovanton

Medium: https://medium.com/pepegramming

Ссылки на конкретные посты: http://telegra.ph/Pepegramming-Contents-03-11
Обратная связь: https://goo.gl/forms/iUd1Gufq6WnTsaO62

Кто рекламировался:

Где рекламировался:

Суточный охват записей
График изменения цен
Записи канала
так же, подсказали важную мысль на счет самоутверждения и доверия, дополнил тексты
BAR1: 470
BAR2: 499
BAR3: 696
696
На работе попробовал новую для себя практику post review. Делюсь опытом.

Medium
Telegraph
MindNode
BAR1: 496
BAR2: 539
BAR3: 707
707
Пятничное чтиво

Maintaining 65k open connections in a single Ruby process
Соеденив вместе puma, rack и hijacking получим развлечение на вечер и статью, в которой автор подробно рассказывает как с помощью этих вещей добиться обработки 65523 открытых коннекшенов. В конце статьи - ссылка на гист с полным кодом (всего 55 строк кода с комментариями).
Из проблем: такой код съедает 350 мб памяти, что много (nginx для примера потребляет 2.5 мб), race conditions проблемы (поправились с помощью использования http://amp.gs/vXFN и http://amp.gs/vXFA).
Если хотите разобраться как подобные штуки работают и как еще можно ускорить приложение - маст рид.

—————————————

Architecture of a high performance GraphQL to SQL engine
В первый раз, когда увидел graphQL подумал, что было бы круто получить сервис с 1 в 1 доступом к базе. Спустя 3 года появилась статья, которая описывает как работает Hasura, сервер-прослойка между клиентами и постгресом. Стоит обратить внимание, что сервис написан на хаскеле, по бенчмаркам быстрее prisma и postgraphile. Надеюсь что подобные сервисы смогут в будущем элегантно решить проблему кастомной логики.

Русский перевод

—————————————

Six Great Reasons to Build Service Architectures in Ruby with Eventide
За eventide слежу давно. Даже упоминал этот проект пару раз в выступлениях. Для тех кто не в курсе, eventide - тулкит для построения ES систем на руби. Много фич, огромная и полная документация. В статье выше описываются 6 причин, почему eventide стоит попробовать. Для меня причины спорные, но для ознакомления стоит прочитать.

Рад, что таких проектов становится больше. Так же стоит посмотреть на sequent и RailsEventStore. Круто, что библиотеки не просто появляются, но и развиваются. А так же, появляется больше ES ориентированных конференций в мире руби.
BAR7: 1100
1100
Пятничное чтиво

Microservices Are Something You Grow Into, Not Begin With — Nick Janetakis
Давно задумываюсь о том, что микросервисы - архитектурный блокчейн. Считаю, что это кейворд, который усложняет стартапы и полезен только гигантам вроде гугла или в системах, где распределенная архитектура архи важна. На деле микросервисы приносят много новой, асинхронной боли (привет distributed мир), о которой больше говорят. Как пример, segment, который мы используем на работе, поделился историей не обдуманного использования микросервисной архитектуры.

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

Перевод на русский.

—————————————

Why You Should Never Use MongoDB
Люблю истории, особенно истории провалов. В статье выше, ребята из диаспоры рассказывают о том, как начинался проект, почему выбор пал на монгу и как потом перенесли данные в постгресс. В истории идеально все. Понравился опыт хранения социальных данных и способы работы с ними.

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

Перевод на русский.

—————————————

Concurrent Ruby with Tasks · software is fun
Асинхронный код - боль. Использование concurent-ruby в бизнес логике - двойная боль. В функциональных языках для подобных вещей используется Task монада, в js - promises. @flash_gordon сделал реализацию подобной монады в dry-monads, а в статье выше описано зачем Task нужен, как пользоваться и приводится примеры работы с Do нотацией.
936
Пятничное чтиво

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

Совет о гейтвее (Building a gateway in every service) зарезонировал с внутренним архитектором. Причина в том, что в системах о которых читал или слышал, клиенты вызывали сервисы в рандомном порядке. Это приводит к сложности: один сервис начинает вызывать неограниченное количество других сервисов, которые по цепочки вызывают друг друга. Сервисы начинают знать друг о друге, что может влиять на изоляцию и поддерживаемость кода. Элегантное решение проблемы - gateway прослойка, которая последовательно вызывает нужные сервисы и с которой обращаются другие клиенты.

HTTP/2 for Ruby Web Development
Еще один “modern asynchronous HTTP/2 capable web server” для руби. Что понравилось: чистый руби, может в http/2, поддерживает rack приложения. К тому же, ребята с ходу пишут, что продакшен код, использ хоть сейчас.
Но к сожалению к этой штуке хватает и вопросов: как быстро работает? Что с памятью? На сколько сервер готов к продакшену?

Поэтому будет интересно посмотреть, во что превратиться проект, а также, попробовать запустить Falcon в своих проектах.

Understanding user support systems in open source
Open source проект в первую очередь продукт, а не открытый код. Это значит, что у проектов есть пользователи. А где люди, там ответы на вопросы и решение проблем. В статье выше описывается как построить систему помощи пользователям.

Как мейнтейнер - круто, что таких статей становится больше, потому что, в мелких и средних OSS проектах не хватает людей, которые понимают, как улучшить жизнь проекта и людей вокруг него. Возможно в этом причина не оптимальных процессов релизов, работы и анбординга (если такие процессы есть). Или сложностей с получением помощи, а также неочевидные фичи, которые пытаются сделать мейнтейнеры. Так что, если хотите пойти в менеджеры, а на работе не пускают - попробуйте помочь open source проекту со внутренними процессами.
BAR1: 516
BAR2: 540
BAR3: 587
BAR7: 686
686
Пятничное чтиво

Целостность данных в микросервисной архитектуре
Архитектурная статья из авито о том, как сохранить данные в микросервесной архитектуре с зоопарком баз данных.  Рассматривается ACID принцип в связке с микросервисами. Для обеспечения целостности предлагается использовать сага паттерн. Вообще, сага паттерн не заслуженно пропускается в мире руби разработчиков, хотя в некоторых моментах может сильно облегчить жизнь, когда приходится делать бизнес транзакции со сторонними сервисами. Ну и ссылка из ссылки о паттерне в придачу.

Am I doing it wrong?
Cервис объекты приходили в rails тяжело и вызывали много боли у людей привыкшим к rails way (исправте меня, если не прав). В гисте выше разработчик, которого уволили за сервис объект в проекте, спрашивает правильно ли он сделал и как с этим жить дальше. Из интересных комментаторов: Avdi Grimm, Mike Perham, Nick Sutterer, Piotr Solnica и DHH.

How to Read Source Code
Мне сложно читать чужой код. Это отнимает силы, время и мотивацию. К сожалению, заниматься этим приходиться часто, поэтому статьи с идеями, как упростить этот процесс - ❤️.

Добавлю два совета по чтению чужого кода:
- когда документация желает лучшего, смотрите в интеграционные тесты
- если нужно быстро разобраться что и как библиотека делает - дебаггер выручает. В руби открываем исходники (bundle open <gem name>) ставим дебагер и проходим, смотря что происходит
BAR1: 543
BAR2: 553
BAR3: 599
BAR7: 696
696
Пятничное чтиво

User-defined Order in SQL
Сортировка, заданная пользователем не тривиальная задача. На каждый случай в голову приходит тысячи вариантов решения проблемы. В тексте показано, как реализовать алгоритм пользовательской сортировки дешево, используя толкьо одно поле в базе. Если задумали сделать аналог трелло или понадобилась подобная сортировка - однозначный маст хев.

Что бы не спойлерить решение, предлагаю игру. Напишите на бумаге решение, а потом прочтите статью и сравните решения. Если решение кардинально отличается - присылайте ссылку на гист с описанием, опубликую.

Testing best practices
Обожаю гитлаб за открытость. Два года назад, забрал кучу полезных идей из плейбука, а после - сделал описание hanami-paybook по аналогии с гитлабовским. Сегодня - мануал о тестировании в рельсе. Зацепил fast\_spec\_helper.rb,  хочу попробовать использовать похожую практику в своих проектах. Так же, будет интересно тем, кто хочет узнать, как тестировать большие приложения и где можно срезать время выполнения тестов.

Why Funding Open Source is Hard
На RubyRussia в первый раз проводились круглые столы о сервисах, найме и OpenSource. При обсуждении OSS поднялась тема финансирования продуктов с открытым исходным кодом. Из-за этого, вспомнилась статья о том, почему так тяжело привлекать средства в опенсорс.

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

Русский перевод на хабре.
BAR7: 784
784
После открытого стола об open source проектах на rubyrussia задался вопросом, а какие проблемы испытывают люди. Я нашел четыре разных группы лиц, проблемы которых сильно отличаются. Таким образом появился эта короткая форма. Буду рад вашим ответам, а результаты опубликую в ближайшее время.

https://goo.gl/forms/LPHPIYWJzUUkjqF52
BAR7: 829
829
Пятничное чтиво

В прошлый раз пропустил из-за розыгрыша. Сегодня исправляюсь.

Software Architecture Patterns Book
Бесплатная книга о различных архитектурных паттернов систем. Подробно расскажет о пяти видах архитектур:

- Layered architecture
- Event-driven architecture
- Microkernel architecture
- Microservices architecture
- Space-based architecture

Хочу обратить внимание на вторую главу, в которой описывается построение Event-Driven архитектуры. Приводится в пример две топологии, mediator и broker. Идея в том, что в mediator топологии кастомер кладет инициирующий эвент в общую очередь эвентов, а медиатор уже организует события по определенным каналам. В broker топологии используется обратный подход: эвент обрабатывается распределенно и при каждой обработке могут добавляться новые события в очередь эвентов.

DDD for Rails Developers. Part 1: Layered Architecture
DDD набирает обороты в мире руби. Слоистые архитектуры покоряют умы разработчиков. В статье доступное описание зачем это нужно, как сделать и что это такое. Много очевидных, но полезных советов (изоляция AR и бизнес логики)

Soft Skills: The software developer’s life manual
Список софт скилов, которые могут помочь разработчику (и не только) улучшить качество жизни. Из списка, хотелось бы обратить внимание на “Marketing yourself”. По моему, это один из навыков, которому в россии, к сожалению, нигде не учат (если не прав - напишите пожалуйста). На эту тему есть статья из лайвхакера), читать на свой страх и риск.
BAR1: 689
BAR2: 758
BAR3: 810
BAR7: 1400
1700
Перед конференцией, хотелось бы добавить организационных моментов.

Мероприятия

4.10 - др Maciej Mensfeld (http://amp.gs/h7ia)), идем отмечать и пить пиво в RULE taproom в 20:00
5.10 - препати конференции, RULE taproom 20:00
6.10 - конференции и афтепати
7.10 - воркшопы (если найдутся силы - можем устроить афтепати для афтепати)

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

Доклады которые понравились
В этом году слушал прогоны некоторых докладов. Из того, что понравилось и что рекомендую к посещению

1. Эволюция rails архитектуры. Просто маст хев. Доклад не технический, но интересно послушать как github, cookpad и basecamp живут с рельсой. Кроме того, на докладе будет розыгрыш (но это не точно)
2. Фичафлаги. Использую этот подход на работе и читал фаулера, но даже с таким багажом узнал много нового. Если испытываете проблемы с доставкой фич в прод - маст хев
3. Mruby, слежу за проектом уже 3 или 4 года. Искренне рад, что такие доклады появляются. Узнаете что это, зачем и где использовать
4. Мониторинг. Мониторинг не самая популярная тема в руби сообществе, узнаете на что смотреть в первую очередь, а так же будет анонс новой библиотеке марсиан

Что еще
Мой доклад будет сильно пересекаться с темами из Designing Data-Intensive Applications (DDIA). Поэтому хочу разыграть эту книгу. Подробности на докладе.

Стикеры! С радостью возьму и раздам.

До встречи!
BAR1: 484
BAR2: 515
BAR3: 536
BAR7: 924
BAR30: 1200
1200
https://prnt.sc/kzrn0a
BAR1: 467
BAR2: 502
BAR3: 520
BAR7: 687
BAR30: 900
900
Всё куплено೯
BAR1: 463
BAR2: 497
BAR3: 515
BAR7: 690
BAR30: 911
911
Как и обещали, вместе с @wi11son разыграли 2 билета на конференцию. Наши победители: @hana1995 и @asmorozov. Организаторы напишут вам по поводу билетов.

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

Полное видео с записью того, как и что делали тут:
https://youtu.be/FI7Fa55VrjQ
BAR1: 607
BAR2: 653
BAR3: 684
BAR7: 816
BAR30: 1000
1000
Hапомню, что в эту пятницу мы разыгрываем два билета на предстоящую конференцию. Если не успели записаться - самое время!

Пока учавствуют 100 человек, а это значит, что шансы получить билет высоки

http://amp.gs/hthb
BAR3: 890
BAR7: 989
BAR30: 1200
1200
У меня больше 30 репозиториев в гитхабе, за которыми надо следить и оперативно закрывать ишю (или отвечать на них). Так как эти репозитории в разных организациях, то постоянно бегать между ними - гиблое дело. Могли бы спасти нотификации, но к сожалению с ними не увидить картину целиком.

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

Сам проект

Доска с моими прокетами и ишю, которые хотелось бы закрыть (можно с этим помочь)

Гитхаб - davydovanton/cookie\_box. В гитхабе примеры того как hanami дружит с dry-system и как работают do-notation на практике. А так же пример представления поддерживаемой архитектуры и пример использования веб хуков гитхаба.
BAR1: 483
BAR2: 921
BAR3: 970
BAR7: 1200
1400
Пятничное чтиво


A guide to logging in Java
Полноценный гайд о том, как использовать логгер в приложении. В качестве примера используется java и разные виды логгеров. Меняем  java на Any Lang - получаем маст хев чтиво.

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

Learning SQL Resources
Список ссылок для того, что бы изучить SQL, а так же PostgreSQL и MySQL. Добавлю, что PostgreSQL Exercises сильно помог разобраться в сложных запросах и на него стоит потратить время.
BAR3: 1100
BAR7: 1300
BAR30: 1600
1600
Благодаря ребятам из Saint P Ruby User Group (https://t.me/saintprug) количество билетов увеличивается в 2 раза (2 вместо одного). Что это значит? шансы на победу увеличиваются в 2 раза!
BAR7: 1300
BAR30: 1600
1600
Pepegramming второй год подряд является информационным партнером конференции http://amp.gs/yXWI (ex railsclub). Это значит, что в этом году опять разыгрываем билеты.

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

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

Условия:

- Заполнить форму
- Рассказать друзьям
- 28 сентября в 18:00, с помощью рандома выберу победителя
BAR7: 1500
BAR30: 1900
1900
Ну а для тех, кто хочет поучиться на чужих ошибках - гитхаб репозиторий со списоком post-mortems разных компаний:

https://github.com/danluu/post-mortems
BAR2: 526
BAR3: 542
BAR7: 1200
BAR30: 1600
1600
Пятничное чтиво.

В далеком 2015 году, грезил дочитать SICP до конца, но к сожалению, с 3 раза дочитал только до главы об environments, frames и bindings. (3.2, если правильно помню). Для того что бы хоть как-то понять что это и зачем - решил написать интерпретатор scheme. В интернете нашел аналог на питоне и сделал подобное на руби.

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

Если вы застряли там же - надеюсь пост с примером реализации интерпретатора scheme сможет помочь понять тему лучше.

Write simple scheme interpreter on ruby
BAR2: 456
BAR3: 467
BAR7: 897
BAR30: 1200
1200
Люблю открытые компании. Чем больше опыта получишь не работая в компании - тем лучше. Политика открытости (даже если говорить только о техническую часть) помогает инженерам получить бесплатный опыт, а это сразу вес в комьюнити и хорошее отношение к компании со стороны. В этом плане gitlab персональный фаворит, так как плейбук натолкнул на кучу идей, а код платформы позволил найти решения  собственных проблем.

На днях, коллега поделился видео со внутренней презентации додо пиццы.

Стабильность Dodo IS

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

О том, как устроено IT в Додо Пицца

Понравилась диаграмма сервисов с описанием основного стека и напоминание, что компания - продуктовая и продукт можно и нужно потрогать:

> Надоело писать код – можешь сходить в пиццерию, покрутить додстеры или постоять на кассе.

Ну а если интересно посмотреть на процессы работы в ресторанном бизнесе (заказ пиццы) стоит почитать серию статей о работе информационной системы в додо:

Dodo IS. Часть III. Всё о заказе - Сила ума
BAR3: 761
BAR7: 932
BAR30: 1100
1100
В одной статье обратил внимание на упоминание the knowledge loop . Если кратко, то петля состоит из 3 элементов:

изучить -> создать -> поделиться

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

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

Из текущей работы:

* Data intensive applications и все что касается данных в продуктах. Год назад пришло осознание, что код это не важно, а бизнес логика - важно. Теперь пришел к тому, что данные и работа с данными > бизнес логика. Из-за этого, интересно как работать с данными, а так же как хранить и как обеспечить оптимальную эволюцию в проекте
* По работе отковыриваю сервис из монолита. Это первый шаг к сервисной архитектуре, в котором хочется получить как можно больше шишек. В планах написать статьи в блог как документацию к проекту
* Из-за полного контроля отковыривая сервиса нашел у себя много пробелов не технических умениях. Из-за этого приходится читать много книг связанных с soft skills, бизнесом и головой
* В качестве опыта, решил попробовать написать реальный продукт. Хочу начать глубже понимать тех, на кого работаю. Планирую закончить mvp и сделать приватную бету на https://rubyrussia.club. Об этом тоже напишу, но позже
BAR7: 807
BAR30: 1000
1000
В последние время очень много путешествий (26 часов из японии в москву чего стоят), поэтому пишу мало. Зато, если вы 10 числа будете в питере на конференции (https://www.meetup.com/saintprug/events/249120635/) - говорите привет. К тому же у меня есть ограниченное количество крутых наклеек :)
BAR7: 525
BAR30: 673
754
Написал о еще одном способе создания callable objects - Do notations из dry-monads. А так же, почему dry-transactions не вытягивают.

Medium
Telegraph
BAR1: 434
BAR2: 442
BAR3: 474
BAR7: 516
BAR30: 1100
1200
Хорошие статьи - редкость, а хорошие статьи по тестированию - двойная редкость.

13 антипаттернов тестирования. Сложно выделить один антипаттерн, который понравился. Поэтому советую прочитать о каждом отдельно.

http://blog.codepipes.com/testing/software-testing-antipatterns.html

Русский перевод: https://habr.com/post/358178/
BAR7: 610
BAR30: 1500
1500
Тут ребята из @saintprug выложили запись hanami воркшопа. Пара причин почему стоит посмотреть (советую на 1.25-1.5):
- посмотреть на то, как работает фулстек ханами
- реальные примермы DI и почему это работает
- в конце второй части были вопросы на большое количество тем (эвенты, dry, архитектура)
- можно написать на почту и получить ссылки 😉

Код на то, что вышло в итоге: https://github.com/saintprug/spb_link_shortener

А по вопросам - пишите в личку или в @saintprug

Первая часть: https://youtu.be/KnSPR-F2nag
Вторая часть: https://youtu.be/DCMTyddUvio
BAR7: 1100
BAR30: 1600
1700
йо!
По поводу последнего поста и планирования задач. У меня тоже адовый перегруз по задачам, поэтому я решил делать как делает Шон Бланк: 3 задачи которые сдеалют мой день успешным, 3 задачи которые сделают неделю успелшной + записываю мотивацию почему мне надо сделать именно эти задачи и что они принесут. 3 неделя пошла, в привычку ещё не вошло, но уже результаты есть небольше: проще стало немношк

http://macshifford.me/all-the-things-pro/ - тут чёта тоже написывал про это
BAR30: 1100
1200
Новая неделя (месяц) - новый текст, сегодня о не техническом но важном.

А что вы обычно делайте когда не прет?

Медиум
Телеграф
BAR30: 738
789
Решил собрать немного статистики, поэтому, если вам не сложно - пройдите пожалуйста опрос, 11 вопросов, которые помогут лучше понять на что обращать внимание в следующем проекте 🙂

https://goo.gl/forms/weQbVYOJGKpMmqG73
BAR7: 534
BAR30: 1200
1200
Стоит ли использовать еще одну платформу для текстов, кроме медиума?

Да, телеграф – 90
👍👍👍👍👍👍👍 49%

Нет, медиума хватит – 86
👍👍👍👍👍👍👍 47%

Да, свое (напишу @davydovanton лично) – 5
▫️ 3%

Да, яндекс дзен – 3
▫️ 2%

👥 184 people voted so far.
BAR7: 578
BAR30: 1200
1200
На прошлой неделе провел вокшоп в питере, спасибо ребятам из @saintprug за теплый прием. Поэтому сегодня - мысли и советы, как сделать что-то подобное. Хочется верить, что в будущем в россии будет все чаще и чаще встречаться такой формат (организаторы конференций - это ваш шанс 😉).

https://medium.com/pepegramming/workshop-adbe753f2df4
BAR30: 1100
1200
Привет, на улице наконец-то стало тепло, поэтому радостные новости. Я наконец-то переехал на medium. Теперь все посты будут выходить там.
В течении ближайшего времени я перевезу все тексты туда, так что подписывайтесь и рассказывайте друзям:
https://medium.com/pepegramming
BAR30: 835
904
#quality

Backlog Grooming - понятие из scrum, смысл которого в том, что команда собирается и решает что будет делать дальше и ставит эстимейты задачам. Проводится 1-2 раза в спринт в назначенное время. Но к сожалению, у нас, в какой-то момент возникли проблемы с PR:

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

Решение проблем оказалось банальным, появились “technical groomings” (название взято из головы, если вы знаете как этот процесс называется официально - пишите в личку). Смысл в том, чтобы позволить технической стороне обсудить формальный алгоритм задачи, разбить задачи на атомарные задачи и заэстимейтить каждую из задач.

Формальный алгоритм

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

Разбивка на атомарные задачи
Правила, которых стараюсь придерживаться:

- 1 задача == 1 RP
- Работающий код, потом рефакторинг

Также, планируйте рефакторинг и закрытие технических долгов либо перед началом работы, либо после. Если одна задача из списка блокирует другую - стоит задуматься и попробовать вынести то, что блокирует - в отдельную задачу. Яркий пример такой задачи: добавить эндпоинт для фронтенда. Минимум два варианта, так решить проблему:
- 1 большой PR в котором будет и логика и эндпоинт. Много кода и сложно ревьювить
- 2 PR-а. быстро сделать “пустой” эндпоинт для фронтенда, а потом потратить время на логику. Так разработчик разблокирует коллег, потом сделает остальную работу
BAR1: 500
BAR2: 505
BAR3: 505
BAR7: 577
BAR30: 866
886
Плюсы

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

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

Минусы

Главная проблема - трата времени на обсуждение задачи. Этого могут не понять менеджеры, которые считают “нет кода - нет работы”. Старайтесь говорить с менеджерами и объяснять смысл таких обсуждений.

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

И главное - груминг требует командной дисциплины.

Советы

- Ведите записи. А в конце задачи выделяйте время на обновление документации. Это поможет в поддержке документации к проекту
- Начните с культуры и помощи коллегам. Не везде практикуются подобные обсуждения. Хотите исправить это - подойдите и предложите поговорить о задаче коллеги. После чего попросите помощи сами
- Один груминг - одна тема. Также, желательно ограничивать обсуждения по времени и количеству участников. Не тащите команду, хватит только тех, кто будет работать над задачей
- Делайте груминги по необходимости. Не тратьте время коллег в пустую

Запомнить

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

Ссылки
- MindNode со всеми идеями
- Product Backlog Grooming Best Practices
- Версия для покета
BAR1: 475
BAR2: 483
BAR3: 483
BAR7: 579
BAR30: 1200
1300
и ссылкой в браузер
https://my.mindnode.com/SfeToxQtx9dv2b2n8scQq6N7HqxWPAhzSTJweLBW
BAR1: 315
BAR2: 357
BAR3: 383
BAR7: 474
BAR30: 896
939
и майдмап для лучшего запоминания
BAR1: 327
BAR2: 369
BAR3: 396
BAR7: 481
BAR30: 836
881
ссылка для покета:
https://gist.github.com/davydovanton/bb504c423e958470ca639dbc086ad2dc
BAR1: 328
BAR2: 367
BAR3: 393
BAR7: 476
BAR30: 751
794
В программировании много абстракций, которые кажутся сложными на первый взгляд, но после практики становятся понятнее. Например - монады.

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

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

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

* Объяснение функторов и монад в картинках
* Объяснение в HaskellWiki
* A Fistful of Monads - Learn You a Haskell for Great Good!


Код

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

response = http.get(url, params)
if response[:status] == :success
user_repository.create(response[:body])
end


Пример не выглядит сложным, но с бизнес логикой - вложенность выходит из под контроля:

response = http.get(url, params)
if response[:status] == :success
validation_result = validator.call(response[:body])

if validation_result.valid?
if user = user_repository.create(response[:body])
NotificationWorker.perform_async(user.id)
end
else
validation_result.errors
end
else
response
end


Вариант с гардами мне показался сложнее для восприятия

Вспоминая railway programming, было бы здорово переписать наш пример с использованием последовательных шагов:

step :get_response # returns response or Failed result
step :validate # returns payload or error message
step :persist # returns user or nothing
step :notify # calls worker with user id


В случаях, когда данные из прошлого шага влияют на последовательность логики, приходят на помощь монады. Важно запомнить, что монада - объект с общим интерфейсом, в котором лежит значение. Ближайшая абстракция - коробка. В коробке лежит все, что поместиться. При этом, не открыв коробку - значение не получить. Коробки - разные, большие, маленькие, цветные, но каждая коробка открывается одинаково - просто подними крышку и посмотри что там.
BAR1: 387
BAR2: 419
BAR3: 438
BAR7: 515
BAR30: 746
781
Монада - инструмент, который позволяет создавать цепочки вызовов функций или методов без лишних проверок данных, которые возвращаются в предыдущем шаге. Монад много, но рассмотрим только популярные - Maybe, Result и Try.

* Maybe - оборачивает значение в Some или возвращает None объект без значения.

* Result - оборачивает значение в Success или Failure.

* Try - оборачивает вызов кода в Result если не было эксепшенов и в Error, если код упал с ошибкой (которая ловится)

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

* fmap - выполняет блок, если значение монады соответствует Success варианту, а результат выполнения блока оборачивает в ту же монаду, у которой он вызвался. Например:

Some(1).fmap(&:to_s) # => Some(1)
None().fmap(&:to_s) # => Nothing


* bind - аналогичен fmap, только возвращается результат выполнения блока:

Some(1).bind(&:to_s) # => 1
Some(1).bind { |value| Success(value) } # => Success(1)
None().bind(&:to_s) # => Nothing


В руби нет монад из коробки, но существуют гемы, которые реализуют монады:

* dry-monads
* kleisli
* tomstuart/monads

Советую dry, как единственную поддерживаемую. К тому же, при использовании dry-validation можно легко конвертировать результат валидации в монаду, воспользовавшись экстеншеном:

Dry::Validation.load_extensions(:monads)


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

http.get(url, params) # теперь клиент возвращается Result Monad
# валидация возвращает Result, который используется для следующих вызовов
.bind { |body| validator.call(body).to_result }
# сохраняем в базу, если валидация вернула Success
.bind { |payload| Maybe(user_repository.create(payload)) }
# вызываем воркер, если сохранение вернет Some
.fmap { |user| NotificationWorker.perform_async(user.id) }


Кроме использования монад в бизнес логике, попробуйте эту абстракцию для обработки результата, который возвращается из бизнес логики. Как пример - вызов operation из экшена и последующая обработка результата в этом же экшене: cookie_box/show.rb

Что делать с результатом

При использовании dry-monads можно:
- вызывать на прямую success?, failed? или value_or
- использовать "dry-matcher"
- мой любимый вариант, использовать "case"

Минусы

1. В отличии от условий (if, unless, etc) нельзя просто взять и использовать монаду. Если не знать в чем смысл абстракции и что значат bind и fmap - будет сложно понять код, который написан
2. Использование монад может сильно усложнить код. Спасает опыт, а опыт получается в практике
3. Если хотите начать использовать монады в проекте, придется прорваться через ужас в глазах коллег (причина почему я написал этот текст)

Запомнить

* Монады - абстракция для чейна вызовов функций и следованию railway programming
* Для использования монад не нужно математическое образование. Главное понять, что монада оборачивает данные в объекты с единым интерфейсом
* Советую начать с - Maybe, Result и Try
* fmap и bind - методы для чейна вызовов функций
* Чрезмерное использование монад усложняет код, будьте осторожны и подходите к написанию кода с умом

Полезное

* Как рефакторить руби код с монадами
* Algebraic Data Types & Monads in Ruby
* Monads and Ruby
* Railway Oriented Programming
BAR1: 379
BAR2: 426
BAR3: 452
BAR7: 553
BAR30: 831
877
@shiroginne поделился подробной воскресной статьей о вещах, которые стоит помнить во время ревью:
https://medium.com/@palantir/code-review-best-practices-19e02780015f

А @alexsubbotin поделился CONTRIBUTING.md файлом, дополненым после текста выше:
https://gist.github.com/KELiON/45cae7ac0eeeaa2a097116396c94b610
BAR1: 521
BAR2: 565
BAR3: 594
BAR7: 642
BAR30: 943
968
А каких правил вы придерживаетесь в ревью и на что смотрите в первую очередь? (обратная связь тут - @davydovanton)
BAR2: 454
BAR3: 457
BAR7: 823
BAR30: 1000
1100
А так же, версия для покета: https://medium.com/@anton_davydov/pepegramming-ревью-кода-e82794a8f05e
BAR3: 477
BAR7: 784
BAR30: 994
1100
Персональные выводы

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

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

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

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

Для последнего шага ревью необходима внимательность, но с этим возникают проблемы у отдельных людей (ADHD напрмиер). При этом, базовые проверки, таких как стиль, грамматика и опечатки автоматизируются с помощью код стайла с rubocop, danger и codeclimate, который показывает, какие части пулл реквеста не покрыты тестами.

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

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

# Запомнить

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

# Полезное

- 11 советов, как улучшить ревью от IBM
- Еще советы, на этот раз от asana
- И еще советы
- Посмотрите, как Лука пишет описания к ПР-ам в ханами, у него есть чему научиться
BAR3: 554
BAR7: 751
BAR30: 955
1000
#quality

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

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

Понимание задачи

Начните с главного, понимания задачи, которую пытается решить разработчик. Важно: поймите бизнес требование, а не текущую реализацию. Проверьте, разбиваются изменения на 2 и больше пулл реквеста или нет. Если сложно - попросите коллегу о помощи или подробном описании того, зачем изменения нужны. На этом этапе определяется насколько сложную и значимую задачу решал разработчик, а ревьюверы погружается в контекст проблемы. Правило, которого стараюсь придерживаться: 1 пулл реквест == 1 атомарная задача, которую просто понять и просто объяснить на каждом из уровней абстракции.

Проверка, что задача выполнена

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

Проверка архитектуры и способа решения

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

Проверка кода и грамматики

Последний шаг - скрупулезная проверка кода. Тут проверяется нейминг, стилистические особенности, проверяется перформанс.

Подитожив, можно увидеть такую последовательность:


Понимание задачи -> проверка, что задача выполнена -> проверка архитектуры и способа решения -> проверка кода и грамматики
BAR3: 586
BAR7: 665
BAR30: 958
1000
Конкурс завершен!
В течение недели вы писали свои истории о проблемах, с которыми приходится сталкиваться в работе https://github.com/moscowrb/organisation/issues/3. Спасибо всем, кто поделился наболевшим и рассказал о своей проблеме.
Наибольшее количество лайков собрал рассказ Nikolay Shebanov (https://github.com/killthekitten). Николай получает бесплатный билет на RailsClub 2017. Поздравляем!
На 2 и 3 месте соответственно оказались Кирилл (https://github.com/mephody-bro) и domenic99 (https://github.com/domenic99). Пожалуйста, напишите мне в личку @davydovanton, чтобы забрать свой сувенир из Японии.
1600
Ребята из RailsClub из года в год делают самую крупную Ruby-конференцию в России с иностранными спикерами. В этом году ожидаются выступления авторов dry, rom, Hanami и Trailblaizer, а также крутых разработчиков со всей страны.

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

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

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

Награда
Человек с наибольшим количеством 👍 получит бесплатный входной билет на конференцию RailsClub 2017, которая состоится 23 сентября в Москве.
Обладателям второго и третьего мест я привезу сувениры из Японии.

Условия
Конкурс завершается 18 сентября. Каждый участник может отправить неограниченное количество историй. Флуд и спам будут удаляться.

Полезное
- Напишите вашу историю как можно быстрее — так у вас будет больше шансов собрать максимальное количество голосов
- Почитайте пост о том, почему конференции — это круто и что вы можете получить от них помимо докладов
- И еще один старый пост — про то, что делать до, во время и после конференциии
2000
Благодаря трекингу времени, проведенного за компьютером, обнаружил, что в последний месяц, трачу половину дня на соцсети и месенджеры. Из-за этого я захотел провести экспиремент и не пользоваться меcсенджерами (кроме рабочего слака) и социальными сетями на 7 дней.

Поэтому, к сожалению, в канале будет перерыв на эту неделю. А пока можно вспомнить старые сообщения или задать вопросы. А также прочитать пост Андрея Ситника о цифровом шаббате.
1300
#закладки №1

Статьи

* www.blackbytes.info/2017/08/how-does-sinatra-work
Статья о том, как работает Sinatra и что происходит, когда в коде появляется require sinatra. Если хотите прокачаться, в процессе чтения попробуйте написать свою собственную реализацию этого фреймворка с таким же синтаксисом.

* jakeyesbeck.com/2016/03/13/the-power-of-arel
Arel — библиотека, которая вызывает либо отвращение, либо отвращение. Я не знаю ни одного человека, которому бы нравился код, написанный на ней. Так как Arel — low level библиотека для работы Active Record, в коде иногда приходится использовать этот гем. Обычно найти нормальную документацию на эту библиотеку сложно, но статья по ссылке хороша тем, что содержит примеры селектов, джойнов и сложных выборок.

* nicksda.apotomo.de/2011/07/are-class-methods-evil/
* andrzejonsoftware.blogspot.ru/2011/07/yes-nick-class-methods-are-evil.html
Я не фанат методов класса. В коде стараюсь использовать такие методы только по необходимости, либо для создания фабрик и других инициализаторов. В этих двух статьях на примерах рассказано о том, почему не стоит использовать методы классов. Советую также почитать комментарии — там много интересной информации.

* robots.thoughtbot.com/rebuilding-git-in-ruby
Лонгрид о том, как написать git на чистом Ruby. Постарайтесь не просто прочитать статью, но и написать код самостоятельно, без копипаста. Потом запустите программу и проверьте, что всё работает корректно.

* stillflowing.net/2014/12/21/an-experience-in-contributing-to-open-source
Автор рассказывает, почему не надо заниматься опенсорсом ради опенсорса. Ключевая идея: лучше просто пишите код, и во время этого процесса вы найдете проблему, которую можно решить с помощью Open Source.


Репозитории

* reqres-api/reqres_rspec
Интересное решение для того, чтобы генерировать документацию из тестов. Я не использовал эту библиотеку, но планирую испытать ее в деле с Hanami и dry-web приложениями. К сожалению, у библиотеки нет тестов и непонятно, будет ли гем работать с нерельсовыми проектами. Поэтому, если у вас есть время и желание помочь, велкам.

* donnemartin/system-design-primer
Материал о том, как работают разные части веб-приложений. Это популярный текст, который не раз попадал в рассылки или подкасты. У репозитория с этим текстом — 16 тысяч звезд, хотя в нём лежит довольно разрозненная информация. Есть ссылка на русский перевод, который можно дополнить, если есть желание. Вот вам готовая идея для PR: просто дополните гайд и помогите другим разработчикам.

* muan/dashboard
Расширение для Chrome, которое фильтрует информацию на главной странице Github. Скажу честно, мне не нравится Github feed и я раздумывал написать приложение, которое исправило бы эту ситуацию. Но плагин решает проблему: отфильтрованный фид выглядит намного информативнее.


Опенсорс

* slim-template/language-slim/issues/25
Автор Slim ищет помощников. Хотите помочь 10 миллионам человек (на самом деле это количество скачиваний гема)? Есть свободные пара часов в неделю? Напишите автору и предложите помощь. А если сомневаетесь — я уже писал, почему Open Source — это круто (https://t.me/pepegramming/43).

* hanami/events/issues
Если знаете, почему важен event sourcing, хотите прокачаться в асинхронщине и работе с Kafka, Postgres, Redis и другими крутыми штуками — велкам. По ссылке — много открытых ишью, которые ждут своих героев.
1500
Недавно нашел статью (https://m.habrahabr.ru/post/158011/, оригинал: http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/) про паттерны для моделей в Rails от 2012 года. Подскажи, насколько эти паттерны актуальны и часто ли их приходится применять на практике. Заранее спасибо!

Я считаю, что эти паттерны актуальны даже сейчас. Если присмотреться, они об одном и том же: разделяй логику на изолированные объекты и радуйся жизни. Конечно, можно не следовать паттернам, но необходимо задавать самому себе вопрос: «А действительно ли код, который я написал, должен быть в этом месте, или нет?».

Получается, рельсовые параметры нам всё равно нужно постоянно пермитить? (вопрос по последнему примеру)

Мне не приходилось таким заниматься, но думаю, ответ легко найти в интернете. Например, на SO описывается один из вариантов, как отключить параметры:
https://stackoverflow.com/questions/18092475/in-rails-4-disable-strong-parameters-by-default

Думал, что "Dry::Validation.Schema" на выходе будет выкидывать все параметры, которые не описаны в схеме, это возможно? Просто получается, что если в запросе будет куча лишнего хлама, и описанные параметры проходят валидацию, то лишние параметры тоже остаются, и приходится их самому подчищать, иначе при попытке сохранить запись будет эксепшен, что переданы дополнительные параметры, о которых модель не в курсе, и запись не сохранится.

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


schema = Dry::Validation.Form do
required(:email).filled(:str?)
required(:age).maybe(:int?, gt?: 18)
end

schema.call(email => jane@doe.org, age => )
# => #<Dry::Validation::Result output={:email=>"jane@doe.org", :age=>nil} errors={}>

schema.call(email => jane@doe.org, age => , firstname => anton)
# => #<Dry::Validation::Result output={:email=>"jane@doe.org", :age=>nil} errors={}>
1100
Я люблю экшены в Hanami и сегодня расскажу, почему.

После рельсы и синатры разработчики привыкли, что экшены являются методом класса или чем-то похожим. Главное, что они — в одном классе.

У такого подхода есть плюсы:
- каждый экшен в одном месте, не надо «прыгать» между файлами
- легко представить экшен как один класс и инкапсулировать его в голове.

Но существуют и минусы:
- если экшены большие, то куча кода в одном месте превращается в хаос
- появится код, который будет общим для 1+ экшена (например, callback), что увеличивает связанность экшенов между собой
- такие экшены сложно тестировать. Нельзя просто взять и явно вызвать метод, для этого нужны интеграционные тесты
- permit params из Rails шарится на каждый экшен в классе. Это доставляет трудности, если нужно предоставлять разные параметры.

Тут в игру врывается Hanami, который переворачивает такой подход с ног на голову. Этот фреймворк утверждает обратное: каждый экшен — изолированный класс с единственным публичным методом #call. Но если задуматься, то получается, что мы работаем не с контроллером, а с отдельным экшеном. Поэтому логично изолировать не контроллеры между собой, а экшены.

Выглядит это следующим образом:


module Web::Controllers::Home
class Index
include Web::Action

def call(params)
# your action code here
end
end
end


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


Web::Controllers::Home::Index.new.call({ ... })


Этот подход добавляет гибкости при тестировании. Теперь можно писать не только интеграционные, но и юнит-тесты. А если у экшена есть сложная для тестирования зависимость в коде, то Hanami позволяет использовать DI вместо моков:


module Web::Controllers::Home
class Index
include Web::Action

def initialize(repo: UserRepository.new)
@repo = repo
end

def call(params)
# your action code here
end
end
end

action = Web::Controllers::Home::Index.new(repo: EmptyRepository.new)


Кроме того, экшен предоставляет валидацию для работы с параметрами. Валидация основана на dry-validation, что позволяет вынести логику из модели. В результате модель получается «тоньше». Условные валидации пропадают как костыль, потому что валидируются только указанные в каждом экшене параметры.
1000
Но и как у любой технологии, у экшенов Hanami есть минусы.

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

Много файлов
Это палка о двух концах. Пока в системе маленькие экшены на 1-3 строчки кода, легче смотреть весь контроллер целиком — и тут будет удобен подход из Rails. Но когда экшены растут и сложность увеличивается, помогут идеи, заложенные в Hanami. Изолированный экшен позволяет разработчику сфокусироваться только над ним одним, а не над контроллером в целом. Поэтому если у вас будет приложение с простым CRUD без излишеств, рассчитывайте, что разом на весь контроллер вы вряд ли посмотрите.

Чем это полезно разработчикам, которые не будут использовать Hanami

Как я неоднократно говорил, Hanami интересен идеями, которые лежат в его основе. Например, фреймворк помогает задуматься, правильно ли валидировать данные в модели и создавать огромные контроллер-классы.

Запомнить
- В мире Ruby существует устоявшееся «правило», как должны выглядеть контроллеры.
- Hanami предлагает концептуально новый подход к написанию экшенов.
- Этот подход не является «серебряной пулей». Он решает только определенные проблемы.
- Если вы не планируете использовать Hanami, можете просто вдохновиться идеями из этого фреймворка.

Ссылки
- Документация на экшены в hanami
1100
Доброго времени, читаю канал, но интересно, почему не используется телеграф(telegraph.ph) для хранения статей? Интересно узнать ваше мнение

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

Оргвопросы

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

Также появилась идея раз в неделю делиться ссылками на интересные посты. Что думаете?
1100
Я уже писал о dry-transaction. На работе мы начали использовать эту библиотеку в оперейшенах. Это такие сервис объекты, которые вызываются из транспорта (http, stream) и выполняют код завязанный на бизнес логику. Это может быть как просто манипуляция с бд (достать данные, сохранить данные), так и действительно сложная логика. Например процессинг платежа. Текущее решение содержит в себе много магии и поэтому было решено начать использовать dry-transactions как основной каркас для построения оперейшенов.

Поэтому сегодня две ссылки.

Пример использования такого оперейшена в rails экшене:
https://gist.github.com/davydovanton/ec99546c3eb512599b65e5b27fe78bb0

Старая ссылка с примером в ханами:
https://gist.github.com/davydovanton/0a9e9dcaef75582e3c2fe9b4392b61d9
1300
Как найти задачи
Я знаю четыре способа, которые могут помочь:

1. Использовать технологию, в которую хотите начать писать. Самый простой вариант.
Вы пишете проект на hanami, dry-web, rails или используете любую другую технологию. Видите проблемы, на решение которых нужно потратить время, и исправляете их, обновляете документацию или пишете новую библиотеку. Как пример: работая с rom, мне было сложно понять ассоциации между таблицами, поэтому я написал простой инструмент, который генерирует картинку с этой информацией.

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

3. Воспользоваться агрегаторами тасков. В интернете можно найти много сервисов со списком осс-задач (1, 2). Я сам написал такой. Проблема в том, что вам как новичку сложно будет понять, что и как нужно сделать. Поэтому я не фанат такого варианта.

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

Что можно делать, кроме кода

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

Советы

1. Лучше час каждый день, чем 5 часов один раз в неделю. За час можно многое успеть и получить много ❤️ от других людей. Регулярность важнее количества.
2. Не идеализируйте. Опенсорс — это прежде всего помощь другим, а не хардкорные таски. Порой важнее поправить сайт проекта, чем написать невероятно сложную и быструю систему.
3. Не отчаивайтесь. Все мы люди, все мы ошибаемся. У меня был пулл-реквест в Rails с 80 комментариями, который я не смог закончить. Такие ситуации нормальны. Не сдавайтесь, потому что все сообщество готово вам помочь.
4. Отдыхайте и не делайте через силу. Если чувствуете, что не идет — забейте. Хуже от этого никому не будет. Если чувствуете, что не можете доделать задачу — скажите это другим людям. Вам помогут и никто не обидится. Например, не так давно я попросил помощи у Луки (Luca...) с тестами, потому что я не знал, как их поправить, и он мне помог.

Запомнить

- Опенсорс — такая же работа, с такими же людьми. Не думайте, что она для избранных или исключительно для профи. Это под силу каждому.
- Опенсорс — это не только про код, но и про общение. Не обязательно писать код, чтобы помочь.
- Не заставляйте себя, пользы от этого никому не будет.
- Не нервничайте и не сдавайтесь. Будьте вежливы и дружелюбны, и вам понравится!
1600
«Как начать писать в opensource?»
Кажется, такой вопрос задавал себе каждый разработчик, в том числе и я сам. Сегодня мне хотелось бы поделиться опытом и советами для всем, кому интересна эта тема.

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

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

Прокачивайтесь как разработчик
Опенсорс-проектов много. Это значит, что найти задачу по душе не составит труда. Понравился elixir — найдите проект на нем и попробуйте помочь. Хотите прокачаться в асинхронном программировании — откройте гитхаб и найдите интересный репозиторий.

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

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

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

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

Я уже говорил, что опенсорс — такая же работа, как и та, за которую платят деньги. На нее нужны силы и время. Поэтому первое, что нужно сделать, чтобы начать писать в опенсорс — ответить самому себе на вопрос, зачем это нужно лично вам. Не стесняйтесь себя и отвечайте честно, потому что причин может быть несколько, и они могут быть даже эгоистичными. Подумайте, действительно ли вы готовы пожертвовать своим временем и силами ради этого, и если да, то ищите задачи.
1200
и немного опыта моего коллеги, который будет полезен, если вы захотите использовать контейнеры
1300
DI containers

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

Какие проблемы решает DI container:

* Зависимости находятся в одном месте. Не нужно писать пачку файлов в config/initializes/*, а потом пытаться контролировать флоу загрузки зависимостей.
* Каждую зависимость достаточно инициализировать один раз. Если нужна динамическая инициализация — не проблема, библиотеки это поддерживают.
* Не нужно держать конфигурации зависимостей в одно месте. Можно легко выделять конфиги в разные части приложения.

В руби есть библиотеки, которые реализуют подобный функционал:

* dry-containers
* micon
* encase
* dim
* hanami-components

Если ничего не понравилось — велосипед займет меньше 100 строк кода. Но я отдаю предпочтение dry-containers, и вот почему:

* Можно использовать класс или инстанс контейнер.
* Легко пишется кастомный регистратор и резолвер зависимостей контейнера.
* Register options.
* Поддерживаются стабы.

Но у контейнеров можно найти минусы:
* Появляется глобальная переменная, которая ведет себя как синглтон. Это создает глобал стейт, поэтому будьте аккуратны.
* Может возникнуть соблазн создать мега-контейнер с множеством излишних зависимостей. Это принесет много проблем и негативно отразится на производительности.
* Придется писать конструктор в каждом сервисе/объекте, в который будет передаваться DI container.
* Если есть куча сервисов, которые резолвятся в контейнере, придется писать много кода.
* Что делать, если понадобится использовать DI и DI containers сразу в одном коде?

Хочется обратить внимание на последние 3 пункта. Это проблемы, которые не решаются через контейнер. Поэтому придется говнокодить. Например, так:

class Service
def initialize(twitter: Container[twitter])
@twitter = twitter
end
end


А для автоматической регистрации сервисов придется писать сложный код с require в интеракторе.
1200
Ребята из dry-org подумали о разработчиках и сделали две библиотеки, которые решают эти проблемы: dry-auto_inject и dry-system).

dry-auto_inject нужен для того, чтобы легко и просто инжектить зависимости в объекты:
* Библиотека предоставляет сахар для инжектинга зависимостей из контейнера.
* Заинжекченные зависимости также инжектятся через классический DI.
* Работает с любыми контейнерами. Я проверял с ханами-контейнером и с обычным руби хешем.

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

Примеры:

* Все части ханами загружаются в DI контейнер, который уже резолвит что и как загружать.
* Пост из icelab о том, как правильно использовать DI.
* Пример блога на dry-web, можно посмотреть на DI containers в деле

Tips:
Контейнер хорошо подходит для реализации фабрик. Можно создать класс, который будет загружать в память и возвращать только указанный объект. Именно так работает выбор адаптеров в hanami-events.

Links:
* Пост великолепного Jim Weirich, который поможет разобраться в теме
* Не путайте IoC и DI containers. Это разные вещи
* Статья, которая описывает когда лучше использовать DI containers
1300
Я уже писал об использовании dependency injection в ruby. Но как и у всех подходов, у DI существуют свои минусы.

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

Используя DI, придется каждый раз прокидывать один и тот же инстанс логгера в каждый объект. Это утомительно и заставляет писать много кода.

Сложная и дорогостоящая инициализация
Например: для инициализации клиента Amazon приходится писать много кода.

В случае с DI понадобится каждый раз создавать ресурсозатратный инстанс или использовать константу, которая объявленна где-то в коде.

Много кода
Например: сервис, которому нужен твиттер-клиент, логгер, репозиторий и еще пара зависимостей. Создается инициализатор с кучей переменных, а это уже code smell.

class MyObject
def initialize(repo:, twitter:, logger:, mailer: ,...)
end
end


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

Перечисленные проблемы заставляют задуматься об использовании DI в проекте. Но есть решение, которое позволяет контролировать зависимости.
1200
Простите, ссылка на использование AR::Validation вне модели вела не на тот пост, вот правильный:
https://blog.ragnarson.com/2016/10/26/validation-outside-activemodel.html
1400
Запомнить
- Rails way не панацея. Старайтесь думать, когда полезно его придерживаться, а когда — нет.
- Валидации и модель — разные вещи. Вынос валидаций в контроллер может сильно облегчить жизнь и процесс тестирования.
- У выноса валидаций есть минусы, выбирайте осознанно.

Интересное
- Валидация разных параметров в пользовательском приложении и в приложеини администрирования на примере hanami
- Пример большой валидации в моделе гитлаба

Почитать
- Hanami — отличный пример, когда вынос валидации из модели работает как надо.
- Такой же подход пропагандирует трейлблейзер.
- Облегчаем жизнь монадами.
- Как использовать AR::Validation вне модели.
- Используем dry-validation в rails приложении.
1500
Сегодня поговорим про валидации. Я не фанат rails way подхода, и вот почему.

На мой взгляд, главные проблемы заключаются в следующем:

1. Модель вмещает в себя много логики. Это мешает в тестах, а также увеличивает связанность между частями системы.
2. В одном файле описывается схема для всех возможных вызовов в коде. Получается гибрид с кучей кондишен-условий (привет if: :paidwithcard?)
3. Если говорить о rails, то заметно дублирование логики. Контроллер проверяет ключи (permit params), а модель проверяет значение ключей при сохранении.

Это ведет к сложностям и затратам усилий на борьбу с фреймворком вместо решения бизнес-задач.

Как с этим жить?

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

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

Получить данные → Провалидировать → Сохранить валидные данные в базу


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

Плюсы такого подхода:
- Схемы валидаций специфичны только для конкретного случая, поэтому не нужно думать о реализации, которая покроет все случаи.
- Легко тестировать. Тестируется только схема, а с помощью DI она пробрасывается в код. Такой подход позволит проще тестировать объекты, так как не нужно заморачиваться по поводу валидных данных в тестах.
- Модель не реализует логику валидирования, следовательно, уменьшается в размерах. Так проще найти нужную валидацию для определенного случая, не нужно разбираться, в каком случае кондишен валидации сработает, а в каком — нет.

Минусы:
- Неканоничный rails way. Новым разработчиками придется понимать, почему было сделано так, а не иначе.
- Появляется новая абстракция. Не имею ничего против этого, но абстракции текут.

Как это сделать в Ruby?

Я знаю три библиотеки, которые предоставляют валидированию данных:
- dry-validation
- ActiveModel::Validations
- hash_validator gem

Используйте любую, но я отдаю предпочтение dry-validation. Это гибкая библиотека, которая предоставляет удобный DSL для кастомных матчеров и проверяет опциональные поля. У нее также есть гайд о сравнении с AR::Validatoin. Эта библиотека используется в hanami, trailblazer и других гемах. Чтобы начать с ней работать, достаточно прочитать гайды.
1400
Я сделал простой проект, который поможет легко и быстро найти застаренный гитхаб-репозиторий. Поиск похож на таковой по полям в гитхабе.

Задача

Вместо множества полей и перегрузки интерфейса было решено сделать единственное поле для поиска. Такой поиск сделал гитхаб. Строка is:open is:issue позволяет получить список открытых issue. Мне захотелось сделать подобное и в своем проекте.

Реализация

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

1. Поиск в базе по ключам
2. Парсинг строки для созданием ключей поиска
3. Валидация ключей

Поиск по ключам

Поиск по ключам состоит из главного релейшена, который пробрасывается через методы для поиска. Каждый метод принимает query в виде релейшена и значение ключа для поиска и возвращает новый query-объект. В виде кода это выглядит следующим образом:

def find_by_account(account_id, search = {}, limit = 100)
query = projects.where(account_id: account_id)
query = text_search(query, search[:text])
# ...

query.order{ starred_at.desc }.limit(limit).as(Project).to_a
end

def text_search(query, text)
return query if text.nil?

text = pattern(text)
query.where { name.ilike(text) | description.ilike(text) }
end


Парсинг строки

Мне не хотелось заморачиваться с парсерами, поэтому выбор пал на стандартную библиотеку strscan. StringScanner посимвольно проходит по строке. Результатом выполнения метода будет либо совпадение, либо nil. В документации много подробных примеров. Хотелось бы добавить, что создание токенов в виде регулярных выражений и сканирование строки по этим токенам может сильно упростить логику и повысить читаемость кода:

require strscan
OPTION_TOKEN = /\w+:\w+/

StringScanner.new(command:test).scan(OPTION_TOKEN)
# => "command:test"
StringScanner.new(other text).scan(OPTION_TOKEN)
# => nil


Полный код доступен в репозитории. Парсер возвращает хеш вида { search_key => value }, который валидируется, а потом передается в репозиторий.

Валидация ключей

Следующая проблема: как провалидировать параметры поиска? Хочется закрыть xss-уязвимость, а также для улучшения UX показать, что пользователь ввел неправильные данные. Для этого я написал сервис валидации и проверки параметров. Сервис знает допустимые ключи поиска и удаляет невалидные символы.

Что можно имправить

1. Главный экшен. Стоит вынести валидацию в отдельный сервис, а поиск в интерактор, который будет вызывать валидацию и метод репозитория.
2. Поиск в репозитории. Метод содержит много логики. Вынос логики в отдельный класс упростит логику и поможет в тестировании.
3. Поиск в postgresql. Я люблю постгрес, в нем отличный поиск. Но возможно, вариант с эластиком будет проще и быстрее.

Запомнить

1. Если нужен простой поиск, а за SaaS платить не хочется — стоит подумать, может, проще написать велосипед.
2. StringScanner — рабочая библиотека, которая поможет сохранить силы и время.
3. Использование больше одного поля для поиска усложняет UX и код.

Ссылки

* Блог пост о том, как парсить текст в руби
1500
Спасибо всем за вопросы! Приятно видеть ваш интерес к постам. Надеюсь, что в будущем фидбека будет еще больше :)

> Привет! Вижу, ты часто пишешь про Dependency Inversion, и поэтому хотел бы спросить: в чем для тебя принципиальная разница между di и паттерном strategy? Спрашиваю, т.к., на мой взгляд, разница между определениями в Ruby несколько размыта.

Мне нравится ответ SO на такой же вопрос.

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

В случае паттерна strategy вероятность передачи разных объектов выше. Например, использование разных форматов данных (http, pdf, xml, etc) в одном рантайме.

> А как ты для себя решаешь, когда использовать service object, а когда interactor?

Функциональные объекты похожи между собой. Различие в деталях — и иногда эти детали важны, а иногда — легко опускаются.

Немного теории: сервисы — объекты, которые принимают и возвращают данные. У таких объектов нет возвращаемого стейта, а для разработчика это выглядит как функция y = f(x). Неважно, вернется success или failed, главное — получить результат.

Интерактор — другое. Это тот же сервис, но вместо данных возвращается еще и стейт кода. Можно легко сделать «интерактор» из ~~говна и палок~~ подручных средств. Для этого достаточно просто возвращать хеш со статусом кода и данными:

class Service
def call(payload)
validation = UserSchema.call(payload)

if validation.success?
user = UserRepository.new.create(payload)
{ success?: ture, user: user }
else
{ success?: false, errors: validation.errors }
end
end
end

result = Service.new.call(name: Anton)
result[:success?] # => true
result[:user] # => #<User:xxx >

result = Service.new.call(name: nil)
result[:success?] # => false
result[:errors] # => { name: [should be not empty] }


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

Возникает логичный вопрос: в чем различие между оперейшеном, интерактором и сервисом? Об этом поговорим в следующий раз :)
1500
Организационные моменты

1. Чтобы было проще искать конкретные сообщения и понимать взаимосвязь некоторых тем, я добавил оглавление. Там же есть ссылка на mindmap по функциональным объектам.
http://telegra.ph/Pepegramming-Contents-07-16

2. Появилась форма обратной связи. Ответы на вопрсы — хороший способ глубже понять тему как вам, так и мне. Я считаю, что не бывает глупых вопросов — они все важны. Поэтому на любой фидбек я отвечу в течение пары дней. Если вам хочется что-то спросить или посоветовать, воспользуйтесь анонимной формой или просто напишите мне в личку (@davydovanton).
1500
Сегодня я расскажу о фиче ханами, над которой работаю сейчас и которую хотел бы видеть в следующей версии (1.1).

Для начала — теория. В ханами контейнерная архитектура. Это значит, что проект на ханами состоит из набора приложений. Разработчик волен выбирать сам, как называть приложения. Например: web, api, admin. Или доменные приложения (account, cart, posts, etc). Каждое из них — набор контроллеров и средств представления данных. Например, вью объекты + темплейты, или же сериализаторы для API. Эти приложения полностью изолированы и загружаются в память при старте сервера.

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

1. Запуск бэкграунд-процессинга, например, sidekiq, без приложений. Это нужно, чтобы не загружать в память ненужный код, который не будет выполняться.
2. Если существует web-приложение, на которое приходится большая часть нагрузки, можно легко заскейлиться. Поднимите кластер серверов только с web-приложением, опять же, не загружая в память лишнего.
3. Если необходимо защитить админки, это можно легко сделать, запустив конкретное приложение в приватной сети. При этом саму админку в открытой сети можно не запускать. В этом случае злоумышленник не сможет взломать auth и узнать эндпоинты админских приложений.
4. Кейс повышенной сложности: если есть главное приложение и куча админок или внутренних приложений, не нужно дублировать бизнес логику или модель данных. Просто поднимите внутренние сервера и на каждом запустите сервер с нужным приложением.

Последний пункт объясню подробнее. Много раз видел, как создают больше одного приложения с общей базой. На предыдущей работе было 3 приложения с одной базой и одинаковыми моделями, которые надо было как-то поддерживать. Каждый раз возникали одни и те же проблемы: начиная от копирования модели и кучи логики, связанной с доменной областью, заканчивая одинаковыми патчами 2+ проектов, которые надо сделать и проверить. Конечно, один API-сервер решает часть проблем, но в моем случае это не работало.

Аналогичный функционал существует в dry-web. Его я использую в своей работе. К сожалению, я не знаю других руби-фреймворков, которые позволяют делать подобные вещи. Если вы знаете другие примеры — расскажите об этом. Для заинтересовавшихся — ишью на гитхабе: https://github.com/hanami/hanami/issues/778
1500
Я работаю в американском healthcare стартапе. Медицина в Штатах отличается тем, что там много проверенных решений.

Каждый житель, имеющий страховку, приписан к определенной аптеке. Большинство лекарств доступно только по рецепту, и покупать их можно только в указанной в рецепте аптеке. Если владелец страховки захочет сменить аптеку, нужно предупредить новую аптеку, чтобы та получила его данные. Туда должен быть отправлен факс вида: «One of our members would like to transfer a prescription to your pharmacy» с полными данными этого пользователя.

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

Во-первых, для факсов существует специальный API у twilio. Есть и другие API, но twilio уже используется в нашем приложении. В документации говорится — чтобы послать факс, необходимо знать 3 вещи:
* телефон получателя
* телефон отправителя
* ссылку на *.pdf файл, который будет отправлен по факсу

Итого, чтобы послать факс, нужно:
Собрать данные → Сгенерировать pdf → Разместить файл в облачном сторадже → Передать телефоны и ссылку на файл в API.

Собрать данные
Стучим в базу и собираем данные. В моем случае это ROM repository, через который вытаскиваются данные об аккаунте из BD.

Сгенерировать pdf
Из всех гемов мне понравился prawn, который легко создает *.pdf файлы. Из плюсоов:
* нативный
* понятная документация с множеством примеров
* можно создать изолированный класс для генерации .pdf

Разместить файл в облачном сторадже
Тут мало подробностей. Я использовал s3, но если у вас не сервис от aws — проблем быть не должно. Главное — получить ссылку.

Передать телефоны и ссылку на файл в API
В документации к twilio указан пример отправки факса. Делаем POST-запрос на twilio URL и передаем параметры.

Собираем шаги вместе
Каждый из этих шагов написан в виде функциональных объектов (оперейшенов). А потом я объединил все объекты в одной транзакции:

class TransferMedicationToPharmasy
include Dry::Transaction(container: Application)

step :read_user, with: operations.read_user
step :generate, with: operations.generate_pdf
step :send_to_s3, with: operations.send_to_s3
step :send_fax, with: operations.send_fax
end


На выходе получил класс, который вызывается в бэкграунд-процессинге: TransferMedicationToPharmasy.new.call(account_id).

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

Что узнает пользователь
Это вопрос, который необходимо себе задать с самого начала: «Что полезного узнает слушатель»? Именно с этого я сам начинаю работу над презентацией.
Мотивация спикера — это очень важно. Если вы идете выступать только из-за того, что заставило начальство, или чтобы показать себя, то качество вашего выступления и всего мероприятия может пострадать.

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

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

Меньше текста на слайдах
Часто замечаю, что люди пишут много текста на слайдах. Такие слайды выглядят перегруженно, отвлекают от речи докладчика. Возможно, это удобно для спикера: часть текста можно просто прочитать со слайда, а не запоминать. Но доклад — для слушателей, а не для спикеров. Разбейте текст на слайды (1 слайд — 1 термин), попробовать заменить текст картинками или же просто выкинуть лишнее.

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

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

Запомнить

- Сделайте доклад полезным для слушателя, а не для себя.
- Рассказывайте связанную историю вместо рандомных фактов.
- Рассказать о проблемах — способ поделиться опытом.
- Много текста на слайде — мало внимания к слайду.
- Подготовьтесь заранее и сделайте собственный прогон доклада с записью и последующим разбором.

Ссылки
- Советы от Scott Hanselman
- Советы от Zach Holman
1600
Тут подсказали, что про railway programming в elixir есть лучше статья:
http://www.scottmessinger.com/2016/03/25/railway-development-in-elixir-using-with/
1700
Вынести логику

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

class UserOperation
def call(payload)
result = ValidateUser.new.call( ... )
result = result.success? ? CreateUser.new.call( ... ) : result
result
end
end

if UserOperation.new.call({ ... }).success?
...
end

Плюсы:
- процесс создания user находится в одном месте
- легко переиспользовать объект

Минусы:
- решение не решает проблему нескольких условий, а просто размазывает логику


Railway Oriented Programming

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

Создается цепочка функциональных объектов, в которые передаются данные. Дальше есть только 2 пути, по которому эти данные будут идти. Либо по success-пути, что будет значить, что объекты вернули положительное значение. Либо, зафейлившись на одном из объектов, возвращают значение failed. В конце можно просто обработать значение, как в интеракторе, и выполнить необходимую логику.

Схематично это выглядит следующим образом.

Допустим, есть объект, который принимает данные и возвращает два разных вида данных — success и failed:

success data → first function object → success data
failed data → first function object → failed data

success data → second function object → success data
failed data → second function object → failed data

В таком случае можно сделать цепочку объектов:

success data → first function object → second function object → success data
failed data → first function object → second function object → failed data
1600
Я знаю 2 способа применения Railway Oriented Programming в Ruby:

Waterfall

Гем, который чейнит функциональные объекты и работает с возвращаемым значением. Выглядит это так:


Wf.new
.chain(user1: :user) { FetchUser.new(1) }
.chain(user2: :user) { FetchUser.new(2) }
.chain {|outflow| puts(outflow.user1, outflow.user2) } # report success
.on_dam {|error| puts(error) } # report error


Использование бизнес-транзакций

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

Учтите, что придется использовать объект, который будет хранить в себе success/failed состояние и значение. Это нужно для передачи состояния между шагами транзакции. Выбирайте сами — подойдет все, что угодно, например, собственный класс, хеш или Either монада (о монадах в следующий раз).

В Ruby есть 3 библиотеки, которые реализуют транзакции:

* operation из trailblazer
* solid use case gem
* dry-transaction

Я фанат dry-transaction, так как библиотека позволяет:
* использовать матчер для возвращаемого значения
* работать с контейнерами (о контейнерах тоже поговорим позже)
* использовать DI в виде инжектинга операций
* использовать один из трех видов шагов (возвращать любой результат как успешный, возвращать failed при exception и передавать данные и не думать о возвращаемом результате)
* создавать кастомные адаптеры для шагов
* многое другое

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


class CreateUser
include Dry::Transaction

step :validate
step :persist

def validate(input)
# ...
end

def persist(input)
# ...
end
end

CreateUser.new.call(name: "Jane", email: "jane@doe.com") do |m|
m.success do |value|
# ...
end

m.failure do |error|
# ...
end
end


Пример рефакторинга знакомого класса с использованием транзакций.

## Запомнить

* Проблема с чейнингом логики возникает чаще, чем кажется.
* Только лишь вынос логики не поможет справиться с хаосом условий.
* Railway Oriented Programming позволяет забыть о проблеме хаоса условий, а также использовать функциональный подход обработки данных в приложении.
* Места применения Railway Oriented Programming — экшены и любые другие места, где у вас есть «поток» данных.
* Забудьте о велосипедах, возьмите одну из готовых библиотек для работы с бизнес-транзакциями.
* dry-transactions — самая навороченная и гибкая из этих библиотек.

## Ссылки

* Главная страница railway programming где можно найти кучу ссылок и примеров
* Описание того, как чейнить объекты "правильно"
* Практическое руководство функционального программирования в rails
* Пример railway programming в elexir
1800
#functional_objects

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

result = ValidateUser.new.call( ... )
result = result.success? ? CreateUser.new.call( ... ) : result

if result2.success?
redirect_to
else
render
end

Или просто код, который валидирует две разные сущности:

validation_post_result = ValidatePost.new.call( ... )
validation_comments_result = ValidateComments.new.call( ... )

if validation_post_result.success? && validation_comments_result.success?
...
end

Или же код, который запускает цепочку сервис объектов:

UserCreator.call(...) && CommentCreator.call(...) && ...

В этих примерах много лишних условий, которые приводятся к общему правилу: выполни пачку действий и верни общий статус. Выглядит такое решение сложным для понимания и будущей отладки, поэтому давайте попробуем упростить код.
1600
#functional_objects

Сегодня поговорим о глобальной теме — функциональных объектах.
Функциональные объекты уже упоминались в предыдущем посте, посвященном интеракторам.

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

Итак, что такое функциональный объект и зачем он нужен?
Это объект, который выглядит как функция. Соответственно, он принимает и возвращает какие-то данные. Также в идеале он должен быть чистым (мы же за функциональное программирование!)
Простые примеры функциональных объектов выглядят следующим образом:

convert_to_string = :to_s.to_proc # => proc
convert_to_string.call(123) # => "123"

pov2 = -> (x) { x ** 2 } # => proc
pov2.call(5) # => 25


Плюсы таких объектов:
- Изолированность. Функциональный объект ничего не знает об окружающем мире, следовательно, его связанность с остальным приложением минимальна.
- Чистота. В идеале такой объект реализует чистую функцию. Это значит, что одни и те же входящие данные каждый раз возвращают один и тот же результат вне зависимости от количества повторений.
- Отсутствие мутаций. Если нет мутаций, тестировать и поддерживать код будет проще. Есть несколько исключений, но о них поговорим позже.


## Зачем нужны функциональные объекты?

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

Эти сервис-объекты будут выглядеть примерно так:

class ToString
def call(object)
String(object)
end
end

to_string = ToString.new
to_string.call(:one) # => one


А теперь сравните этот код с функциональным объектом :to_s.to_proc. Так, интеракторы, оперейшены и сервисы — это тоже функциональные объекты.

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

2. Если вы знаете функциональные языки, например, Haskell, вы знаете, что одни функции объединяются в другие со сложной логикой. Например:

plusOne = (+1)
square = (^2)
squareAndPlusOne = plusOne . square
squareAndPlusOne(4) # => (4 ^ 2) + 1 == 17


Есть энтузиасты, которые сделали библиотеку transproc. Библиотека дает возможность работать с функциональными объектами как в функциональных языках:

convert_to_json = Transproc(:load_json) # создаем первый функциональный объект
symbolize_keys = Transproc(:symbolize_keys) # второй
symbolize_json = convert_to_json >> symbolize_keys # объединяем их в один

symbolize_json.call([{"name":"Jane"}])
# => [{ :name => "Jane" }]


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


## Запомнить

* Объект, который ведет себя как функция, называется функциональным. Логика, которую реализует объект — не так важна.
* Такие объекты реализуют изолированную и чистую функцию, которая не мутирует данные.
* Сервис-объекты, интеракторы или оперейшены — функциональные объекты.
* Функциональные объекты — это просто, они используются каждый день.
* Соединяя функциональные объекты в цепочки, можно создавать сложную логику из небольших изолированных частей.


## Ссылки

* Пример использование функциональных объектов от icelab
* Пример использования функциональных объектов и чистых функций для json конвертера
* Примеры функциональных подходов в руби
* Пост солника о Transproc
1700
Этот подход называется dependency injection (DI) wiki и он «прокидывает» изолированную часть логики извне в объект или метод, что дает нам больше контроля.

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

Плюсы
- Тестирование упрощается во много раз
- Классы и методы становятся гибкими, их легко переиспользовать
- Изоляция кода. Оборачиваете логику в абстракцию — в следующий раз не нужно думать, как она работает
- DI превосходно работает с легаси кодом во время рефакторинга, так как не требует лишних библиотек и не меняет функционал
- Работает в любом языке, фреймворке, библиотеке.

Минусы
- Бесконтрольное использование DI усложняет систему из-за количества сущностей и связей. Такой код сложнее поддерживать
- Не всегда понятно, что делает объект, который инжектится
- Как и все абстракции, может потечь.

Ссылки
- Отличное обсуждение о DI
- Пост Солника о DI в руби
- Пример замены наследования на DI
- Еще один пример рефакторинга код с использованием DI
- Обратная сторона, dhh рассказывает о том, почему DI это зло
1600
1. Eсть класс, который возвращает данные для текущего времени:


class Foo
def get_users_for_current_time
User.where(created_at: Time.now)
# ...
end
end


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


describe Foo do
before do
@time = Time.now
Time.stub(:now).and_return(@time)
end
...
end



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

2. Eсть класс, который отображает логи:


class Logger
def call(message)
# ...

print_message(message)
end
end


Предположим, что в какой-то момент понадобилось отображать лог в JSON. Наследование спасает:


class JSONLogger < Logger
def call(message)
# ...

to_json(message)
end
end


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

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

Поэтому давайте попробуем изолировать эту логику и вынесем ее из объекта:


class Foo
def get_users_for_current_time(time: Time.now)
User.where(created_at: time)
# ...
end
end

describe Foo do
let(:time) { Time.now }
it { expect(Foo.get_users_for_current_time(time)).to eq ... }
# ...
end


И для другого примера:


class Logger
def call(message, formatter: BaseFormatter)
# ...
formatter.call(message)
end
end

Logger.new.call(message, formatter: BaseFormatter)
Logger.new.call(message, formatter: JsonFormatter)
Logger.new.call(message, formatter: XmlFormatter)
1600
#functional_objects

В прошлый раз мы смотрели, как изолировать часть логики. Сегодня же поговорим о ситуации, когда у изолированной логики есть сложные для тестирования или контроля части.
Возможно, вы слышали о таком подходе, и сегодняшняя тема вызывает ассоциацию с миром javaEE, но поверьте, это знание выручает меня каждый день. Начнем с примеров.
1600
Ссылка оказалась битой, вот работающая:
https://gist.github.com/davydovanton/5fc0f213b56da3baa3a1e2c7b378a6e9
1600
## Практика

Я знаю о двух работающих библиотеках, в которых реализован этот паттерн:
1. Hanami-interactor
2. Гем interactor

Что из этого выбрать, решайте сами.

Лично мне нравится подход в Hanami, так как колбэки только усложняют код, а context объект добавляет еще одну штуку, о которой нужно постоянно думать. С hanami можно использовать просто класс с минимумом методов.

Как пример — рассмотрим экшен из open source проекта. И постараемся зарефакторить код с помощью interactor.
https://gist.github.com/davydovanton/5fc0f213b56da3baa3a1e2c7b378a6e

## Ссылки
1. How to Reduce Controller Bloat with Interactors in Ruby
2. A couple of words about interactors in Rails
3. Why using Interactor Gem is a Very Bad Idea
1600
# Зачем это нужно
В первую очередь интерактор нужен, чтобы скрыть бизнес-логику в объекте с единственным публичным методом call. Пока это выглядит как типичный сервис-объект, но прелесть интерактора в том, что возвращаемый им объект (data object) содержит в себе статус (success или failed) и указанные геттеры.

# Какие проблемы решаются
Интерактор поможет решить три распространенных проблемы:

Изоляция бизнес-логики в отдельную сущность
Изолированные и имутабельные объекты легко тестируются. Объекты легко вызвать (в отличии от контроллеров и вью), объекты возвращают значение и при использовании dependency injection (DI) можно подменять логику в тестах вместо стабов. Я не фанат стабов и моков, но это отдельная тема для отдельного разговора.

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

Контроль флоу в зависимости от бизнес логики
Я писал, что интерактор возвращает data object со стейтом. Как можно догадаться, это используется. Например, надо сохранить объект, и в зависимости от того, сохранится успешно или нет, редиректнуть пользователя на указанный путь. Вот так это выглядит в приложении:


def call(params)
result = Interactors::CreateDrug.new(params).call

if result.successful?
redirect_to routes.drug_path(result.drug.id)
else
redirect_to routes.drugs_path
end
end
1500
Получил предложение писать о том, что использую в ежедневной работе, и добавить больше юзкейсов.

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

Я фанат идеи функциональных объектов. В Rails я использовал сервис-объекты, в текущем dry-web проекте — оперейшены, а в ханами — интеракторы.

Текст будет касаться исключительно Hanami и hanami-interactor, но подход возможно использовать в других фреймворках.
1600
## После конференции

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

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

Доклады != Лекции в универе
Сложно успеть рассказать объемную и (или) хардкорную тему за 25 минут. Поэтому мой совет: воспринимайте доклады не как лекции, а как мотивацию двигаться в этом направлении. Как пример — доклад Тима с прошлогоднего reddotrubyconf, где рассказывалось про микс ООП и функциональных объектов в вебе. Это сложная и объемная тема. Понятно, что непросто рассказать все и сразу. Но для меня это выступление стало стимулом глубже разобраться в теме и узнать много нового.
1500
## На конференции

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

Общайтесь где угодно, как угодно, о чем угодно. Если сложно просто так заговорить, то придумайте себе задачу. Например, на railsclub в прошлом году раздавали купоны на бесплатное пиво. Я бросил себе вызов собрать 20 таких купонов https://twitter.com/anton_davydov/status/789848018107367424, а в итоге собрал больше 30. Благодаря этому я познакомился с интересными людьми и весело провел день.

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

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

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

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

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

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

Приходите за полчаса до начала
Во-первых, так ваша регистрация пройдет без суеты — основная масса людей приходит за 5-15 минут до начала.
Во-вторых, это отличный шанс спокойно выпить кофе и поймать интересных людей первыми.
1500
Немного советов о том, что делать до, во время и после конференции, чтобы получить максимум пользы и впечатлений.
1300
## Карьера (и в open source тоже)

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

А еще можно познакомиться с людьми, которые помогут в работе. Прочтите пост моей коллеги Марион в блоге Hanami (https://github.com/hanami/hanami.github.io/pull/267/files). Марион познакомилась с автором Hanami Лукой на конференции, и это знакомство привело к неожиданному результату. Вчера её презентацию оценили слушатели, а работа с опенсорсом помогает ей в решении ежедневных задач.
1200
## Обмен опытом и / или идеями

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

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

Попробуйте выйти из зоны комфорта и узнать, как разработчики используют обыденную технологию в нестандартных ситуациях. Так, например, я узнал, что Ruby используется для инвалидных колясок (https://twitter.com/hanmd82/status/877735708798066688).
1200
## Тусовка

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

Два дня назад я впервые встретился вживую с коллегой по Hanami, Марион. За эти 2 дня, попутно решив насущные проблемы, связанные с проектом, я узнал от неё, что вегетарианство в Швейцарии намного выгоднее. Причина в том, что в Японии мало блюд, где нет мяса или рыбы.

С Ником, создателем фреймворка Trailblazer, мы познакомились на прошлогодней конференции Euruko. Я спросил, как у него дела с гемом для Hanami, и мы разговорились. За последние 3 дня, успев обсудить варианты использования Trailblazer и Hanami, мы выпили пива с дурианом, чего, по словам местных, делать ни в коем случае нельзя.

Иногда конференции — единственное место, где встречаются удаленные разработчики. Например, Railsclub объединяет кор-разработчиков Toptal, Evil Martians и других компаний. Разработчики Gitlab собираются на Euruko. На прошлой работе я увидел вживую коллегу из Таиланда только один раз – на RedDotRubyConf 2016.
1100
Только что прошла сингапурская конференция http://reddotrubyconf.com, которую я посетил два раза: в прошлом году как участник, а в этом – как спикер. Так как впечатления и эмоции еще свежи, было бы логично поделиться мнением, связанным с конференциями, митапами и другими похожими ивентами.

Есть люди, уверенные в том, что подобные ивенты — трата времени. Я так не считаю, и вот почему:
1100