I define it so that you:
That gives you a macOS empire and turn you into a Ruler 👑
In this story, I’ll explain how building a macOS empire came to me, how I built mine, and how you can build yours.
It originated from health concerns. My wrists started to hurt a few months ago due to pushing way too many buttons for money and too much mouse usage. I fixed the physical aspect of the problem by sitting properly in my chair and purchasing an ergonomic keyboard, but the mouse usage strain remained. So I decided to eliminate mouse usage as much as I can.
Fish shell, Vim text editor, and Tmux terminal-multiplexor were the solutions I picked for myself. This meant hundreds of shortcuts and configurations I had to tweak and manage. So I put my Fish, Vim and Tmux config files in my configurations repository, also known as
It wasn’t until I was gifted a new MacBook however that I realized there’s a whole lot more to setting up a fresh macOS than just having my most frequently used applications config files in my
Dotfiles repository. A package manager, all the applications to install with that package manager, system preferences, shortcuts for those applications and more had to be done. I ended up doing so much manual work to set up the gifted MacBook that my inner-automation-child refused the prospect of having to do it again. I decided to automate it. I decided to build a macOS empire and be the Ruler of it.
I asked myself what do I want in a software that would set up my macOS software development environment entirely, and the rest followed smoothly. The wisdom behind that question doesn’t deserve to be credited to me, however.
If I would be given an opportunity to write the most important concept I learned in software development in 2017, I would write the law of user focus. I quote directly from Fish shell design document:
When designing a program, one should first think about how to make an intuitive and powerful program. Implementation issues should only be considered once a user interface has been designed.
So, “What do I want in a software… “ question is essentially similar to asking “What kind of user interface I would like to have?”. The answer was such that I liked the interface to:
With those interface requirements in place for the software I was going to write, I created a macOS bootstrapping bash script called
setup-mac-os.sh in my
Dotfiles repository which printed “Hello World!”. macOS comes with bash shell by default so the script will be executable on a fresh macOS. I also updated the
README.md with a one-liner command to execute that
setup-mac-os.sh bash script. Keeping the no manual intervention in mind, all requirements were fulfilled.
After setting up a virtual macOS High Sierra and taking a snapshot from it, I was ready to implement the steps necessary to setup my macOS one at a time. Throughout this process and while going through almost all repositories featured on dotfiles.github.io , I learned some best practices and some pitfalls to avoid which I’d like to share. Let’s begin.
I found several macOS bootstrapping scripts in featured repositories on dotfiles.github.io that were just a blob of code with an attempt to be readable with visual comments. While visual comments are helpful visually, they offer no code modularity and they’re difficult to debug. With a function-based approach, you can comment out the steps you’d like to disable quickly, you can test each step individually using a virtual macOS and leveraging snapshots to ensure all steps run without errors, and you can make sense out of what you did both now and in the future. Top-to-bottom approach also increases readability of your script and saves people time when they want to familiarize themselves with what your script actually does.
I promised myself as a 2018-new-year resolution to memorize all the options for
grep command-line application. One by one.
--byte-offset and so on. Said no one ever.
Do everyone a favor and write command-line application options in full. This makes a visit to the terminal, typing
man <APPLICATION>, navigating to the option, and seeing what on earth it does unnecessary if you would be kind to type the options in full. Short-hand options are for running ad-hoc commands. I also write
grep -Fxq if I want to find out if a file contains a line in bash, but not when writing a script from which I see a potential of people looking at it and trying to make sense out of it.
“Press RETURN to continue…”. Fairly disappointing. If only the Homebrew installer could parse and respect an option, say,
--no-prompt, then I wouldn’t have had to remove its interactivity myself in a custom homebrew_installer script, which is identical to the original installer with the exception of a single line of code removed. So, don’t be afraid to change other people’s code to bend it at your will for your scripts, because when using your macOS bootstrapping script, you’ll want to be singing “I don’t want control, I want to let go” as P!nk puts it; remove the interactivity, so you can sit back and let go.
Think of the steps of your macOS bootstrapping script and determine which ones prevent you from repeatedly executing the bootstrapping script and write those steps in another script. For example, I use some Vim plugins which need to be compiled to work, and the compilation takes around 2 minutes. There’s no way I could put them in my bootstrapping script and be able to execute it repeatedly as it takes way too long. Instead, I have an executable function in my shell which compiles those plugins which I need to run once for a fresh macOS or if I update the plugins.
This frequent execution of your bootstrapping script will allow it to evolve slowly and steadily, and prevent it from going out of date, if you commit to it. So, for example, if you save a new configuration file and you want to symlink it, do it in your bootstrapping script and then execute it instead of doing it manually.
Homebrew’s installer can install
xcode-select without any GUI popping up, i.e. headlessly, which is nice. Quite a few
Dotfiles repositories instructing to install
xcode-select before installing
brew, which is unnecessary given Homebrew’s installer ability to do it without interactivity. It’ll fall back to GUI installer of
xcode-select in case of failure to install it headlessly.
Don’t write orchestration logic for all the system-wide packages you would like to install in a bash script. Use a
Brewfile and install the packages within it with a simple:
brew bundle. This way, you can have a versioned file in your
Dotfiles repository and you immediately get all the benefits of git like
brew bundle cleanup and you’ll always have exactly what you define in your
Brewfile installed on your macOS.
Make a conscious decision about your primary shell. I had been using bash since it was the default on macOS anyway. I switched to
zsh and it blew me away, I was suddenly a lot more productive. I switched to
fish after a year of
zsh and I couldn’t believe I could be blown away again, but I was wrong. Going through the features of these different shells is outside the scope of this story, but do your own research and choose one. I recommend fish.
Configurations are personal. They’re meant to be tweaked to supreme levels. Think twice before forking someone else’s
Dotfiles repository and using it for yourself. Remember that applications evolve and so their default options. The tweaks someone has done for their Tmux two years ago could as well be the default for Tmux in its latest version today or have been removed entirely. Use your own configuration files, get inspired by other people’s
Dotfilesrepositories, understand them, copy them for yourself, and tweak them if necessary.
Keep an executable function handy that updates “everything”. You get to decide what to update, but a good starting point would be all software updates from the App Store and all installed packages using
Dotfilesrepository, if you don’t have one yet.
README.mdto execute a macOS bootstrapper bash script.
Link to original story on Medium: https://medium.com/@Sajjadhosn/build-a-macos-empire-a0c83879ac24