Should you use REPL consoles?

The first time I faced a REPL console was back at university in the Languages and Programming Paradigms lecture by the great Casiano Rodriguez-Leon. We used the pry console, as it was nicer than Ruby’s built-in one irb. It was a really cool experience, as I was just able to type the code and run it. On top of that, the speed at which we were typing new code and figuring out what worked or didn’t was far higher than with the most common language we used at the university at the time, C++.

Although I’ve mentioned pry and ruby consoles, this tool is available in a wide range of languages, like python and even Golang! Though I think it’s most commonly used in Ruby and Python.

What is a REPL console, anyway?

A read–eval–print loop (REPL), also termed an interactive top-level or language shell, is a simple interactive computer programming environment that takes single user inputs, executes them, and returns the result to the user; Wikipedia, Read–eval–print_loop

In other words, REPL consoles are very cool little pieces of software that lets you try things out and throw away the code afterwards.

Why even talk about these consoles?

Throughout time, I’ve seen these consoles used to test or build POCs and to try to improve developer experience, but they are sometimes used as a way to run scripts in production. At first, you might think that it is great as teams can easily use the production code to fix issues for users. No more getting into the database and updating data, you can use the DTOs you love so much allowing you to focus on developing your core features for the same users. But is it really that great? Let’s look a little deeper…

The good

It’s an easy way to run data migrations

Do you need to fix some pesky data for your users, or do you want to do it behind the scenes to provide a great experience? Well just SSH in, run the console and do the migration! Easy-peasy-lemon-squeezy.

You’re using your own code

To me, this is one of the selling points to use a REPL console, you’re using your own code to fix issues, and no more random SQL migrations, or bringing up another repo with a quasi-identical code to connect to the database and run the scripts you need. If it’s not the same, most likely you’re forgetting something, and you might do more harm than good.

Fixing problems with tight deadlines

Sometimes, you need to adhere to a specific schedule and must respect a deadline. In my current gig, for example, banks have cut-offs at which you can no longer send files to move money around. So, if a piece of software fails, and you need to run a portion of it to finish the job and ensure your customers get paid, well you can!

The bad

Reinventing the wheel

With these consoles, you’re writing some “disposable” code that, most likely exists for the sole purpose of the task you’re currently working on and for which you haven’t tested the interactions with your system.

That means that this code and the risk assessment purely rely on your engineering team’s knowledge. It may be great today but, it might not be the case in the future.

Ideally, you should keep the code in your runbook but, in my experience, this is oftentimes not the case, and you’re rewriting similar code over and over again.

Code run is not on VCS

The code that you run on the consoles is not pushed to your VCS(Version Control System):

  • If you want to reuse it you need to apply an extra process to ensure that happens.
  • If you need to audit what was done to a user’s data, you need to apply an extra process.

The ugly

MonkeyPatching

Sometimes, running your production code is not enough, and you are required to update some small portions of it to make it works for what you want to achieve. Ideally, you would change it permanently in the code, but, either it does not make sense for it to be a permanent change, or you can’t because you have made your code “so bad” that it’s impossible for you to cleanly execute the piece of code you need independently. This is not the fault of the consoles per se, but something noteworthy to say.

I have so many opinions about Monkey Patching alone that I’ll probably write something about it in the future.

DANGER, you might know this but Monkey Patching means all users accessing the same machine will see your change, so you should spin up other pods on which you should run the console instead. But if you’re running consoles as a common practice, you probably know this already, or you’re lucky enough to not have faced issues because of this (or you don’t know you have them now).

You don’t push directly into production, do you?

With consoles, you’re relying on the interpreter to yell at you when you’re doing things wrong, but sadly it can’t tell you whether your code passes other integration specs you might have failed if you had run your code against your test suite. Neither you’ll ask other peers for an opinion about such code, and worse even, if you’re not sharing such knowledge with peers in the code review cycle.

The industry already agreed tests and code reviews are necessary, why do I keep seeing teams following these bad practices then?

The sustainable way

The easy path

In my opinion, to fix problems properly, you need to face them to fix them for good. Patching things together works now, but it will get worse in the future.

  • If you use consoles because your CI/CD times are terrible and adding fixes or new scripts takes forever then fix that instead!
  • If you use consoles because you don’t have a way for your engineers to use the production code to run supportability scripts, then fix it! You might consider buying something like retool for this.
  • If you use consoles because your code is bad, and you need Monkey patching to run something, fix your code!
  • If you use consoles because…, FIX IT!

An alternative

At Intuit, our team had an internal API called the supportability API, that we used to run for special tasks or special migrations. It has several benefits:

  • You can audit who runs which task and for what purpose. In our case, these tasks required a JIRA ticket to be provided.
  • You integrate your existing best practices into these scripts, such as adding tests and code reviews.
  • You are keeping such scripts for future reference. Sometimes, these scripts are a one-off that you will throw away, but it might happen that you would refactor them to enable you to fix several production issues at once.
  • You’re running your own code, all the time, so you will most likely write code that you can reuse easily, keeping your code SOLID!

Was it perfect? Nope! But it was serving us well. In retrospect, it would have probably been worth investing into something that would have allowed us to safely run internal APIs or to wire our database together without much integration involved.

Although this approach was keeping us on our toes, ensuring that we had good reusable code with clean patterns, and making the whole team aware of the changes we made to the codebase.

Conclusion

Should you use REPL consoles in production? No, in my opinion, you should not. They don’t allow your team to grow and fix the real issues about your codebase. It also allows you to be careless about the quality of your code, and you might end up being really coupled with them. In the end, instead of being a cool tool to allow you to move fast, it will likely become something that won’t let you move forward.

If your team uses these, please work together to move away from them:

  • Write down who uses them for what purpose.
  • Document what script was run.
  • Run retrospectives on their usage and try to improve things so that you rely less on consoles.
  • Integrate tools like big query or retool to access your data safely without bringing your services down.

Thanks

I’d like to thank my wife Marie Dziubich for the help on this post (you definitely did not want to read the previous versions 🤣, although we are improving) and friends like Rubén Ángel Negrin Afonso with whom I’ve discussed this in the past.