window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster already exists') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() HI, I'M PORO - The Codest
The Codest
  • About us
  • Services
    • Software Development
      • Frontend Development
      • Backend Development
    • Staff Augmentation
      • Frontend Developers
      • Backend Developers
      • Data Engineers
      • Cloud Engineers
      • QA Engineers
      • Other
    • It Advisory
      • Audit & Consulting
  • Industries
    • Fintech & Banking
    • E-commerce
    • Adtech
    • Healthtech
    • Manufacturing
    • Logistics
    • Automotive
    • IOT
  • Value for
    • CEO
    • CTO
    • Delivery Manager
  • Our team
  • Case Studies
  • Know How
    • Blog
    • Meetups
    • Webinars
    • Resources
Careers Get in touch
  • About us
  • Services
    • Software Development
      • Frontend Development
      • Backend Development
    • Staff Augmentation
      • Frontend Developers
      • Backend Developers
      • Data Engineers
      • Cloud Engineers
      • QA Engineers
      • Other
    • It Advisory
      • Audit & Consulting
  • Value for
    • CEO
    • CTO
    • Delivery Manager
  • Our team
  • Case Studies
  • Know How
    • Blog
    • Meetups
    • Webinars
    • Resources
Careers Get in touch
Back arrow GO BACK
2018-01-03
Software Development

HI, I’M PORO

Katarzyna Jaruga

Many people are learning Ruby by starting with Rails framework and, unfortunately, this is the worst possible way of learning this language. Don’t get me wrong: Rails is great, it helps you to build web applications quickly and efficiently without having to get into many technical details.

It’s nice to meet you!

Many people are learning Ruby by starting with Rails framework and, unfortunately, this is the worst possible way of learning this language. Don’t get me wrong: Rails is great, it helps you to build web applications quickly and efficiently without having to get into many technical details. They provide a lot of “Rails magic” that makes things simply work. And for a newbie programmer this is really great, because the most pleasant moment of the process is when you can say “it’s alive!”, and see that all parts fit together and people use your app. We like to be “creators” 🙂 But there is one thing that distinguishes good programmers from the average: the good ones understand how the tools they use work. And by “understanding your tools” I don’t mean knowing all the methods and modules provided by a framework, but understanding how it works, understanding how the “Rails magic” happens. Only then you can feel comfortable with using objects and programming with Rails. The foundation of the object-oriented programming, and the secret weapon which makes the complicated Rails application easier, is the already mentioned in the title PORO, that is Plain Old Ruby Object

What really lies beneath this name? What is this great secret weapon? It is a simple Ruby class that does not inherit from anything. Yes, just that, and so much.

class AwesomePoro
end

How can I help you?

You are continuously developing your application and adding new functionalities as the number of users and their expectations are growing. You get to the point where you encounter more and more dark places of extremely twisted logic, the places which are avoided like the plague by even the bravest developers. The more such places, the more difficult to manage and develop the application. A standard example is the action of registering a new user, which triggers a whole group of other actions associated with this event:

  • checking the IP address in a spam database,
  • sending an email to the new user,
  • adding a bonus to an account of a recommending user,
  • creating accounts in related services,
  • and many more…

A sample code responsible for user registration might look like this:

class RegistrationController < ApplicationController
  def create
    user = User.new(registration_params)
    if user.valid? && ip_valid?(registration_ip)
      user.save!
      user.add_bonuses
      user.synchronize_related_accounts
      user.send_email
    end
  end
end

Okay, you’ve got it coded, everything works, but… is all of this code really okay? Maybe we could write it better? First of all, it breaks the basic principle of programming – Single Responsibility, so surely we could write it better. But how? This is where the already mentioned PORO comes to help you. It’s enough to separate a class RegistrationService, which will be responsible for only one thing: notifying all the related services. By services we will consider the individual actions which we have already singled out above. In the same controller all you need to do is create an object RegistrationService and call on it the “fire!” method. The code has become much clearer, our controller is taking up less space, and each of the newly created classes is now responsible for only one action, so we can easily replace them should a need arise.

class RegistrationService
  def fire!(params)
    user = User.new(params)
    if user.valid? && ip_validator.valid?(registration_ip)
      user.save!
      after_registered_events(user)
    end
    user
  end
  private
  def after_registered_events(user)
    BonusesCreator.new.fire!(user)
    AccountsSynchronizator.fire!(user)
    EmailSender.fire!(user)
  end
  def ip_validator
    @ip_validator ||= IpValidator.new
  end
end
class RegistrationController < ApplicationController
  def create
    user = RegistrationService.new.fire!(registration_params)
  end
end

However Plain Old Ruby Object may prove useful not only for controllers. Imagine that the application you are creating uses a monthly billing system. The exact day of creating such a billing is not important to us, we only need to know that it concerns a specific month and year. Of course you can set the day for the first day of each month and store this information in the object of the “Date” class, but neither is it a true information, nor do you need it in your application. By using PORO you can create a class “MonthOfYear”, the objects of which will store the exact information you need. Moreover, when applying in it the module “Comparable”, it will be possible to iterate and to compare its objects, just like when you are using the Date class.

class MonthOfYear
  include Comparable
  attr_reader :year, :month
  def initialize(month, year)
    raise ArgumentError unless month.between?(1, 12)
    @year, @month = year, month
  end
  def <=>(other)
    [year, month] <=> [other.year, other.month]
  end
end

Introduce me to Rails.

In the Rails world, we are used to the fact that each class is a model, a view or a controller. They also have their precise location in the directory structure, so where can you put our little PORO army? Consider a few options. The first thought that comes to mind is: if the created classes are neither models, nor views nor controllers, we should put them all in the “/lib” directory. Theoretically, it is a good idea, however if all of your PORO files will land in one directory, and the application will be large, this directory will quickly become a dark place which you fear to open. Therefore, undoubtedly, it is not a good idea.

AwesomeProject
├──app
│  ├─controllers
│  ├─models
│  └─views
│
└─lib
  └─services
      #all poro here

You can also name some of your classes non-ActiveRecord Models and put them in the “app/models” directory, and name the ones which are responsible for handling other classes the services and put them in the “app/services” directory. This is a pretty good solution, but it has one drawback: when creating a new PORO, each time you will have to decide every whether it is more of a model or a service. This way, you may reach a situation where you have two dark places in your application, only smaller ones. There is yet a third approach, namely: using namespaced classes and modules. All you need to do is create a directory which has the same name as a controller or a model, and put all PORO files used by the given controller or model inside.

AwesomeProject
├──app
│  ├─controllers
│  │ ├─registration_controller
│  │ │ └─registration_service.rb
│  │ └─registration_controller.rb
│  ├─models
│  │ ├─settlement
│  │ │ └─month_of_year.rb
│  │ └─settlement.rb
│  └─views
│
└─lib

Thanks to this arrangement, when using it, you don’t have to precede the name of a class with a namespace. You have gained shorter code and more logically organized directory structure.

Check me out!

It is a pleasant surprise that when using PORO, the unit tests of your application are faster and easier to write and later on more likely to be understood by others. As each class is now responsible for only one thing, you can recognize the boundary conditions sooner, and easily add appropriate test scenarios to them.

describe MonthOfYear do
  subject { MonthOfYear.new(11, 2015) }
  it { should be_kind_of Comparable }
  describe "creating new instance" do
    it "initializes with correct year and month" do
      expect { described_class.new(10, 2015) }.to_not raise_error
    end
    it "raises error when given month is incorrect" do
      expect { described_class.new(0, 2015)  }.to raise_error(ArgumentError)
      expect { described_class.new(13, 2015) }.to raise_error(ArgumentError)
    end
  end
end

I hope we’ll meet again!

The examples we presented clearly show that using PORO improves readability of applications and makes them more modular, and, in consequence, easier to manage and expand. Embracing the principle of the Single Responsibility facilitates the exchange of particular classes if necessary, and doing so without interfering with other elements. It also makes testing them a simpler and faster procedure. Moreover, this way keeping Rails models and controllers short is much easier, and we all know that they tend to get unnecessarily big in the process of development.

Related articles

Software Development

Build Future-Proof Web Apps: Insights from The Codest’s Expert Team

Discover how The Codest excels in creating scalable, interactive web applications with cutting-edge technologies, delivering seamless user experiences across all platforms. Learn how our expertise drives digital transformation and business...

THECODEST
Software Development

Top 10 Latvia-Based Software Development Companies

Learn about Latvia's top software development companies and their innovative solutions in our latest article. Discover how these tech leaders can help elevate your business.

thecodest
Enterprise & Scaleups Solutions

Java Software Development Essentials: A Guide to Outsourcing Successfully

Explore this essential guide on successfully outsourcing Java software development to enhance efficiency, access expertise, and drive project success with The Codest.

thecodest
Software Development

The Ultimate Guide to Outsourcing in Poland

The surge in outsourcing in Poland is driven by economic, educational, and technological advancements, fostering IT growth and a business-friendly climate.

TheCodest
Enterprise & Scaleups Solutions

The Complete Guide to IT Audit Tools and Techniques

IT audits ensure secure, efficient, and compliant systems. Learn more about their importance by reading the full article.

The Codest
Jakub Jakubowicz CTO & Co-Founder

Subscribe to our knowledge base and stay up to date on the expertise from the IT sector.

    About us

    The Codest – International software development company with tech hubs in Poland.

    United Kingdom - Headquarters

    • Office 303B, 182-184 High Street North E6 2JA
      London, England

    Poland - Local Tech Hubs

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Warsaw, Poland

      The Codest

    • Home
    • About us
    • Services
    • Case Studies
    • Know How
    • Careers
    • Dictionary

      Services

    • It Advisory
    • Software Development
    • Backend Development
    • Frontend Development
    • Staff Augmentation
    • Backend Developers
    • Cloud Engineers
    • Data Engineers
    • Other
    • QA Engineers

      Resources

    • Facts and Myths about Cooperating with External Software Development Partner
    • From the USA to Europe: Why do American startups decide to relocate to Europe
    • Tech Offshore Development Hubs Comparison: Tech Offshore Europe (Poland), ASEAN (Philippines), Eurasia (Turkey)
    • What are the top CTOs and CIOs Challenges?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Copyright © 2025 by The Codest. All rights reserved.

    en_USEnglish
    de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek en_USEnglish