Ivan Kulagin
Menu

My Ruby Portfolio

AVR Chiptuning

One of my favourite projects! Sadly, the client disappeared right in the middle of the service’s frontend implementation, so the screenshots represent the work in progress.

But anyway here is the story.

David needed the car engines database to let the user select he want to tune. After research he found and bought the required DB. But because that DB was just a scraped raw data, there were a lot of corrupted data and of course it wasn’t logically structured. So the primary goal was to model the data and create a complex CSV data normalizer

After that done, the next goal was to create an API. Here I decided to use my favourites: Rack wrapped in tiny hanami-api, warden for token authentication and dry-rb gems collection. That way we’ve got a beautiful and testable code like this:

module Avr
  module Api
    module Endpoints
      module Employers
        class SignIn
          include Dry::Monads[:result]
          include Avr::Api::Endpoints::Common::Public
          include Import['avr.logging.logger',
                         action:     'avr.actions.employers.sign_in',
                         serializer: 'avr.api.serializers.employee']

          # Params: Hanami::Params
          def call(params)
            case action.call(params.to_h)
            in Success(employee)
              logger.info("Employee authenticated: #{employee.inspect}")
              json_body(serializer.render(employee, view: :sign_in))
            in Failure(Dry::Validation::Result => result) # match against validation: true
              api_validation_error(message: 'Validation error', errors: result.errors.to_h)
            in Failure(result)
              api_error(message: result, error_type: :sign_in)
            end
          end
        end
      end
    end
  end
end
module Avr
  module Actions
    module Employers
      class SignIn
        include Dry::Monads[:result, :do]

        include Import[
                  'avr.logging.logger', 'avr.utils.api_tokens_generator',
                  employers:  'avr.repos.employers',
                  api_tokens: 'avr.repos.employee_api_tokens',
                  contract:   'avr.api.contracts.employers.sign_in']

        def call(params)
          values   = yield validate(params)
          employee = yield find_employee(values[:email])
          employee = yield authenticate(employee, values[:password])
          employee = yield generate_new_access_token(employee)

          Success(employee)
        end

        # contracts return the result objects that keep both input values and errors.
        def validate(params)
          contract.call(params).to_monad
        end

        def find_employee(email)
          if (employee = employers.find_by_email(email))
            Success(employee)
          else
            Failure("Can't find Employee")
          end
        end

        def authenticate(employee, password)
          logger.debug("Authenticating")
          if BCrypt::Password.new(employee.password_digest) == password
            logger.debug("Password match!")
            Success(employee)
          else
            logger.debug("Password mismatch")
            Failure("Password mismatch")
          end
        end

        def generate_new_access_token(employee)
          logger.debug("Generating new access/reset token pair for employee: #{employee.email}")

          tokens_data = api_tokens_generator.generate
          logger.debug("Creating new access/reset token pair for employee: #{employee.email}")
          token = api_tokens.create(employee_id: employee.id, **tokens_data)

          return Failure("Can't create access tokens") unless token

          employee.current_api_token = token
          Success(employee)
        end
      end
    end
  end
end

Next step was to create frontend part. And that was the first time I choose Elm as a frontend language, having some awesome experience with it in my learning sandboxes. Everything went smooth until in the middle of frontend work my client stopped responding :(

Anyway, I’d love to use Elm again someday, that was a joy to work with it!

Actually this project had my dream stack: parsers/normalizers, data modelling, APIs, lightweight stack and Elm for frontend. I’d only add TailwindCSS in that list for completeness.

Visit

spINFLUENCEit

Long-term API project, where I was a head developer of backend side of two applications:

  • one DJ’s desktop app which DJ use to notify the crowd the track he’s playing, respond to music requests, upload his music collection metadata people able to search in, etc.
  • and the second app is a mobile app for party guests, where people can order, vote, like the currently playing track, send tips to DJ, search the DJ’s music collection etc.

Initially the app were built on Ruby on Rails, but soon we decided to replace it with Grape, just because we were not need Rails beast for API, that migration increased performance a lot. As a free bonus we’ve got a swagger docs for API for free. Hanami (formerly Lotusrb) wasn’t mature enough yet, but today I’d definitely use it instead (or even clean Rack app), additionally replacing ActiveRecord which I consider as an antipattern for everything but MVP.

Interesting design decisions/stack used:

  • Firebase for authentication
  • Google Cloud Messaging to interact with guest’s mobile application (broadcasts, direct messages)
  • heavy use of bz2 streams to transfer huge DJ’s music collection metadata
  • stream compressed metadata in NDJSON format
  • PG per-DJ partitioning (at those times there wasn’t native PG solution for that out of the box)
  • multiple external musical APIs integration (cover images look up, search song my fingerprint etc). At some point each background track normalization process called 5 different external APIs
  • of course most core features where covered by tests (unit/feature al kind of, depending on what was the goal of tests)
  • custom Firebase authentication warden strategies implemented for both roles: DJ and Guest
  • few PG triggers implemented on PL/pgSQL to ease work with millions of music tracks data records
  • Braintree payments integration
  • using Que for background tasks (client want no additional elements like Redis in stack)
  • simple S3 integration

This was a very interesting experience, where I had to use all my knowledge about performance optimization and big project (with lots of data) leading development

Visit

BlockVestMovement

Big DevOps job with a lot of complex tasks, pursuing low cost for the client. On of the cool things I choose is to use Nomad cluster (because we didn’t need bloated k8s here), and Nomad+Vault+Consul trio did the work perfectly.

  • network design, stack parts selection
  • Terraform for setting up AWS for each environment (staging/production), including ELB, CloudFormation, CloudFront etc
  • custom AMI’s used to provision machines created with Packer for each role
  • Gitlab’s CI used to build and push app’s docker images to Nomad’s cluster
  • two (scalable) instances of HAProxy as a reverse proxy working in pair with Consul
  • tens of AWS smaller building block involved, TLS certs, dns, etc
  • lots of shell scripting and automation

NOTE In Apr 2022 website seems down, but I’m not working on this project for a year now :)

Visit

Instamotor Inc.

The project consists of two parts: main grape-based API backend and web crawler, gathering vehicle sell postings from the web. API includes tricky communication layer based on Twilio. My noticeable goals were:

  • migrate both apps from Resque to Sidekiq (jobs rework, queues tuning)
  • add Sidekiq monitoring and logging extensions
  • refactor/add MMS handling for Twilio
  • leasing and freeing Twilio phone numbers
  • forwarding calls/steganography (shown on screenshot)
  • Amazon EC2 instances managing and tuning
  • rewrite and make testable internal Slack messenger (shown on screenshot)
  • integration with NewRelic, Rollbar, Papertrail and Dead Man’s Snitch 3rd-party services
  • plenty of small refactorings (code had low quality)

And of course everything was tested with Rspec.

NOTE: my goals were related to backend only

Visit

Apple pass manager

AngularJs + Ruby on Rails project with integration with Apple Passbook API and Apple push service. This project was done solely by myself for BestFit mobile company.

Features implemented:

  • WYSIWYG pass designer with near pixel-perfect result with support of all five pass types
  • several versions of the same pass supported
  • ability to schedule publishing any version to registered devices using APB API (+push service)
  • generating and signing passes
  • simple and robust hand-crafted image uploading service (instead of Carrierwave or Paperclip). Creating it allowed decoupling image processing and make the whole pass creation process straight and neat.
  • a whole bunch of nice other features

The code was heavily tested, and it was relatively easy, thanks to nice gems like light-service (I love Command pattern :) and virtus

Higgins MD 420

Heavy refactoring/cleanup/drying of legacy code and new features implementation. There was no unit tests at all, and became more than 500 after about three months as I’ve joined project.

Technologies used:

  • common gems toolbox (about one hundred gems; rspec, cucumber, poltergeist, rails 3.2, capistrano, mysql etc.)
  • devise with heavy customization to satisfy business needs
  • active_merchant billing (with authorize.net binding/testing)
  • activeadmin with decorated models
  • wicked_pdf for health history pdf generation
  • cocoon for nested forms (yep, it was long time ago :)
  • jenkins CI with github PR triggers
  • mercury editor
  • errbit
  • redmine

Note on frontend: when I joined this project, frontend (including JS) was almost completed, I’ve done only refactoring of CSS (SCSS+Compass) and JS (CS).

Visit

Pelesend corporate site

Almost completely rewritten backend (Ruby on Rails based) ugly source code, added completely missed integration/unit specs, added Mercury Editor for admins, no frontend work applied (client is waiting for new design), removed or taken from gems 90% of code (JS mostly).

Results of refactoring:

3,626,024 bytes -> 322,949 bytes
536 files changed
5562 insertions(+)
98880 deletions(-)

Less code - less trouble :)

Visit

ABC Logistik

Regular complexity site for Russian logistic company, made solely by myself from the ground. Some features (menu items) client decided to implement in the future.

Tools used:

  • Ruby on Rails 3.2
  • MySQL (not my decision)
  • simple_form
  • strong_parameters (while using Ruby on Rails 3.2)
  • rubytree
  • active_admin
  • compass-rails
  • bootstrap-sass
  • rspec
  • capybara
  • factory_girl_rails
  • livereload
  • capistrano
  • passenger

This website was created using Hugo 0.139.2, and Google Material Design Lite