Setting up a Mac for Development

mac

Some months ago, I decided to treat myself to a new laptop / work machine, partly as an incentive to really get going with these Coding Adventures I am writing about in my other posts, and partly because I just cannot resist spending money for new tech.

Despite having built a somewhat powerful PC (AMD Ryzen CPU, NVIDIA GPU, 32GB RAM) during the beginnings of the COVID crisis around March 2020 (at least here in Germany), I soon came to the conclusion that I don’t want to code on a Windows machine. Setting up the programming environment and interacting with the terminal just seemed so much more complex and laborious than on a Unix-based system such as macOS or Linux. So I decided to leave my PC as an entertainment and gaming station and move all of my uni- and self-study-related work onto a new, portable machine.

Wanting to go full-nerd, I first thought about getting a Linux laptop and soon stumbled upon the extremely high value-for-money Pinebook Pro. Unfortunately (or fortunately in hindsight), the Pinebook was hopelessly out of sale due to the global chip crisis at that time and I had to come to terms with not getting my hands on this cool Linux laptop anytime soon.

So, having made really good experiences with Apple laptops in the past and with the introduction of the new powerful M1 Silicon chips, I finally got myself a 2020 MacBook Air. As a dev novice, setting up this beauty took a LOT of research (references are linked at the end) beforehand and I tried to agglomerate the best practices and setup tips, tailored to my needs, below.

Without further ado, let’s dive into the details of setting up a Mac for development. Again, be aware that I am a beginner in this field, so enjoy the contents below at your own discretion. I am always grateful for constructive criticism, so if I made some stupid mistakes, feel free to comment.

1. General Setup

Welcome Screen
Language
English
Country / Region
Germany
Preferred Languages
English (US)
Input Source
U.S.
Dictation
English (US)
Accessibility
Cognitive > Appearance > Dark
Ask Siri
disable

After the desktop environment has loaded, click on the Apple logo in the upper left corner > About This Mac > System Update… to get the latest macOS version.

System Preferences
Apple ID
iCloud > enable only 'Find My Mac'
General
Sidebar icon size: small; Default web browser: Chrome
Dock & Menu Bar
size: small (all the way to the left); position: Bottom; minimize windows: Scale effect; select 'minimize window into application icon'; select 'automatically hide and show the dock'; deselect 'animate opening applications'; deselect 'show recent applications in dock'; automatically hide and show the menu bar
Control Centre
Wi-Fi: deselect 'show in menu bar'; Battery: show percentage; Wi-Fi: Clock: use a 24-hour clock; Spotlight: deselect 'show in menu bar'
Spotlight
Search Results: deselect everything; Keyboard Shortcuts: uncheck
Language & Region
Preferred languages: English (US), delete 'English' > restart
Notifications
uncheck for every application
Keyboard
Keyboard > Key Repeat: fast; Delay until repeat: short; Keyboard > Modifier Keys... > Select 'external keyboard' and switch Option and Command Key; Text: uncheck 'correct spelling automatically'; Input Sources > U.S. International - PC (delete U.S.)
Trackpad
Point & Click > Tracking speed: fast
Mouse
Tracking speed: fast; Scrolling speed: middle-fast; deselect 'Scroll direction: Natural'
Display
Display > Scaled: more space; Night Shift > Schedule: Sunset to Sunrise
Sharing
Computer Name: 'M1'
Security & Privacy
General
'Require password immediately after sleep or screen saver begins'; Advanced > 'Require an administrator password to access system-wide preferences'
FileVault
turn on (note down recovery key)
Firewall
turn on
Safari
General: deselect 'open "safe" files after downloading'; Search: uncheck 'include safari suggestions'
Other
Finder
General: 'new finder windows show home directory'; Tags: delete all; Sidebar: 'show homedirectory', uncheck 'AirDrop'; Advanced: 'show all filename extensions', deselect 'show warning before removing from iCloud Drive'; ⌘+Shift+. to show all hidden files
Sidebar
sort Favorites to: User, Desktop, Downloads, Recents, Documents, Applications
Applications
Delete Apps
GarageBand, iMovie, Keynote, Numbers, Pages > empty trash
Clean up dock
remove everything except Finder, Trash

2. Terminal Setup

2.1. iTerm2

Download and install iTerm2 and choose the following settings in Preferences:

General > Closing
uncheck 'confirm closing multiple sessions' and 'confirm Quit iTerm2'
General > Profiles
new profile; Other Actions: set as default; Working Directory: 'reuse previous session's directory'; Window: Columns 125, Rows 35; Keys: locate ⌥← shortcut and set to 'send escape sequence' > Esc+ b (enables to skip words by ⌥←); Keys: locate ⌥→ shortcut and set to 'send escape sequence' > Esc+ f (enables to skip words by ⌥→); Keys: record new ⌘← shortcut and set to 'send escape sequence' > Esc+ OH (enables to skip to start of the line); Keys: locate ⌘→ shortcut and set to 'send escape sequence' > Esc+ OF (enables to skip to end of the line)

2.2. XCode CLT

In the terminal, install command line tools for XCode:

xcode-select --install

2.3. Homebrew

Homebrew is a package manager that enables very easy installing of programs and dev tools via the command line, similar to sudo apt install on a Linux system.

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Afterwards, homebrew needs to be added to the PATH environment variable:

echo 'PATH="/usr/local/bin:$PATH"' >> ~/.bash_profile
echo 'PATH="/usr/local/bin:$PATH"' >> ~/.zshrc

Reload the shell:

eval "$(/opt/homebrew/bin/brew shellenv)"

Close and reopen the terminal. Now, you can test the brew doctor command to see if everything has been installed correctly and homebrew works as expected. For future housekeeping, it is advisable to regularly call the following commands:

brew update
update package definitions (formulae) and homebrew itself
brew upgrade
upgrade all packages (kegs) and homebrew itself
brew cleanup
removes old versions of formulae and small kegs

2.4. ZSH

Though zsh has replaced the bash shell on the newer macOS distributions and should already be the default, you would install it via the following command:

brew install zsh

2.5. Git

Git is the version-control-system of choice in the industry, so I do not dare to question it or other alternatives. Since I will be using GitHub to remotely store my projects, learning to work with Git is imperative.

brew install git

This step is optional, but when setting up my Mac, I shamelessly copied the .gitconfig file from the user nicolashery as recommended in his dev setup article.

cd ~
curl -O https://raw.githubusercontent.com/nicolashery/mac-dev-setup/master/.gitconfig

Set username and mail to the same credentials as on your GitHub:

git config --global user.name "username"
git config --global user.email "yourmailaddress"

Enable colors in the output:

git config --global color.ui auto

2.6. SSH for Git & GitHub

In order to seamlessly pull and push repositories from and to your GitHub, you’ll have to setup SSH. First, create a new public-private-key pair:

ssh-keygen -t ed25519 -C "yourmailaddress"

Hit Enter three times and then start the ssh-agent:

eval "$(ssh-agent -s)"

Modify the ~/.ssh/config file to automatically load keys into the ssh-agent and store passphrases in the keychain. If it does not exist, create it …

vim ~/.ssh/config
  • hit i to enter insert mode
  • hit Esc to exit the current mode
  • hit :wq to save and quit
  • hit :q! to force quit without saving changes

… and add the following to the config file:

Host *
    AddKeysToAgent yes
    IdentityFile ~/.ssh/id_ed25519

After saving and quitting the file (:wq), add the key-pair to the ssh-agent:

ssh-agent ~/.ssh/id_ed25519

Now, add the public key to GitHub by copying it into the clipboard …

pbcopy < ~/.ssh/id_ed25519.pub

… and pasting it in your GitHub account settings > SSH and GPG keys > New SSH key as SSH-ed25519. Finally, test the ssh-connection via:

ssh -T git@github.com

If something does not work, you can always refer to the official docs here.

2.7. Oh My ZSH

After all this hard work, it is finally time to pimp your zsh shell. For this, download the Oh My ZSH configuration framework:

sh -c "$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

Install the following plugins: autosuggestion, syntax-highlighting, powerlevel10k that will supercharge your terminal workflow.

git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-syntax-highlighting
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k

Now, add these plugins inside the ~/.zshrc file via Vim (see above).

ZSH_THEME = "powerlevel10k/powerlevel10k"
...
plugins = (# other plugins... zsh-autosuggestions zsh-syntax-highlighting)

Restart the terminal and go through powerlevel10k’s setup, then restart again.

2.8. Terminal Color Preset

Since I really like the Atom One Dark theme, I downloaded it for iTerm2 and set it as my color preset of choice.

cd ~/Downloads
curl -o "Atom One Dark.itermcolors" https://raw.githubusercontent.com/nathanbuchar/atom-one-dark-terminal/master/scheme/iterm/One%20Dark.itermcolors

Within iTerm2, go to Preferences > Profiles > Colors > Color Presets > Import > Import the downloaded theme. Make the colors work via:

echo -e '\n# Add colors to Terminal\nexport CLICOLOR=1\nexport LSCOLORS=ExFxBxDxCxegedabagacad' >> ~/.zshrc

2.9. Vim

For my command line editor of choice, I downloaded the following default settings. If you want to go into even more customization, this link might be helpful.

mkdir -p ~/.vim/pack/tpope/start
cd ~/.vim/pack/tpope/start
git clone https://tpope.io/vim/sensible.git

3. Brew installs

With your terminal now being a beautiful and highly optimized tool, you can now simply brew install the rest of your favorite apps. For me, these were:

Coding Apps
Local
brew install --cask local (for easy WordPress website hosting & editing)
MacTex
brew install --cask mactex, deinstall TeXShop, LaTeXiT, TeX Live Utility & BibDesk
MySQL Workbench
brew install --cask mysqlworkbench
VSCode
brew install --cask visual-studio-code (IDE of choice)
Standard Apps
Chrome
brew install --cask google-chrome, extensions: DarkReader, HTTPS Everywhere, Privacy Badger, uBlock Origin
Discord
brew install --cask discord
Edge
brew install --cask microsoft-edge, extensions: same as chrome
NordVPN
brew install --cask nordvpn
Obsidian
brew install --cask obsidian
Spotify
brew install --cask spotify
Whatsapp
brew install --cask whatsapp
Zoom
brew install --cask zoom
Other Apps
Alfred
brew install --cask alfred, Appearance > Alfred Modern Dark Theme; Hide hat on Alfred menu; Hide menu bar icon (more sophisticated spotlight search)
Archey
brew install archey (terminal gadget for some key specs)
Menumeters
brew install --cask menumeters, Preferences > CPU: horizontal bar; Disk: disable; Memory: used/free totals; Network: disable (stats monitoring)
Spectacle
brew install --cask spectacle, Preferences > launch at login: run as background application (resizing windows)

4. App Store / Web installs

There are some apps that cannot (yet) be installed via homebrew. For these, just download via the App Store or the Web. For me, these were:

Gestimer
open at login, show countdown in menu bar (timer widget)
Google Drive
delete Google Docs, Sheets & Slides (Cloud service of choice)
Microsoft Office
only Word, Excel, PowerPoint
Spark Mail
(Mail client of choice)

5. Programming Languages & VSCode Extensions

5.1. Python

Since I will be mainly coding in Python, getting the setup with different environments for different projects right, posed a crucial step in the dev setup. Before knowing any better, I installed pyenv to manage different Python versions and libraries without altering the system Python version. This step proved to be unnecessary since Miniforge (the smallest and leanest distribution of the Python package manager Anaconda) works in the Terminal as well as in VSCode, my IDE of choice. Thus, I can only recommend to skip the whole pyenv shenanigans and simply install Miniforge as follows:

brew install miniforge

Next, install the Jupyter environment:

conda install -y jupyter

Activate conda for the shell via:

conda init zsh

Then, restart the terminal. Python packages can then be installed in their very own conda environment, either via conda install packagename or pip install packagename (oftentimes easier). To leverage the M1 chip’s Neural Engine for Machine / Deep Learning tasks, these videos are a good starting point:

5.2. MySQL

First, simply brew install MySQL:

brew install mysql

Then, start the MySQL server in daemon mode* via:

brew services start mysql

Since no root password has been set by default, it is advisable to run the following securing procedure (just answer all questions with y):

mysql_secure_installation

After that’s done, stop the mysql server (since daemon mode* might not always be the preferred choice):

brew services stop mysql

Now, simply start the MySQL server via mysql.server start and stop it with mysql.server stop. If you’re not sure whether your server is running or not, you can always call mysql.server status for information on that. After starting the server, you can connect to it as root via:

mysql -u root -p

5.3. WordPress

By far the easiest way I’ve found to install WordPress and all its dependencies (Apache/Nginx, PHP, MySQL) is to brew install Local as seen above.

In fact, this website is also being developed locally via Local and WordPress and is published via the free GitHub Pages service. You will just have to create a public repository on your GitHub and a gh-pages branch. Then, simply convert your WordPress website via this plugin into static content und push the files to your repository. This tutorial provides more detail on the process.

5.4. LaTeX

Most of the work for getting LaTeX to run on the MacBook has already been done before by brew installing MacTex. Now, you will only need to update LaTeX via:

sudo tlmgr update --self

To work with LaTeX, simply create a .tex file in VSCode and hit ⌘+s to save and generate the .pdf file.

5.5. VSCode Extensions

This step is totally optional and depends a lot on your own preferences. I slightly altered VSCode’s default preferences like this (Code > Preferences > Settings > Open Settings (JSON) and paste …):

{
  "editor.tabSize": 2,
  "editor.rulers": [80],
  "files.insertFinalNewline": true,
  "files.trimTrailingWhitespace": true,
  "workbench.editor.enablePreview": false
}

My extensions:

Atom One Dark Theme
by Mahmoud Ali
GitLens
by GitKraken
Jupyter, Jupyter Keymap, Jupyter Notebook Renderers
by Microsoft
LaTeX Workshop
by James Yu
Markdown All in One
by Yu Zhang
Pylance, Python
by Microsoft
Rainbow Brackets
by 2gua
Remote - SSH, Remote - SSH: Editing Configuration Files
by Microsoft
vscode-icons
by VSCode Icons Team

Also, press ⌘+SHIFT+P > Shell Command: Install ‘code’ command in PATH. This enables to quickly open up VSCode by typing code . in the terminal.

6. Final Touches

Whew, if you’ve come this far, it means you now have a really well set up machine for coding and software development – congrats!

This section just briefly goes over some final touches:

  • go over Notifications & Menu Bar again (enable notifications only for Gestimer)
  • sort the applications in the launchpad via:
defaults write com.apple.dock ResetLaunchPad -boolean true; killall Dock
  • set the dock delay to 0 for instant response:
defaults write com.apple.dock autohide-time-modifier -int 0; killall Dock
  • set up archey to start together with the terminal (set p10k configure instant prompt to quiet):
echo archey -c >>~/.zshrc

Now, when starting up your terminal, you will be greeted by some information on your system:

Archey specs on Terminal startup.

7. Project Workflow

It is always good to have some sort of structure in your projects. For my part, I created a new folder titled Projects in my home directory for everything code-related, and I am using the already existing Documents folder for my Obsidian vaults and LaTeX projects.

7.1. Git & GitHub Primer

When starting a new project that you want to have version control over, first create a repository for it on GitHub. Then, copy the link under Code > SSH (looks like git@github.com:username/repositoryname.git) and in the terminal call:

git clone git@github.com:username/repositoryname.git

Now, you can freely add / create files locally in the project folder, and once you’re done, just hit

git status

to see which files need to be added and which to be committed. You can group several files via …

git add file1 file2 file3

… into one commit for better readability in the version log. Then, commit with:

git commit -m "message"

And finally, push the changes to your remote GitHub repository:

git push

If you are working on a shared repository together with other developers, you can pull the most recent version of this repository to your local folder via:

git pull

It is good practice to set up a .gitignore file to specify file types that you want to keep in your local directory, but not upload to your remote repository, for instance large .pdf files, .csv or .xlsx files, .swp, .DS_Store, and so on. Just call vim .gitignore in the terminal when you’re inside your project folder and add the file types to be ignored.

7.2. Conda Environments Primer

Speaking of good practice, it is also always a good idea to separate your programming projects and corresponding packages in their very own environment. We already installed Miniforge to manage our Python environments before. To set up a new environment with the same packages as the base environment, simply call:

conda create --name yourenvironment --clone base

Before the environment can be used, it first needs to be activated:

conda activate yourenvironment

Once activated, you can install Python packages either via conda install packagename or pip install packagename into this environment. It is advisable to keep a requirements.txt file with all the installed packages and their version number to make it easy for others to download and run your code without problems (pip install -r requirements.txt). The pipreqs package is a handy tool for automatically creating such a requirements.txt file.

After coding on a bigger project myself and watching other developers on YouTube, I also made it a habit to create a config.py file to store e.g. API URLs / keys, passwords, etc. that are needed throughout the project and a utils.py file to outsource my function definitions. Just don’t forget to import these files into your main.py / main.ipynb!

7.3. MySQL Database Primer

If your program needs to read / write a lot of data, you might want to consider building a database for it. I already discussed the initial setup of a MySQL server above, so we will continue from there.

After starting up your MySQL server (mysql.server start) and logging in as root (mysql -u root -p), you can list all existing databases via:

SHOW DATABASES;

For creating a new database, call:

CREATE DATABASE yourdatabase;

To use it, call:

USE yourdatabase;

If you’re really interested in building a database yourself, you might want to head over to my post about Building up a Securities Master Database, where I go into more detail of actually creating tables within a new database. To view all tables in the database, call:

SHOW TABLES;

And to  get a more detailed view on a specific table within the database, call:

DESCRIBE tablename;

Once you’re done, you can quit the MySQL server session by simply calling:

QUIT

Don’t forget to stop the server (mysql.server stop) before shutting down your computer.

If your database is being used by other people than yourself, you might want to create dedicated users for them (and not let everyone act as root on the database). To do so, simply log in as root, create the new user and grant them privileges as follows:

CREATE USER 'username'@'hostname' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON *.* TO 'username'@'localhost';
FLUSH PRIVILEGES;

8. All Done!

Setting up a new coding machine and especially interacting so much with the terminal can be intimidating if you have never done it before, but it is so rewarding being able to completely customize your shiny new hardware to your own needs. Setting up my very own MacBook, I learned so much – from terminal jargon, bash/zsh shells, version control & SSH, to coding within a terminal editor, getting different programming languages to work and finally bringing everything together in an exciting project.

I hope this guide gave you some valuable insights and might help you in setting up your own machine. Please also take a look at the references section below.

 

Thank you for reading 🙂

Cheers, Niklas