I enjoy automating tasks that take time and effort to do manually. By automating these workflows, I’m able to help out my teammates to free up time to focus on other things that are important. I recently automated a task to retrieve emails from a database and then add the emails to a database and then upload them to Box, a cloud storage service.
So I created a Ruby script to automate the process which I did fairly quickly. Although I wrote the script in a fair amount of time the quality of the code wasn’t good, it was awful. I wasn’t going to let that piece of software in that state so I decided to be guided by Object Oriented Design principles and refactor that piece of code that didn’t let me have a good night sleep.
When I turn around and look at the above code I see a lot of dependencies, different concerns being mixed, and a lack of clarity of whats going on. Now, let’s think about the different tasks this software is doing.
- Configuration
- File Backup
- File Upload
Now when discussing configuration, we can use OpenStruct which is a data structure similar to a hash. This way we can add all the configuration and have it in one place. Adding clarity and cohesion to what the configuration is and what it intends to achieve.
This is so much better already, I can now get the year from config.year
.
In this way improving readability and increasing cohesion in the configuration.
Now the other concern is the file backup. We can improve by creating a class with follows the single-responsibility principle of backing up the file.
Notice how we use Dependency
Injection
passing DateTime
as an argument into the BackupFile
class.
Then we have the other concern of Upload. Now imagine you wanted to use
Dropbox
or any other cloud storage service? We can create a class that takes
any client as a parameter and we can use dependency injection to pass the cloud
storage’s client as an argument into the class.
Notice here how I used the Adapter Design
Pattern To match the BoxApi
interface to the Uploader
class. If we wanted to use Dropbox, we would just
need to create a DropboxAdapter
or OtherStorageServiceAdapater
. We can now
also use dependency injection to pass these clients and not be tied to one
specific clod storage service, like this:
Uploader.new(BoxAdapter.new(args),file.full_path, config.box_folder_id)
which is much better.
Now the runner script is much cleaner and better.
We have touched on different Object Oriented Design principles that have increase the quality of the code bringing the software to a state where dependencies are managed and more adaptable to future changes.
Shout out to Christian Bruckmayer for his mentorship and feedback. Fun fact I wrote this blog while listening to Que No Quede Huella it reminds me of back home!