Bad software fails. Good software fails gracefully.
No matter how stable you believe your software to be, it will inevitably fail. Most likely, it will fail in the middle of doing something really important.
Imagine you are building an online store. Your system accepts orders, processes payment information, and notifies the warehouse to fulfill paid orders. Your system makes customers happy by simplifying the process of buying what they want. Of course, you’re a great developer and you have done everything you can to ensure the system works well and makes customers happy. Your code is well-tested, and you’ve ensured that no action taken by end users will disrupt the flow of money and purchased goods. But your code is not the only piece of this system.
You are likely using a payment gateway like PayPal or Stripe to process payments. Your software relies on the payment gateway to tell you if a payment has been successfully processed. Perhaps a network outage or other problem prevents the payment gateway from telling you this, but a customer’s payment was indeed processed successfully. What happens to your customer? Their money has been taken, but you have not notified the warehouse to fulfill their order!
Most modern databases have a way of handling this problem through transactions. A transaction ensures that a unit of work is completed successfully. Every change you wish to make will be done, or no changes will be done. Transactions prevent the possibility of completing only part of the work. In other words, a transaction can be considered an atomic unit of work.
In the database world, transactions have another benefit: grouping commands together as a single unit of work affords you some time savings. Instead of opening multiple database connections to insert several records, a transaction will insert all desired records in one fell swoop. Ruby on Rails exposes this behavior through Active Record Transactions. Active Record also automatically rolls back database changes in the event of an unsuccessful transaction. Unfortunately, this only applies to database operations.
My gem, Up And At Them!, brings atomic transactions to general Ruby code. It enables you to define blocks of Ruby code that need to be executed, and to describe how to roll back changes made by each command you need to execute. In the event that only some of your code is successfully executed, the rollback code will be executed automatically.
The benefit to you as the online store developer is that you can automatically deal with the order fulfillment problem. You now have the ability to detect failures in notifying the warehouse of a new order and act upon that failure (e.g., automatically refund the customer and escalate the ordering issue to a support representative).
There are countless other applications for transactions. Electronic medical record systems, file synchronization services, code generators, unit test frameworks, point-of-sale systems, media players, and video games – just to name a few – all include components that benefit from atomic transactions. Any time you require several things to happen together, you should treat those things as an atomic unit of work, a single transaction.