Callbacks are evil! 😈
Tags: ruby, rails
Published: 2024-02-22 14:47:00

I’m working on a super secret app to revolutionize service field businesses 😜. Yesterday, the codebase had the opportunity to be viewed by eyes from the outside world for the first time and got feedback.

One of the things that stood out was the code related to converting Requests to Quotes. This workflow:


![Requests to Quotes workflow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f0nc8x6x6i7p1z1ouhyn.png)

This particular code:
![Code using after_create callback](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5k7gg75jmjrifdtal492.png)

This involved the callback `after_create`!
![Code that involved the callback `after_create`](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x7yf0hmwld2of8zvcqwl.png)


I know, I know. [Callbacks are evil](https://medium.com/planet-arkency/the-biggest-rails-code-smell-you-should-avoid-to-keep-your-app-healthy-a61fd75ab2d3)!

Well, my lame excuse at the time of development is I could not find the correct language for the conversion process when developing the [ubiquitous language](https://thedomaindrivendesign.io/developing-the-ubiquitous-language/).

Based on the stakeholders, whenever they need the quote to be produced, they just say to the employee: “Palihug ko pa.quote ani dong/dai. “

This can be loosely translated as: “Hey [name], can you please create a quote for this customer’s request?”

At that time of development, I could not find the right words for it. Based on what I was hearing from the stakeholders, they just said to create a quote.

So, I opted for the easiest solution available, callbacks!

## Why are callbacks bad?

It is probably not that concerning in this particular case since the workflow is pretty simple.

However, I’ve been burned by this before! When I was working on an e-commerce application, we used a `after_save` callback that sent app notifications to listing owners when their listings were updated. When we ran a script that was intended to update silently thousands of listings on a Sunday evening. Long story short, it was not a very silent Sunday 😅.


![Meme about failed deploys](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/26b8uw6wci5rxp4qkfta.png)

## So, how do we move away from callbacks?

Modeling/developing/writing a better ubiquitous language for the domain you are working on helps you write better code.

In my case, I could not find the right technical words while conversing with the stakeholders.

However, now that I started developing the user interface, it seems it’s pretty straightforward:


![User interface](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jh3o6xbzkt3h8ysrsgwn.png)

## So, what does the change look like in the code?


![Changes to code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dxqor8b867l4lm426u6l.png)


**Step 1: Create a PORO to handle the business logic**


![PORO to handle business logic](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l0rwobssc8ziu2q2aywi.png)

Things to note on the code above:
- I created a PORO (Plain Old Ruby Object) for the Request to Quote Conversion business logic.
- Later, if we want to send email or mobile notifications to admins or employees, we should update this class.
- If anything fails, this class should handle the failure gracefully, especially if it involves payments, etc.
- Now that it’s a class, creating unit tests for this specific business logic would be easier, ensuring that this process is more robust when change requests come in later.

**Step 2: Update controllers**

You can then use the PORO on the controller like this:
![Using the PORO in controller](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i67u8fqsnw9n4v74ecqb.png)

Optional Steps:
You can do it a step further and follow [DHH’s approach](https://www.youtube.com/playlist?list=PL3m89j0mV0pdNAg6x9oq6S8Qz_4C-yuwj), creating a method for the request model:

![Update on request model](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/og2opfj2n8l58isidwe0.png)

Then, you can easily create a call this method on the controller like so:
![Using the PORO](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2lrx9khu2xgoxfgyhoy4.png)

## Question: Are callbacks evil?

There are two camps for this: people who are [for](https://dev.37signals.com/globals-callbacks-and-other-sacrileges/) and [against](https://medium.com/planet-arkency/the-biggest-rails-code-smell-you-should-avoid-to-keep-your-app-healthy-a61fd75ab2d3) callbacks.

My take is:
As developers, we constantly understand the domains that we are working on and develop a unique [ubiquitous language](https://thedomaindrivendesign.io/developing-the-ubiquitous-language/) for them.

Initially, we may not have the right words for it, thus we need to use convenient “generic” tools such as callbacks. But as soon as you learn more about the domain, and build a better ubiquitous language, the design of your code should follow also.

_Originally posted on: https://blog.ademartutor.com/p/callbacks-are-evil_

***

Hello there!

Do you have a startup idea or an exciting project you're passionate about? I'd love to bring your vision to life!

I'm a software developer with 13 years of experience in building apps for startups, I specialize in Rails + Hotwire/React. 

Whether you're looking to innovate, grow your business, or bring a creative idea to the forefront, I'm here to provide tailored solutions that meet your unique needs.

[Let's collaborate to make something amazing!](https://www.linkedin.com/in/ademar-tutor-0a95972a/)

Sincerely,
Ademar Tutor