Reading List
The most recent articles from a list of feeds I subscribe to.
Construction Lines
I recently stumbled across The Oatmeal’s series on Creativity. While all of it is spot on, the part on erasers hit especially hard.
“There is a lot of shame associated with backpedaling; things like quitting your job, getting a divorce, or simply starting over are considered shameful.
But forward isn’t always progress.
And backward isn’t always regress.
Sometimes going down the wrong path isn’t a mistake — it’s a construction line.”
It was exactly what I needed to hear. You see, only a few days prior, Font Awesome and I had parted ways — the end of a short, but transformative chapter. I’m proud of what we built together, and grateful for what I learned along the way. But it was time to move on.
Jobs are a lot like relationships. They often start with infatuation — and end with the realization that you’re simply not compatible, and that’s no-one’s fault. Letting go always stings, even when it’s the right call. There’s always grief: when you’re not ready to move on, you grieve the bond; when you are, you grieve your expectations. But every ending leaves behind clarity — about who you are, and what makes you happy.
The pursuit of happiness
Today is my 39th birthday — and this summer marks 20 years since I first dipped my toes into this industry. Naturally, I’ve been doing a lot of reflection.
As is typical for ADHDers, I have done a ton of different things, and built a diverse skillset as a result. But what made me happiest? The list of highs went a bit like this:
- Entrepreneurship: Co-founding a startup and driving it to become a household name (in Greece — this was 2008!)
- Consulting: Being a full-time consultant, speaker, and author, traveling the world and jumping from one exciting gig to another
- Academia:[1] Pushing the boundaries of Human-Computer Interaction at MIT and teaching MIT CS students to care about people.
All had three things in common: autonomy, breadth, and impact.
These three things have been the biggest predictors of happiness for me — far more than income [2] or work-life balance, which are the usual suspects.
I used to aspire to work-life balance in the same way I aspired to frequent exercise — because it was good for me, not because it gave me joy. Eventually I realized that what makes me happy isn’t working less, it’s loving what I do, and feeling it matters. Working less cannot transform how your work makes you feel; it can only dampen the effects. But dilution doesn’t turn misery into joy — at best it just makes it tolerable. Don’t get me wrong, poor WLB can absolutely make you miserable; when long hours are an externally imposed expectation, not an internal drive fueled by passion. As with many things in life, it’s enthusiastic consent that makes all the difference.
Then there’s breadth. Most jobs try to box you in: PM or engineer? Scientist or practitioner? UX Researcher or designer? DevRel or standards? And I’m like…
Aurora is my spirit animal 🫶🏼 Source
It’s silly that people are forced to choose, and present themselves as less than to seem more attractive to hiring managers. To use myself as an example:
- Web architecture: I have designed several web technologies that have shipped across all browsers. I’ve spent 4 years in the TAG, reviewing new web technologies across the web platform, and eventually leading the Web Platform Design Principles effort.
- Product/usability/HCI: Prior to working as Product Lead at Font Awesome, I’ve earned a PhD at MIT in Human-Computer Interaction with a minor in Entrepreneurship & Innovation. I published peer reviewed papers in top-tier HCI conferences, and co-created/taught a course on usability & web technologies that is now a permanent subject. I have run user research for scientific and industry projects. I have started several open source projects, some used by millions. In the more distant past, I co-founded a (then) well-known social startup in my home country, Greece and ran product, engineering, and design for three years (six if you count pre-incorporation).
- DevRel: I’ve given over 100 conference talks, published a bestselling book on CSS, and was the first devrel hire at W3C back in 2012. I have built dozens of apps and polyfills that stimulated developer interest in new Web features and drove browser adoption.
Should I present myself as a web architecture expert, a usability/product person, an HCI researcher, or a Developer Advocate?
What a pointless dilemma if I ever saw one!
Combining skills across different areas is a strength to be celebrated, not a weakness to be swept under the rug. The crossover between skills is where the magic happens. Off the top of my head:
- Understanding usability principles has made me a far better web standards designer.
- Web standards work is product design on hard mode. After the impossibly hard constraints and tradeoffs you deal with when designing APIs for the Web platform, regular product problems seem like a cakewalk (we have versions? And we can actually change things?? And we have reliable metrics?!? And the stakeholders all work at the same company?!? 🤯).
- They often feed into each other: DevRel work made me a better communicator in everything I do. Usability made me a better speaker and educator[3], so a better developer advocate too.
- Leading the Web Platform Design Principles convinced me that explicit design principles are immensely useful for all product work.
- Web standards taught me that contrary to popular belief, you do not need a benevolent dictator to ship. But then you do need a good process. Consensus does not magically grow on trees, building consensus is its own art.
Lastly, impact does not have to be about solving world hunger or curing cancer. Making people’s lives a little better is meaningful impact too. It all boils down to:
You can achieve the same total impact by improving the lives of a few people a lot, or the lives of many people a little. For example, my work on web standards has been some of the most fulfilling work I’ve ever done. Its Individual Impact is small, but the Reach is millions, since all front-end developers out there use the same web platform.
What’s next?
Since consulting and entrepreneurship have been my happiness peaks, I figured I’d try them again. Yes, both at once, because after all, we’ve already established that WLB is a foreign concept 🤣
My apprentice Dmitry and I have been in high gear building some exciting things, which I hope to be able to share soon, and I feel more exhilarated than I have in years. I had missed drawing my own lines.
In parallel, I’m taking on select consulting work, so if you need help with certain challenges, or to level up your team around web architecture, CSS, or usability, get in touch.
Don’t get me wrong, I’m not closing the door to full-time roles. I know there are roles out there that value passion and offer the kind of autonomy, breadth, and impact that would let me thrive. It’s the ROI of digging through rubble to find them that gives me pause — as a product person at heart, I/E tradeoffs are top of mind. But if you have such a unicorn, I’m all ears.
I also finally took a few small steps to make my pro bono work financially sustainable, a long overdue todo item. Both pages still need work, but you can now support my writing via ko-fi[4], and my open source work via GitHub Sponsors. I made separate pages for my two most popular projects, Prism (nearing 1.8 billion total npm installs! 🤯) and Color.js. This is as much about prioritization as it is about sustainability: money is an excellent signal about what truly matters to people.
I don’t have a polished “next” to announce yet.
But I’m exactly where I need to be.
Sometimes the clearest lines are the ones drawn after you erase.
Many things wrong with academia, but the intellectual freedom is unparalleled, and it makes up for a lot. ↩︎
See also Alan Watts’ “What if money was no object?” — a classic, but still relevant. ↩︎
Teaching is absolutely a form of UI design — a UI that exposes your knowledge to students — the users. There are many similarities between how good educators design their material and how good UI designers design interfaces. ↩︎
Thanks Dan Abramov for the wording inspiration (with permission). These things are so hard. ↩︎
Using `make` to compile C programs (for non-C-programmers)
I have never been a C programmer but every so often I need to compile a C/C++
program from source. This has been kind of a struggle for me: for a
long time, my approach was basically “install the dependencies, run make
, if
it doesn’t work, either try to find a binary someone has compiled or give up”.
“Hope someone else has compiled it” worked pretty well when I was running Linux but since I’ve been using a Mac for the last couple of years I’ve been running into more situations where I have to actually compile programs myself.
So let’s talk about what you might have to do to compile a C program! I’ll use a couple of examples of specific C programs I’ve compiled and talk about a few things that can go wrong. Here are three programs we’ll be talking about compiling:
step 1: install a C compiler
This is pretty simple: on an Ubuntu system if I don’t already have a C compiler I’ll install one with:
sudo apt-get install build-essential
This installs gcc
, g++
, and make
. The situation on a Mac is more
confusing but it’s something like “install xcode command line tools”.
step 2: install the program’s dependencies
Unlike some newer programming languages, C doesn’t have a dependency manager. So if a program has any dependencies, you need to hunt them down yourself. Thankfully because of this, C programmers usually keep their dependencies very minimal and often the dependencies will be available in whatever package manager you’re using.
There’s almost always a section explaining how to get the dependencies in the README, for example in paperjam’s README, it says:
To compile PaperJam, you need the headers for the libqpdf and libpaper libraries (usually available as libqpdf-dev and libpaper-dev packages).
You may need
a2x
(found in AsciiDoc) for building manual pages.
So on a Debian-based system you can install the dependencies like this.
sudo apt install -y libqpdf-dev libpaper-dev
If a README gives a name for a package (like libqpdf-dev
), I’d basically
always assume that they mean “in a Debian-based Linux distro”: if you’re on a
Mac brew install libqpdf-dev
will not work. I still have not 100% gotten
the hang of developing on a Mac yet so I don’t have many tips there yet. I
guess in this case it would be brew install qpdf
if you’re using Homebrew.
step 3: run ./configure
(if needed)
Some C programs come with a Makefile
and some instead come with a script called
./configure
. For example, if you download sqlite’s source code, it has a ./configure
script in
it instead of a Makefile.
My understanding of this ./configure
script is:
- You run it, it prints out a lot of somewhat inscrutable output, and then it
either generates a
Makefile
or fails because you’re missing some dependency - The
./configure
script is part of a system called autotools that I have never needed to learn anything about beyond “run it to generate aMakefile
”.
I think there might be some options you can pass to get the ./configure
script to produce a different Makefile
but I have never done that.
step 4: run make
The next step is to run make
to try to build a program. Some notes about
make
:
- Sometimes you can run
make -j8
to parallelize the build and make it go faster - It usually prints out a million compiler warnings when compiling the program. I always just ignore them. I didn’t write the software! The compiler warnings are not my problem.
compiler errors are often dependency problems
Here’s an error I got while compiling paperjam
on my Mac:
/opt/homebrew/Cellar/qpdf/12.0.0/include/qpdf/InputSource.hh:85:19: error: function definition does not declare parameters
85 | qpdf_offset_t last_offset{0};
| ^
Over the years I’ve learned it’s usually best not to overthink problems like
this: if it’s talking about qpdf
, there’s a good change it just means that
I’ve done something wrong with how I’m including the qpdf
dependency.
Now let’s talk about some ways to get the qpdf
dependency included in the right way.
the world’s shortest introduction to the compiler and linker
Before we talk about how to fix dependency problems: building C programs is split into 2 steps:
- Compiling the code into object files (with
gcc
orclang
) - Linking those object files into a final binary (with
ld
)
It’s important to know this when building a C program because sometimes you need to pass the right flags to the compiler and linker to tell them where to find the dependencies for the program you’re compiling.
make
uses environment variables to configure the compiler and linker
If I run make
on my Mac to install paperjam
, I get this error:
c++ -o paperjam paperjam.o pdf-tools.o parse.o cmds.o pdf.o -lqpdf -lpaper
ld: library 'qpdf' not found
This is not because qpdf
is not installed on my system (it actually is!). But
the compiler and linker don’t know how to find the qpdf
library. To fix this, we need to:
- pass
"-I/opt/homebrew/include"
to the compiler (to tell it where to find the header files) - pass
"-L/opt/homebrew/lib -liconv"
to the linker (to tell it where to find library files and to link iniconv
)
And we can get make
to pass those extra parameters to the compiler and linker using environment variables!
To see how this works: inside paperjam
’s Makefile you can see a bunch of environment variables, like LDLIBS
here:
paperjam: $(OBJS)
$(LD) -o $@ $^ $(LDLIBS)
Everything you put into the LDLIBS
environment variable gets passed to the
linker (ld
) as a command line argument.
secret environment variable: CPPFLAGS
Makefiles
sometimes define their own environment variables that they pass to
the compiler/linker, but make
also has a bunch of “implicit” environment
variables which it will automatically pass to the C compiler and linker. There’s a full list of implicit environment variables here,
but one of them is CPPFLAGS
, which gets automatically passed to the C compiler.
(technically it would be more normal to use CXXFLAGS
for this, but this
particular Makefile
hardcodes CXXFLAGS
so setting CPPFLAGS
was the only
way I could find to set the compiler flags without editing the Makefile
)
two ways to pass environment variables to make
I learned thanks to @zwol that there are actually two ways to pass environment variables to make
:
CXXFLAGS=xyz make
(the usual way)make CXXFLAGS=xyz
The difference between them is that make CXXFLAGS=xyz
will override the
value of CXXFLAGS
set in the Makefile
but CXXFLAGS=xyz make
won’t.
I’m not sure which way is the norm but I’m going to use the first way in this post.
how to use CPPFLAGS
and LDLIBS
to fix this compiler error
Now that we’ve talked about how CPPFLAGS
and LDLIBS
get passed to the
compiler and linker, here’s the final incantation that I used to get the
program to build successfully!
CPPFLAGS="-I/opt/homebrew/include" LDLIBS="-L/opt/homebrew/lib -liconv" make paperjam
This passes -I/opt/homebrew/include
to the compiler and -L/opt/homebrew/lib -liconv
to the linker.
Also I don’t want to pretend that I “magically” knew that those were the right arguments to pass, figuring them out involved a bunch of confused Googling that I skipped over in this post. I will say that:
- the
-I
compiler flag tells the compiler which directory to find header files in, like/opt/homebrew/include/qpdf/QPDF.hh
- the
-L
linker flag tells the linker which directory to find libraries in, like/opt/homebrew/lib/libqpdf.a
- the
-l
linker flag tells the linker which libraries to link in, like-liconv
means “link in theiconv
library”, or-lm
means “linkmath
”
tip: how to just build 1 specific file: make $FILENAME
Yesterday I discovered this cool tool called
qf which you can use to quickly
open files from the output of ripgrep
.
qf
is in a big directory of various tools, but I only wanted to compile qf
.
So I just compiled qf
, like this:
make qf
Basically if you know (or can guess) the output filename of the file you’re
trying to build, you can tell make
to just build that file by running make $FILENAME
tip: you don’t need a Makefile
I sometimes write 5-line C programs with no dependencies, and I just learned
that if I have a file called blah.c
, I can just compile it like this without creating a Makefile
:
make blah
It gets automaticaly expanded to cc -o blah blah.c
, which saves a bit of
typing. I have no idea if I’m going to remember this (I might just keep typing
gcc -o blah blah.c
anyway) but it seems like a fun trick.
tip: look at how other packaging systems built the same C program
If you’re having trouble building a C program, maybe other people had problems building it too! Every Linux distribution has build files for every package that they build, so even if you can’t install packages from that distribution directly, maybe you can get tips from that Linux distro for how to build the package. Realizing this (thanks to my friend Dave) was a huge ah-ha moment for me.
For example, this line from the nix package for paperjam
says:
env.NIX_LDFLAGS = lib.optionalString stdenv.hostPlatform.isDarwin "-liconv";
This is basically saying “pass the linker flag -liconv
to build this on a
Mac”, so that’s a clue we could use to build it.
That same file also says env.NIX_CFLAGS_COMPILE = "-DPOINTERHOLDER_TRANSITION=1";
. I’m not sure what this means, but when I try
to build the paperjam
package I do get an error about something called a
PointerHolder
, so I guess that’s somehow related to the “PointerHolder
transition”.
step 5: installing the binary
Once you’ve managed to compile the program, probably you want to install it somewhere!
Some Makefile
s have an install
target that let you install the tool on your
system with make install
. I’m always a bit scared of this (where is it going
to put the files? what if I want to uninstall them later?), so if I’m compiling
a pretty simple program I’ll often just manually copy the binary to install it
instead, like this:
cp qf ~/bin
step 6: maybe make your own package!
Once I figured out how to do all of this, I realized that I could use my new
make
knowledge to contribute a paperjam
package to Homebrew! Then I could
just brew install paperjam
on future systems.
The good thing is that even if the details of how all of the different packaging systems, they fundamentally all use C compilers and linkers.
it can be useful to understand a little about C even if you’re not a C programmer
I think all of this is an interesting example of how it can useful to understand some basics of how C programs work (like “they have header files”) even if you’re never planning to write a nontrivial C program if your life.
It feels good to have some ability to compile C/C++ programs myself, even
though I’m still not totally confident about all of the compiler and linker
flags and I still plan to never learn anything about how autotools works other
than “you run ./configure
to generate the Makefile
”.
Two things I left out of this post:
LD_LIBRARY_PATH / DYLD_LIBRARY_PATH
(which you use to tell the dynamic linker at runtime where to find dynamically linked files) because I can’t remember the last time I ran into anLD_LIBRARY_PATH
issue and couldn’t find an example.pkg-config
, which I think is important but I don’t understand yet
Apple just Sherlocked Docker
A Simple Example of Calling an Elixir Library from Gleam
I’ve been experimenting a bit with Gleam and Elixir lately as part of my search for a new programming language.
One of Gleam’s flagship features is that it can call Elixir code and libraries, but I couldn’t find any examples of how to do that. I wrote a simple example of calling an Elixir library from a Gleam project, based on my beginner’s understanding of the Gleam/Elixir/Erlang ecosystem.
Install dependencies
For this example, I’m using
Educational Products: Month 8
Highlights
- The writing techniques I planned last month helped me publish faster and focus better.
- I need to find more ways to talk to readers about my book.
Goal grades
At the start of each month, I declare what I’d like to accomplish. Here’s how I did against those goals:
Publish two chapters of my book to pre-order readers
- Result: Published “You’re Qualified to Write a Blog Post” and “Good vs. Bad Content Marketing”
- Grade: A
I completed these chapters and sent them to pre-order customers.