Software Development from Apple iPad

Picture of me developing RetroBox on my iPad: Development on iPad

This post describes my current “work from iPad” setup. There are a few good reasons for using the iPad for software development:

  • The battery: iPad battery lasts days.
  • Portability: iPad is smaller and lighter than most laptops. And I can use it as an e-reader on the public transport too.
  • Drawing with the Apple pen: I do use the pen when I’m solving a maths puzzle and when I need to visualise something.
  • The screen: Although smaller than a laptop’s screen, the iPad screen is crisper and more readable than many laptops. In fact, as far as the pixel per inch (PPI) metric goes, I don’t know a laptop that has a better screen.

Hardware

  • The 2018 iPad Pro with an 11-inch display, and a storage of 64GB (https://support.apple.com/kb/SP784). I’ve never needed to upgrade my iPad even after 5 years. Apple built it too well.
  • The Apple Magic Keyboard. This does the job. Not the most ergonomic keyboard but its integration with the iPad is very good, and I do sometimes use its trackpad.
  • The Mac Mini (M2): This is the backend server of my dev setup. Cheapest one available on the market. The key feature for me is its low power consumption requirements. It is connected to internet via an ethernet cable. This ethernet connection is important as it allows the Mac to wake up when I ssh into it. I wasn’t able to get the “wake up upon request” featue working without the cabled ethernet connection. I use a powerline adapter (this one) to avoid laying cables around the flat.

Software

  • The Blink Shell app for iOS is really unparalleled at SSH. It works well with a display monitor too, if you connect your tablet to one.
  • Tailscale VPN. One Tailscale instance/client is installed on the OSX on the Mac Mini at home, another one on the iPad. You sign in with your email and can see all of your devices and their IP addresses connected to the VPN. The IP addresses you get on Tailscale are fairly static. This allows me to not worry about looking up the IP address of my Mac every time I ssh into it.
  • tmux (Backend): Tmux is really a requirement. If I lose my internet connection, my work won’t be lost because tmux will keep the work in a tmux session. I ssh into my Mac again, and run tmux a which attaches the new ssh session to the existing tmux session from before I lost connection, and everything is back as I left it.
  • ngrok (Backend): For serving HTTP
  • Editor: I have Neovim installed with the Vim Plug plugin manager. Here is my Vim Plug configuration with my favourite plugins:
    • NERDTree for managing files
    • CtrlP for fuzzy-finding files
    • vim-go for Golang
    • vim-clap: An experimental new addition to my library written in Rust. This does a lot of things! So far I’ve used it mainly for looking at Git history and commit diffs.
$ cat $HOME/.config/nvim/init.vim 


" Open file browser on the side when F is pressed twice in a row
nnoremap FF :NERDTreeToggle<CR>

call plug#begin()
" Multiple Plug commands can be written in a single line using | separators
Plug 'SirVer/ultisnips' | Plug 'honza/vim-snippets'

" On-demand loading
Plug 'preservim/nerdtree', { 'on': 'NERDTreeToggle' }
Plug 'tpope/vim-fireplace', { 'for': 'clojure' }

" Using a non-default branch
Plug 'rdnetto/YCM-Generator', { 'branch': 'stable' }

" Using a tagged release; wildcard allowed (requires git 1.9.2 or above)
Plug 'fatih/vim-go', { 'tag': '*' }

" Plugin options
Plug 'nsf/gocode', { 'tag': 'v.20150303', 'rtp': 'vim' }

" Plugin outside ~/.vim/plugged with post-update hook
Plug 'junegunn/fzf', { 'dir': '~/.fzf', 'do': './install --all' }

Plug 'kien/ctrlp.vim'

" Build the Rust binary if `cargo` exists on your system.
Plug 'liuchengxu/vim-clap', { 'do': ':Clap install-binary' }

" The bang version will try to download the prebuilt binary if `cargo` does not exist.
Plug 'liuchengxu/vim-clap', { 'do': ':Clap install-binary!' }

" `:Clap install-binary[!]` will always try to compile the binary locally.
" If you do care about the disk used for the compilation, use the way of force download,
" which will directly download the prebuilt binary even if `cargo` is available.
Plug 'liuchengxu/vim-clap', { 'do': { -> clap#installer#force_download() } }

" `:Clap install-binary[!]` will run using the terminal feature which is inherently async.
" If you don't want that and hope to run the hook synchorously:
Plug 'liuchengxu/vim-clap', { 'do': has('win32') ? 'cargo build --release' : 'make' }

" Initialize plugin system
" - Automatically executes `filetype plugin indent on` and `syntax enable`.
call plug#end()
" You can revert the settings after the call like so:
"   filetype indent off   " Disable file-type-specific indentation
"   syntax off            " Disable syntax highlighting