Using Rake for Executable Build Specification
Tags: ruby, scripting
Published: 2021-05-12 17:16:17

When developing, I find that I need to execute certain tasks from the command line. More often than not these commands must be executed in a definite order, which may be hard to remember, especially when you need to come back to it after a while away. For example, I may need to build a special docker container and upload it to AWS ECR:
```
$ docker build --build-arg NAME=Polar -t hello:latest -f Project.dockerfile .
$ docker tag hello:latest 111111111.dkr.ecr.us-east-1.amazonaws.com/hello:latest
$ aws ecr get-login --region us-east-1 --no-include-email 
$ docker push 111111111.dkr.ecr.us-east-1.amazonaws.com/hello:latest
```
Usually, this command sequence, if documented at all, is placed in a ***README.md*** in the source code directory for the benefit of future developers or even the current developer. Notably, this ***README.md*** file would be considered a _specification_.

I am a big fan of _executable specifications_. ***README.md*** files are needed and sometimes required by corporate/development policy. However, they may be subjected to "comment rot," as they are, in fact, comments. 

What is "comment rot," you ask? How many times do you make a change to code or an idea in a project, and you do not update the comments? Sacrilege! I know! 

![Shame](https://media.giphy.com/media/W81qSImkIxkNq/giphy.gif)

Comment rot happens a lot more than you would think. So, placing the required commands in an executable makes them useful. They can be read and understood by a future developer, and in the very least, they are specified with a defined semantic. Plus, it has the added benefit of being simpler to execute. 

There are many ways to invent such a capability, such as writing (bash, CMD, Powershell) script files, or to use some other interface based tool, such as "Rake".
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ouigs5slkbpc8cobvbi8.jpg)
"Rake" is a RUBY based build tool loosely fashioned after "Make", which is a popular dependency based build tool from the Unix era. Thus, "Rake" is probably short for "Ruby Make." Rake has a defined command line interface and is Domain Specific Language (DSL) for executing interdependent tasks. In fact, they are called "tasks". 

I do not want to get into the specifics of using "rake" here as there are many tutorials on that subject. I just want to state that a good way to create an executable specification of what needs to be done for a project is to use the rake tool. Aside from having the dependency based execution of Rake, you also have the entire RUBY language and gems available to you. I find writing bash scripts to be cumbersome, and Powershell scripts to be down right ugly. Using RUBY to run through loops and process lists is, IMHO, better than using bash or powershell, which I find so oblique, I have to look it up all the time. You may even use rake so that the execution can be made to be portable between Linux and Windows.

It does not matter what language I am writing a project in, whether it is Ruby, Javascript, Typescript, C++, BCPL, Julia, etc. I usually always have ruby/rake installed on my development machine, and I use that to specify and keep track of the command line tasks I must execute in running, testing, and deploying within the project.

As to my example above, the build specification may just be as simple as creating a `Rakefile` in the top level directory that contains the following:
```
desc "Build the project docker and push it to AWS."
task :build_and_push do 
  sh "docker build --build-arg NAME=Polar -t hello:latest -f Dockerfile ."
  sh "docker tag hello:latest #{ENV["ACCOUNT"]}.dkr.ecr.us-east-1.amazonaws.com/hello:latest"
  sh "aws ecr get-login --region us-east-1 --no-include-email"
  sh "docker push #{ENV["ACCOUNT"]}.dkr.ecr.us-east-1.amazonaws.com/hello:latest"
end
```
And then when you need to, you can issue the following command sequence:
```
$ rake -T
build_and_push    Build the project docker and push it to AWS.
```
To find out what the commands are, and then issue the following from the command line to execute it:
```
$ rake build_and_push
```
It is as simple as that. As time goes on, such as if the docker tags change, or they are variable, you have the entire Ruby language to be able to parameterize the tasks using a defined executable language.
![Be Careful](https://media.giphy.com/media/H8a2kvphhXZde/giphy.gif)
NOTE: As seen above, you should *NOT* put sensitive information such as AWS account numbers, passwords, etc. into a file like this, `Rakefile` or otherwise, that gets checked into source code control, especially GitHub. You can see this precaution by my use of an environment variable "ACCOUNT".