Size: a a a

2017 July 19
2pegramming
Завтра состоится митап в москве. Последние пару дней мы слушали доклады спикеров: задавали ребятам вопросы и давали рекомендации по поводу слайдов. Расскажу здесь о правилах, которые, на мой взгляд, помогут сделать презентацию качественной.

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

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

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

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

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

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

Запомнить

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

Ссылки
- Советы от Scott Hanselman
- Советы от Zach Holman
источник
2017 July 26
2pegramming
Я работаю в американском 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).

Выводы
* Отправлять факсы проще, чем кажется.
* Старые технологии, о которых забыли модные ребята, могут приносить деньги.
* Не все задачи, которые кажутся сложными на первый взгляд, на самом деле таковыми являются.
источник
2017 July 28
2pegramming
Сегодня я расскажу о фиче ханами, над которой работаю сейчас и которую хотел бы видеть в следующей версии (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
источник
2pegramming
Организационные моменты

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

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

> Привет! Вижу, ты часто пишешь про 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. Но для себя я выработал правило: если стейт не важен, использую сервис. Если стейт важен — интерактор или оперейшен с монадой, хешем.

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

Задача

Вместо множества полей и перегрузки интерфейса было решено сделать единственное поле для поиска. Такой поиск сделал гитхаб. Строка 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 и код.

Ссылки

* Блог пост о том, как парсить текст в руби
источник
2017 August 03
2pegramming
Сегодня поговорим про валидации. Я не фанат 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 и других гемах. Чтобы начать с ней работать, достаточно прочитать гайды.
источник
2pegramming
Запомнить
- Rails way не панацея. Старайтесь думать, когда полезно его придерживаться, а когда — нет.
- Валидации и модель — разные вещи. Вынос валидаций в контроллер может сильно облегчить жизнь и процесс тестирования.
- У выноса валидаций есть минусы, выбирайте осознанно.

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

Почитать
- Hanami — отличный пример, когда вынос валидации из модели работает как надо.
- Такой же подход пропагандирует трейлблейзер.
- Облегчаем жизнь монадами.
- Как использовать AR::Validation вне модели.
- Используем dry-validation в rails приложении.
источник
2017 August 04
2pegramming
Простите, ссылка на использование AR::Validation вне модели вела не на тот пост, вот правильный:
https://blog.ragnarson.com/2016/10/26/validation-outside-activemodel.html
источник
2017 August 07
2pegramming
Я уже писал об использовании dependency injection в ruby. Но как и у всех подходов, у DI существуют свои минусы.

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

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

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

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

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

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


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

Перечисленные проблемы заставляют задуматься об использовании DI в проекте. Но есть решение, которое позволяет контролировать зависимости.
источник
2pegramming
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 в интеракторе.
источник
2pegramming
Ребята из 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
источник
2pegramming
и немного опыта моего коллеги, который будет полезен, если вы захотите использовать контейнеры
источник
2pegramming
источник
2017 August 10
2pegramming
«Как начать писать в opensource?»
Кажется, такой вопрос задавал себе каждый разработчик, в том числе и я сам. Сегодня мне хотелось бы поделиться опытом и советами для всем, кому интересна эта тема.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Советы

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

Запомнить

- Опенсорс — такая же работа, с такими же людьми. Не думайте, что она для избранных или исключительно для профи. Это под силу каждому.
- Опенсорс — это не только про код, но и про общение. Не обязательно писать код, чтобы помочь.
- Не заставляйте себя, пользы от этого никому не будет.
- Не нервничайте и не сдавайтесь. Будьте вежливы и дружелюбны, и вам понравится!
источник
2017 August 15
2pegramming
Я уже писал о dry-transaction. На работе мы начали использовать эту библиотеку в оперейшенах. Это такие сервис объекты, которые вызываются из транспорта (http, stream) и выполняют код завязанный на бизнес логику. Это может быть как просто манипуляция с бд (достать данные, сохранить данные), так и действительно сложная логика. Например процессинг платежа. Текущее решение содержит в себе  много магии и поэтому было решено начать использовать dry-transactions как основной каркас для построения оперейшенов.

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

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

Старая ссылка с примером в ханами:
https://gist.github.com/davydovanton/0a9e9dcaef75582e3c2fe9b4392b61d9
Telegram
2pegramming
#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(...) && ...

В этих примерах много лишних условий, которые приводятся к общему правилу: выполни пачку действий и верни общий статус. Выглядит такое решение…
источник
2017 August 21
2pegramming
Доброго времени, читаю канал, но интересно, почему не используется телеграф(telegraph.ph) для хранения статей? Интересно узнать ваше мнениеtelegraph.ph) для хранения статей? Интересно узнать ваше мнение

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

Оргвопросы

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

Также появилась идея раз в неделю делиться ссылками на интересные посты. Что думаете?
источник
2pegramming
Я люблю экшены в 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, что позволяет вынести логику из модели. В результате модель получается «тоньше». Условные валидации пропадают как костыль, потому что валидируются только указанные в каждом экшене параметры.
источник
2pegramming
Но и как у любой технологии, у экшенов Hanami есть минусы.

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

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

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

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

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

Ссылки
- Документация на экшены в hanami
источник