4 posts tagged with "tech"

View All Tags

Don't be a 10xer!

In software, engineers are sometimes referred to as "10xers" - implying that they're capable of producing 10x the productivity of a comparable person. When I was getting started in the industry, this was a bit of a goal for me. I'd like to be perceived as superhuman, and this is a pretty explicit endorsement of that. I'd sometimes work a little (or a lot) extra just to prove that I could do more than my peers. One guaranteed way to 10x is to work 10x the hours.

Over time, I did end up being what I call a "feature 10xer". I could often produce, measurably, 10x the amount of code or features than other people on my team. I wouldn't often produce 10x the reliability, but I'd certainly make the CEO and PMs happy, which was my goal. This also meant sometimes hacking through systemic problems (getting to the root of issues isn't fast). At early stage startups, this seemed desirable, but came with many drawbacks.

At startups with older codebases, this attitude still prevailed, although it usually takes a different form: the "intuition 10xer" is the person who knows the codebase and hacks well enough to deftly navigate through it far faster than (otherwise extremely competent) peers. This means they're the "debugger of last resort", and that they can design features in their head and then implement them without needing to change the design, since they knew all the caveats and patterns before reading code. These people also often have been entrenched in their own decisions for so long that they bear little empathy for new team members. Their intuition is so dialed into the history of this specific codebase that they can't even imagine what it would feel like not to know where everything is - everything is where it belongs, after all!

Both of these roles break down at critical times in the business: when you need to react to growth -- either engineering headcount, or scaling pressure from customer growth. I've observed the following common patterns:

  • The "feature 10xer" creates debt faster than everyone, creating a positive feedback loop of debt. To sustain their relationships and pace, they don't have bandwidth to refine shipped work. As a result, a minimum of 10 people are needed to focus on the reactive work they leave behind. If you're lucky, those 10 people won't need to consult the 10xer to fix things, but eventually this will slow the 10xer down, which is extremely frustrating. I've observed that this is when the feature 10xer transitions into an intuition 10xer, or they leave out of frustration.
  • The "intuition 10xer" becomes a blocker for design and review, bottlenecking all work. You grow the team, the performance issues start coming up, and the system's complexity belongs to an individual. They get frustrated when it takes others 10x the time to fix things, but their desire to "just do it themselves" and fix things faster also slows the team down because they're responsible for reviewing nearly everything, and they're busy fixing things. Everyone sits around waiting for this person, contribuiting to a feedback loop of slowness.

At the end of the day, if one team member is dramatically outperforming the others, you have a huge scaling issue, visible or not. If you manage to survive this phase of your company, pain is on the horizon. All a 10xer does is create 10x the work for others, either now or later. That doesn't mean that having senior people on your team is bad. But it does mean that continuing to have them "go back to the dopamine dispenser" for years after they've become a load-bearing decision maker results in the code becoming less and less understandable to new people as more and more decisions are made in a vacuum by someone with less and less exposure to the outside world. Inevitably, these codebases are extremely expensive to onboard and frustrating to work on, making it difficult to hire and retain new employees, contributing to the bottleneck of these individuals.

Instead, teams should aspire to see (roughly) equal distribution of work, with the senior people spending the "other 9x" on technical debt, documentation, mentorship, developer productivity, and proactive issue/complexity resolution. Arguably the most beneficial side-effect of this arrangement is that the example set by your 10x citizens are that new hires are empowered to begin their journey emulating these activities. You'll occasionally need to encourage newer people to ship imperfect things, but you won't have your 10xers shipping imperfection and your new hires cleaning up their mess - an arrangement that feels good today, but hurts your hiring and SLOs in the long run.

Chesterton's Junkyard

Throughout my career, I've seen a lot of old code. Almost every company in Silicon Valley is started by writing some mediocre software and attempting to validate a business model without spending too much time or money on something that works well.

This is fine, and the amount of code that survives usually is relative to how "good" the code was originally - if you have the good fortune of working somewhere with no "founder code", either your founder was on the lower side of the ego spectrum, or their code was especially atrocious. Which is to say, if the product survived at all and you're not in the first cohort of employees, you have probably experienced a phenomenon called "Chesterton's Fence".

The origin of the quote is a passage in Gilbert Keith Chesterton's 1929 book "The Thing". In a chapter called "The Drift to Domesticity", he writes:

In the matter of reforming things, as distinct from deforming them, there is one plain and simple principle; a principle which will probably be called a paradox. There exists in such a case a certain institution or law; let us say, for the sake of simplicity, a fence or gate erected across a road. The more modern type of reformer goes gaily up to it and says, “I don’t see the use of this; let us clear it away.” To which the more intelligent type of reformer will do well to answer: “If you don’t see the use of it, I certainly won’t let you clear it away. Go away and think. Then, when you can come back and tell me that you do see the use of it, I may allow you to destroy it.

This "fence" comes up a lot in software, especially old or poorly factored software - and often it gets translated to "if you can't or don't want to dig in to find the original purpose for something, it probably was put there for a good reason, so you should leave it alone". In large and/or high velocity codebases, this gets reduced to "don't delete things you didn't write".

Piles of fences#

Lately, I've been feeling like while I understand the intention behind this quote and find it helpful, I also find it over-applied to the point of becoming a fallacy.

When taken without subtlety, you could extend it to mean:

A person, encountering a thing that actually has no use, will never be able to destroy that thing. In following this, we inevitably retain only the objects that truly have no purpose.

I've been calling the areas afflicted by this symptom "Chesterton's Junkyards" - piles of old, un-owned code, that nobody is empowered to change or refactor, and that arguably at least some of it literally has no purpose.

Cleaning up Junkyards#

The point of this blog post isn't just to complain, but also to propose a reasonable solution: If you encounter one of these junkyards, consider only the contract, and ignore the junk.

If you cannot reduce the offending code to a contract (e.g. it has too many side-effects, or you lack the knowledge to safely distill and replace the contract), at minimum you should file a bug to the effect of "this area of code is a junkyard, and it needs to be cleaned up before it is changed" – effectively encircling the area with caution tape.

In most cases however, these types of haphazard and unplanned pieces of code are not load-bearing. When considering the contract of a given piece of code, you will likely find that the contract is simpler than the code, and possibly even unnecessary or redundant.

The key difference here is that while Chesterton suggests "seeing the use" of something, I'd propose that many things, especially in code, truly have no use; leading us to a true paradox. But if we instead "define the contract" of said fence – which is to say, we just observe its current functionality instead of attempting to understand its purpose – we can much more easily evaluate if it aligns with our design goals (which likely have changed since we erected the fence), and instead of having to dig in and understand something that may not make sense in the first place, just clean up the junkyard.

Don't Let Them Tell You What To Do

Modern labor, as described by employers, is a paradox.

On the one hand, employers attempt to tell you that labor is a purely transactional interaction; you're on their time, and they get to tell you how to spend it. The product of your labor is not your concern. Leave your identity politics at home. If you're leaning, you could be cleaning. These hours have been bought, and no longer belong to you.

On the other, employers attempt to capitalize on your personality and intuition. There is an emphasis on growth in the workplace, and interviews don't measure only for current abilities, they predict how you may be a value-add to the culture of the workplace. Companies spend huge amounts of advertising budget attempting to prove to you that, yes, black people work at Amazon. That the workplace is a family. That the company's success is dependent on you, and therefore, you share in the company's success.

At the end of the day, neither is true. The work relationship in the extreme majority of workplaces is simple. You work there becuase you working there makes them more money than you not working there. Labor is the source of all value, and ironically, especially so in tech work. There are some values driven workplaces, and they are a wonderful compromise - but ultimately, if you clearly are not generating more money for the company than you are being paid, you will have a hard time working there for very long.

A theoretical view of tech is that it is a passive machine. That you build something somewhat analogous to a book that can print itself forever. And then, people buy that book, on a monthly recurring basis, until you have enough money to shoot yourself into space. The reality is that tech, like nearly every other thing humans create, degrades at a shocking speed, and requires a huge amount of labor just to keep functioning at a flat rate, to mention nothing of scaling or growing.

Labor touches everything in tech - the initial designs have downstream effects on the maintainability and scalability of a product, sales staff set expectations, preferences and intuition shape the product, and all of that work only puts you in a position in which bugfixes, oncall response, customer support, and directional leadership can have a chance of generating more income than they cost. If the staff of any website or app, simple or complex, walked away from it, it would cease to exist in a shockingly small period of time.

Folks who are early in their career can easily, as I did, believe that their job is to build a building that will stand forever, and that the value generated by these high-leverage actions will grow over time exponentially. But the reality is that exponential software growth is tightly coupled with exponential labor growth. Some of this is linked to application complexity, a topic for another post. There are outliers, but this trend is unavoidable.

What does this mean for the labor? It means that despite how much your employer may try to convince you that they know what is best for you, your peers, and the codebase, they always must weigh their ideas in this area against the equation of labor to value - so no mandate by an employer is made entirely in good faith, unless your sole goal at the company is to make your employer a lot more money than you make. I know few if any people who fit that description.

Tech workplaces (along with a growing number of other industries), despite needing to make money, have an interesting secondary effect of being wonderful places to grow your skills, because labor makes all the important decisions. I've certainly watched managers attempt to design software, but at the end of the day, every single decision that directly impacts the functionality of a product is made by someone working at an individual contributor level. This means that quality directly correlates with intuition - even the most hands-on micromanager cannot attempt to control every line of code you write. And as all software programmers know, every line makes a difference in maintainability, scalability, and functionality.

How does this effect your job? It means that if your company is being run correctly (which it likely isn't), you and your employer can form complimentary incentives: your employer wants you to cost less than you make them, and you want your intuition and decision making skills to be better (and worth more) than when you were hired. There is, however, a catch.

The catch is that to make your intuition and decision making skills improve, you have to use them. There are no pure problems in consumer software, everything you do must be both guided by computer science principles and an intuition and awareness of the problems you are solving at work.

Therefore, if you work from a list of JIRA tickets that you don't necessarily understand, if you execute against an OKR that you can't explain why it is important, or if you don't know why the thing you're doing is important to the company, you are being taken advantage of. You are generating more value than you are being paid, and you are not receiving any additional benefit (beyond your salary, which we've already shown, will only be paid to you if it is less than your value).

This type of abuse is both rampant and fairly easy to avoid. Simply, don't let anyone tell you what to do. If presented with a task, ask yourself: "do I agree with the goals of this task? Do I want to do this task? Does this task contribute to my growth and the success of the company?" If the answer is no, politely decline and ask for more information. It's possible you misunderstood the task and just need clarity, but more likely that you're the first person to ask this question about the task, and in doing so you will both improve your personal prospects, and contribute immense value to your employer.

The Simplest CMS, Part 1

What is the simplest & cheapest CMS possible?#

As someone who works in tech, I'm often asked to "build a website".

When asked this question, I always try to learn a bit about what they expect the website to do.

What a non-tech person means when they ask this question is usually:

  • Someone types a url into a browser, and sees something special that works as well as other websites but looks more unique and personal than something like a template.
  • The content on this website follows some common patterns. There's an about page or similar, a listing page containing a potentially infinite, but realistically quite small, list of objects. Maybe they're posts, photographs, or items for sale.
  • Search, if it exists, is quite small. It's not often that someone asks for their content to be globally full-text searchable.
  • Being able to update the content whenever they like is imperative. They don't want to learn a complicated system, they would prefer that it were as easy as posting to Facebook.

I've spent a lot of time, in short durations but over a long period of time, trying to build a system that satisfies these requirements, but is neither expensive to maintain nor complex to use.

This blog is one of the attempts - and in this case, I attempted to delegate as much as possible to an existing, maintained system (docusaurus). However, the approach I used here requires fairly strong familiarity with github and markdown, but passes the cost and simplicity requirements with flying colors.

Over Engineering#

One approach I took to this was quite involved, and used the following setup:

  • Parcel to build the frontend
  • Hasura (running on Heroku) for the database (which is Postgres under the hood), API, and authentication layer
  • GraphQL queries for CRUD between the frontend and the database
  • Docker Compose for running Hasura & Postgres locally
  • Netlify as a CDN, for DNS management, and for serveless functions, which are primarily used for generating JWTs.

The goal here was to leverage a shared db to scale this model fairly cheaply, but still has the downside of authenticated transactions on every load. Scaling this could be potentially problematic at the DB level (although realistically, I'd expect the audience of this product to be relatively small). But most of all, it just felt very heavy weight for something that was supposed to be small. It's an interesting idea for something maximally complex, but I realized that the core interaction needed by the person adding content to the website is just the ability to organize lists, add objects to the list, and update content on static pages.

This blog has nearly the same interaction, but since it's built on docusaurus, has a bunch of unrelated and difficult to modify features.

A Project#

After deciding the above approach was too complex for the problem it was solving, I started thinking about a much simpler CMS that follows some common yet new patterns in the industry. It would be composed of the following pieces:

  • The website would be entirely contained in a git repo. All content would be represented by static files in a human-readable format.
  • When the content changes, a CI job (Github Actions) would compile it to a static website.
  • Netlify would act as a CDN, and handle DNS.

This is how this blog works, for the most part. The DSL is markdown, and this site isn't very flexible in terms of object types. Pretty much only blocks of text are supported. And it still has some problems:

  • You have to know how to use Docusaurus to modify the layout, which leaks to React, Babel, and Webpack knowledge.
  • You have to be able to confidently edit the content in a git repo (alongside the source) and generally understand git to update it.

So, I think the simplest CMS would add two personas to the stack:

1: Setup#

  • The site would define one or more editable schemas that define an object type.
  • The site would define one or more simple html layouts and a page layout. The simplest and/or most common templating language should be used here.

2: Update#

  • The site would provide a dedicated interface for adding new files to folders corresponding with the schemas defined at the site level. These would produce the listed objects that the above talked about.
  • The site would provide a dedicated interface for editing page-level content.


When complete, the goal of this project would be to allow a person with mid-level knowledge of html and git to create a website that was completely custom, with simple schemas. This allows for maximal flexibility while still keeping things relatively simple.

If the site is set up in a standard way, a single desktop/mobile client or website will be able to connect to this git repo using Github OAuth or standard ssh/https git authentication, and edit any website built this way. It would simply edit the schemas defined by each website, and central documentation would track the available scalar types for each of the schemas.

The HTML would simply layout and render the content of the schemas based on their scalar types, but the scalar types can expand to be quite complex, for instance media players or observable notebooks could be embedded using simple definitions.

The build step could be centrally developed and versioned, allowing the boilerplate for this type of website to be very cheap.

Finally, since this repo will be a simple static website, it can be deployed to any of the myriad static website hosts that are available, making administration of some of the harder parts of DNS and CDN quite manageable to someone with little knowledge of the underlying systems.

Next Steps#

It's possible that I won't build this. But if I do, I'll need to choose some initial parameters:

  • Which static site host to target first (probably Netlify)
  • Where to run the shared generation code (probably Github Actions)
  • Which html templating language to use (unsure)
  • How to build the client (Web tech with WASM bindings for shared business logic if it gets complex)
  • What scalar values to support
  • Where/how to build the docs (probably just use the same tech as the CMS)

If and when I make progess, I'll update this blog.