Hire me! (click for details)
I am a software developer. After teaching myself to code on Apple II computers in junior high school and building software for our family-owned telecom business, my degree in Computer Science from Harvey Mudd College gave me the grounding for a career in software development where I was able to let my programming freak flag fly: I worked for Knowledge Adventure, an educational/games software company (where I first started leading teams of developers), HomePage.com, an internet startup (where we developed a white-label free web hosting platform), and MySQL Ab (where I led the web development team and then transitioned over to the server development team).
Through this time I was also involved in the open source community. In
college, I was involved in the very early days of Linux, and I took over
maintenance from Linus of the “root” disk used to install Linux before
distributions. While working on websites for Knowledge Adventure, I got
involved with the the PHP project, and
became a founding member of the PHP Group. I helped set up and maintain some
of the collaborative development infrastructure, including the mailing lists
and online documentation feedback system. Then at HomePage.com,
I contributed work we did related to mod_perl
, and became a member of the Apache Software Foundation.
After MySQL Ab was acquired by Sun Microsystems (and then further by Oracle), I co-founded Raw Materials Art Supplies, a retail store in downtown Los Angeles which I operated as general manager for the last 15 years. I built Scat POS, a point of sale and ecommerce system using PHP and MySQL that we used to run the business. It involved a lot of integration work (payment processors, product feeds, shipping), and I automated as much as I could to focus on our artists' needs. This enabled us to build our business from scratch into one of the top independent art supply stores in the country.
I’m primarily looking for individual contributor roles. PHP/MySQL is the core of what I do best, but I'm comfortable with full-stack web development, Linux system administration, C/C++, Docker, and confident in my abilities to jump into any tech stack and get up to speed quickly.
View my LinkedIn profile for some dates and details, and my GitHub profile for some of my open source contributions. Contact me to discuss opportunities.
Just make it better
This access hatch on a sidewalk on Main St. in downtown Los Angeles used to have chipped concrete around the edges and the doors had a lot of flex to them when you walked over them. A few weeks ago, it was finally fixed up and now it looks clean, the doors don’t have any flex to them, and my near-daily experience of walking on that stretch of sidewalk feels a little bit better and safer.
Today, the website for the PHP Documentation Team was finally moved to a new host. Everything (or nearly so) related to the installation is on the appropriate repositories, it’s being served up over TLS, some of the code has been cleaned up, and the contribution guide has gotten more focused attention than it has had in several years.
None of this is perfect. None of it is done. But making things incrementally better is the kind of good trouble that I want to continue.
Another side of the fence
I keep running into things about the Zig community that intrigue me. The latest was this post by Loris Cro about “Critical Social Infrastructure for Zig Communities,” where these paragraphs really grabbed me:
We definitely also need bolder moves, but for now let's try to take it one step at a time, starting from structuring our communities around the idea that other interesting Zig communities exist out there, and that we should try harder to at least stay informed of what we all are collectively working on.
Conversely, we should also strive to make it easier for others to keep track of what we are doing. The time for bolder moves will come, but this a strong prerequisite before can we get to those.
Maybe it is because it is a new and small community compared to PHP’s, but the Zig community seems pretty great. Mitchell Hashimoto’s investment in the community is a good sign.
A lot of what Loris wrote about also brought to mind the IndieWeb principles and my own interest in promoting the ideal of doing open source development in the open using open tools. I chafe every time a community is centered on Discord or Slack, or finding that the real discussions and decision-making is happening in inaccessible places. One person’s tight-knit community can be another’s exclusive club.
What we have now
I ran across this RFC “analysis” by Zeev Suraski that was a response to a proposal about PHP adopting a Code of Conduct. Particularly the section headlined “The RFC process is [all that] what we have.”
In it, he says:
A person that joined internals@ only after the RFC process was enacted in 2011 may be excused to believe that the RFC process is all we have, and that it governs every possible aspect of the PHP language. However, that isn't true - and there's ample evidence for that available.
First, there are fundamental principals which date all the way back to the late 1990's, that are apparent to anybody who reads the archives. One of these core tenets was covered above - open unrestricted discussion.
Another, which is just as real, is decision by consensus for critical decisions.
As a principal author of the Voting RFC and as the person who came up with the 2/3 bar - I can say with absolute confidence that it was meant to regulate feature proposals - and not transforming policy changes - which this proposal certainly falls under. You don't only have to take my word for it - there - 'clues' are available all over the various RFC documents, beginning with the Voting RFC itself:
[ ... ]
It's true that since the Voting RFC process was enacted, it was used for limited-scope / tactical policy decisions. However - neither of these imply that it suddenly became as our sole form of governance that can be applied to everything - especially as it attempts to make the giant leap to cover topics like project participation policies, mailing list censorship and full-fledged banning of members. It's also worth pointing out that even in the handful of cases where it was used for minor policy changes - all of these policy changes effectively cleared the bar of decision by consensus, and not just barely clearing a 2/3 bar - which would have implied an extremely controversial decision.
That was five years ago, and it looks like the PHP project has only veered further away from Zeev’s ideal of a consensus-based approach for anything but feature proposals.
As jacked as it sounds
Dries Buytaert, founder of the Drupal project, wrote a great article on “Solving the Maker-Taker problem,” about how Drupal built a system to recognize the contributions of community members and their sponsors. I am not wild about the “Maker-Taker” terminology because it gives me Election 2012 flashbacks, but I don’t have anything better to propose. (It was this post by Ben Werdmuller that brought the article to my attention.)
By transparently rewarding contributions and fostering collaboration, we can build healthier open source ecosystems. A credit system can help make open source more sustainable and fair, driving growth, competitiveness, and potentially creating thousands of new open source businesses.
It looks like there is a lot to like about the Drupal contribution credit system and their approach to community contribution in general.
This idea of how money and other benefits should flow within the free software (and open source) ecosystem has been on my mind for over 32 years and it is frustrating to me that I still don’t feel like I know how I feel about it.
It has been easy, at times, to feel like I have ended up on the wrong side of the deal. It felt pretty good when I made money (a little) from MySQL’s sale to Sun Microsystems. I also feel pretty dumb when I’m working alongside people on open source projects where they’re getting paid and I’m not, or someone else entirely is landing investments and spinning up large companies based on the work of communities to which I’ve contributed.
But this isn’t just a feeling I have encountered in my open source work, it was also something I felt when we ran our art supply store. It was a frustrating feeling to hustle to cut a good deal for a non-profit organization where you know the staff there is being paid a better salary than you could afford to pay yourself, and more often than not they would just rely on the big online suppliers rather than even bring the business to us, the small local business.
Maybe my feelings are complicated because I never managed to become post-economic. My version of becoming post-economic was supposed to be running an art supply store, and instead it turned me sub-economic.
Feel like a cheap bouquet of flowers
I took this photo back in 2005 of a building at 3rd and Broadway in downtown Los Angeles as it was just starting to be converted into residential lofts. Gutted, full of promise, and destined for better things. I can relate.
Configuring third-party Apt repositories with Ubuntu
I just upgraded my primary development machine to the latest Ubuntu LTS (24.04.1) and it disabled the third-party sources I had set up for things like WezTerm, Tailscale, Syncthing, and the GitHub CLI. (It warned it would be doing this.)
When I re-enabled them, I finally made sure they were set up in the modern-ish way and no longer complained about keys that were installed using deprecated methods.
Now, the keychain for each repository is in the /usr/share/keyrings
directory in a file named something like tailscale-archive-keyring.gpg
. Some of the keys were mashed together in /etc/apt/trusted.gpg
before, but apt-key list
showed those were keys that I had individually under /usr/share/keyrings
so I just went ahead and deleted /etc/apt/trusted.gpg
entirely.
For each repository, there is either a repository
.list
or repository
.sources
file in /etc/apt/sources.list.d
. The .list
files are in “one line format”, and the .sources
files in a friendlier key-value format called “deb822”. The formats are explained the sources.list
(5) man page.
For example, here’s the /etc/apt/sources.list.d/tailscale.sources
:
Enabled: yes
Types: deb
URIs: https://pkgs.tailscale.com/stable/ubuntu
Suites: noble
Components: main
Signed-By: /usr/share/keyrings/tailscale-archive-keyring.gpg
And /etc/apt/sources.list.d/wezterm.list
:
deb [signed-by=/usr/share/keyrings/wezterm-fury.gpg] https://apt.fury.io/wez/ * *
The files in my /etc/apt/sources.list.d
were a bit of a jumble, where some had been renamed with an extra .distUpgrade
extension and the deb822-formated files had Enabled: no
. I moved everything back into the proper filenames and changed those yeses to nos, and now when I run apt update
it pulls all from all of the appropriate sources and doesn’t complain about any deprecated keys.
Instead of referencing a key file in the Signed-By
line of a source, you can also directly embed the ASCII representation of the key. With that, the tailscale.sources
looks like:
Enabled: yes
Types: deb
URIs: https://pkgs.tailscale.com/stable/ubuntu
Suites: noble
Components: main
Signed-By:
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=AIVM
-----END PGP PUBLIC KEY BLOCK-----
I converted the binary format of the key (the .gpg
file) into that text representation with:
$ gpg --keyring tailscale-archive-keyring.gpg --no-default-keyring --export -a
Put a pin in it
I did a first cut of moving my bookmarks on to this site instead of using Pinboard.
I still need to wire up a way to create new bookmarks, but that should be pretty straightforward.
Each bookmark can carry with it an excerpt and a comment. That way I can clip a little text for the bookmark while I’m creating it. None of the existing bookmarks use that yet because Pinboard did no such thing.
Things to be done aside from adding a way to add bookmarks include adding an Atom feed, really wiring them up to search, figure out how to be marking these up in a more IndieWeb-friendly way, and thinking about whether I want to take snapshots of the bookmarks. (Those would probably only be accessible to me to avoid copyright headaches.)
The oldest sins the newest kind of ways
When I wanted to get away from using Discord to participate in the online PHP and IndieWeb communities, I did still want a web-based interface that provided access to the backlog of conversations from when I was offline, which IRC servers don’t generally do on their own.
I landed on using The Lounge, which has worked out very well.
I run it on my home server in Docker and it is exposed to my Tailscale tailnet so if I ever was on the road, I could still access it. The configuration is pretty straightforward. There’s a docker-compose.yml
file:
version: '3.9'
services:
tailscale:
image: tailscale/tailscale:latest
hostname: thelounge
env_file: ./.env
environment:
- TS_SERVE_CONFIG=/config/thelounge.json
- TS_STATE_DIR=/var/lib/tailscale
volumes:
- ts_state:/var/lib/tailscale
- ./config/tailscale:/config
- /dev/net/tun:/dev/net/tun
cap_add:
- net_admin
- sys_module
restart: always
backend:
image: ghcr.io/thelounge/thelounge:latest
env_file: ./.env
volumes:
- lounge_state:/var/opt/thelounge
expose:
- "9000/tcp"
restart: always
volumes:
ts_state:
lounge_state:
And config/tailscale/thelounge.json
:
{
"TCP": {
"443": {
"HTTPS": true
}
},
"Web": {
"${TS_CERT_DOMAIN}:443": {
"Handlers": {
"/": {
"Proxy": "http://backend:9000"
}
}
}
},
"AllowFunnel": {
"${TS_CERT_DOMAIN}:443": false
}
}
There is an .env
file that sets TS_AUTHKEY
and TS_EXTRA_ARGS
. It looks kind of like this:
TS_AUTHKEY="tskey-client-{something}?ephemeral=false"
TS_EXTRA_ARGS="--advertise-tags=tag:container --reset"
Never was a cloudy day
Another month in the rear view mirror, and time for me to reflect on my job search and remind people that I’m still out on these streets looking.
Some days it feels like I am not any closer to having a job than I was when this all started. I have a lot of applications behind me, a handful of screening calls with recruiters, a smaller number of interviews, and as of yet no offers. I have been ghosted on countless applications and once after a screening call. (That position still gets re-listed periodically.)
I am in the interview process with a very large tech company with a drawn-out interview process. I have very mixed feelings about it. Do I really want to work there? Am I going to pass through their interview hoops? A big factor in those mixed feelings is that if an offer does happen, it will require moving to another city and working out of an office several days a week.
Some of the rejections, even when they came early, have been hard. There have been positions at a few different companies that were focused on building internal tools for the company, which is something I believe I would be particularly well-suited to do, so I have been looking harder at listings that push that button.
I am grateful to everyone who has offered support, and leads on positions.
Into the blue again after the money’s gone
A reason that I finally implemented better thread navigation for the PHP mailing list archives is because it was a bit of unfinished business — I had implemented it for the MySQL mailing lists (RIP), but never brought it back over to the PHP mailing lists. There, it accessed the MySQL database used by the Colobus server directly, but this time I exposed what I needed through NNTP.
An advantage to doing it this way is that anyone can still clone the site and run it against the NNTP server during development without needing any access to the database server. There may be future features that require coming up with ways of exposing more via NNTP, but I suspect a lot of ideas will not.
Another reason to implement thread navigation was that a hobby of mine is poking at the history of the PHP project, and I wanted to make it easier to dive into old threads like this thread from 2013 when Anthony Ferrara, a prominent PHP internals developer, left the list. (The tweet mentioned in the post is gone now, but you can find it and more context from this post on his blog.)
Reading this very long thread about the 2016 RFC to adopt a Code of Conduct (which never came to a vote) was another of those bits of history that I knew was out there but hadn’t been able to read quite so easily.
Which just leads me to tap the sign and point out that there is a de facto Code of Conduct and a group administering it.
I think implementing a search engine for the mailing list archives may be an upcoming project because it is still kind of a hassle to dig threads up. I’m thinking of using Manticore Search. Probably by building it into Colobus and exposing it via another NNTP extension.
Surprise, it’s a new release of Colobus!
Because there’s nothing that quite says “hire me” like polishing your Perl bona fides, I have finally made a new release of Colobus, the NNTP server that runs on top of ezmlm and Mlmmj mail archives. (It was actually three new releases, I had to work out some kinks. More to come as I work out more in testing.)
The Mlmmj support and some of the other tweaks are really just pulling in and polishing changes that had been made to the install used for the the PHP.net mailing lists. There are also a few bug fixes I pulled in from Ask’s fork of colobus that the perl.org project uses.
I did add a significant new feature, which is a non-standard XTHREAD id_or_msgid
command that returns an XOVER
-style result for all of the messages in the same “thread”. The code to take advantage of this new feature for the PHP mailing list archives is on the way.
Writing documentation in anger
As I continue to slog through my job search, I also continue to contribute in various ways to the PHP project. Taking some inspiration from the notion of “good trouble” so wonderfully modeled by John Lewis, I have been pushing against some of the boundaries to move and expand the project.
In a recent email to the Internals mailing list from Larry Garfield, he said:
And that's before we even run into the long-standing Internals aversion to even recognizing the existence of 3rd party tools for fear of "endorsing" anything. (With the inexplicable exception of Docuwiki.)
I can guess about a lot of the history there, but I think it is time to recognize that the state of the PHP ecosystem in 2024 has come a long way since the more rough-and-tumble days when related projects like Composer were experimental.
So I took the small step of submitting a couple of pull requests to add a chapter about Composer and an example of using it’s autoloader to the documentation.
The PHP documentation should be more inclusive, and I think the best way to make that happen is for me and others to just starting making the contributions. We need to shake off the notion that this is somehow unusual, not choose to say nothing about third-party tools for fear of “favoring” one over the other, and help support the whole PHP ecosystem though its primary documentation.
I would love to add a chapter on static analysis tools. And another one about linting and refactoring tools. Maybe a chapter on frameworks.
None of these have to be long or exhaustive. They only need to introduce the main concepts and give the reader a better sense of what is possible and the grounding to do more research on their own.
A big benefit of putting this sort of information in the documentation is that there are teams of people working on translating the documentation to other languages.
And yes, contributing to the PHP documentation can be kind of tedious because the tooling is pretty baroque. I am happy to help hammer any text that someone writes into the right shape to make it into the documentation, just send me what you have. If you want to do more of the heavy lifting, join the PHP documentation team email list and let’s make more good trouble together.