I’m going to do something difficult and controversial and, since this is a first cut at it, I probably won’t do it perfectly. I’m going to develop a system for evaluating the skill and impact of a software engineer or, at the least, outline a trajectory for the idealized growth of a software programmer. The scale runs from 0.0 to 3.0, with each whole number representing a threshold in professional development.
Largely, this is an engineering scale based on the needs of software businesses. It’s not about mathematical ability or the capacity to write fast algorithms. Nor is it about the depth of knowledge a programmer has about the internals of the Linux kernel. Those are important, and will usually develop in tandem with an engineer’s skill, but not the primary focus of this system. It doesn’t represent everything one needs to know in order to evaluate a software developer. It’s also not a substitute for “performance reviews” or to be used for “HR matters”. Sometimes a “2.1” may need to be fired for personality reasons, whereas an amicable “1.2” is an asset to a company.
Finally, this scale is somewhat context-dependent, noting the difference between skill and impact. Change the programming language or technology stack, and a developer can rise or drop by a full point. Also, a developer needs to be on a team for 6 to 12 months (in most cases) to reach a level of impact commensurate with her capability. It’s tempting to speak of levels like “1.5” as if they were objective ratings of a person’s skill. More accurately, they describe scopes of contribution and fit between a person and job role. The size and needs of a company also have a major impact. Small technology companies often encourage their people to “experiment” 0.2-0.5 points above their level of demonstrated skill, and to thereby grow quickly, while large and bureaucratic firms usually slot people an equal amount below their skill levels (because of inherent limitations on leadership positions).
The scale I’m about to define comes from one insight about human organizations. Teams, in general, have four categories into which a person’s contribution can fall: dividers, subtracters, adders, and multipliers. Dividers are the cancerous people who have a broad-based negative effect on productivity. This usually results from problems with a person’s attitude or ethics– “benign incompetence” (except in managers, whose job descriptions allow them only to be multipliers or dividers) is rarely enough to have a “divider” effect. This is an “HR issue” (dividers must improve or be fired) but not the scope of this professional-development scale, which assumes good-faith and a wish for progress. Subtracters are people who produce less than they cost, including the time of others who must coach and supervise them. As a temporary state, there’s nothing wrong with being a subtracter– almost every software engineer starts out his career as one, and it’s common to be a subtracter in the first weeks of a new job. Adders are the workhorses: competent individual contributors who deliver most of the actual work. Finally, multipliers are those who, often in tandem with “adder” contributions, make other people more productive. In many industries, being a multiplier is thought to be the province of management alone, but in technology that couldn’t be farther from the truth, because architectural and infrastructural contributions (such as reusable code libraries) have a broad-based impact on the effectiveness of the entire company.
What this scale intends to measure is the transition from a subtracter to an adder (0.0 to 1.0), from an adder to a multiplier (1.0 to 2.0), and from a “local” to a “global” multiplier (2.0 to 3.0). I ignore issues associated with “dividers” (who may be highly competent engineers; as I alluded above, a 2.0+ engineer can be a “divider” if there are personality problems) because those are “HR issues” (improve quickly or fire) while this scale is concerned with skill and long-term professional development.
Approximately speaking, the ranges are:
0.0 to 0.4: Complete novice: this is the level of a person who is still “learning programming”, by which I mean the person is likely to have trouble getting code to compile. This person has technical limitations that make unsupervised professional-level contributions impossible. Typically, this level of development is observed only in introductory programming courses. Most college interns are already at 0.5 or above when they start programming professionally.
0.5 to 0.7: Sound grasp of fundamentals: this is the level of someone who can call herself a “programmer” but not yet an “engineer”. Can competently build small systems (up to 3000 lines of code or so) but the code is likely to be sloppy and unmaintainable. At this level, getting the code “to work” is not an issue, but the code is likely to be inefficient, and the person’s architectural skills (due to inexperience) are likely to be weak. Typical level for a college student from a strong school before her first software internship.
0.8 to 0.9: Becoming an adder: this is a person who is aware of the practical concerns (maintenance, runtime safety) associated with software development. She can deliver useful scripts and has a decent understanding of software engineering. She is capable of using Google and online resources to answer small-scoped questions about development (such as how to do File I/O in an unfamiliar language).
1.0 to 1.3: Full-fledged adder: this person has demonstrated full competence as a software engineer and can be trusted to manage a small project “full-cycle”: design, implementation, testing, and integration. Code will usually be of reasonable quality, but the engineer is not ready to be responsible for meeting deadlines, production support (being “the 3:00 am guy”), or company-wide concerns. A team of mostly 1.3 engineers can produce solid work (the average software engineer is around 1.1; note that the 50th-percentile software job is a low-autonomy “Java jockey” position) but a software company whose best engineers are in this range will struggle to produce quality software.
1.4 to 1.6: Solid adder: well above-average (top 10%) by software-industry standards, but average (at 5-10 years’ experience) in the context of the best companies (e.g. elite startups, Google, and research divisions of IBM). Can be trusted to independently solve most problems in an elegant and maintainable way. Engineer can make reasonable time estimates and communicate in both business and technical terms with management as well as other engineers. Can handle small levels of deadline/delivery responsibility and should be encouraged to participate in architectural decisions (“multiplier” concerns). Technical leadership non-urgent projects is a serious possibility.
1.7 to 1.9: Becoming a multiplier: top 5%. Engineer is on track toward full “multiplier” status. Her contributions not only solve immediate problems, but improve the state of company infrastructure. She routinely suggests architectural and process improvements, and is ready to be “tech lead” for important projects.
2.0 to 2.3: Full-fledged multiplier: engineer is an objective multiplier whose contributions add immense, demonstrated value to the team– an obvious technical leader. This represents the top 2-3% of software engineers in problem-solving, architectural, and leadership skills.
2.4 to 2.6: Becoming a global multiplier (“Fellow”): engineer’s achievements are vast and astonishing. Contributions are company-wide or extend even further (e.g. to the open-source community). Represents the top 0.25% of software engineers. Can be trusted to work on independent research (with full autonomy) and lead major initiatives.
2.7 to 3.0: Senior fellow: engineer is known within and outside the company as one of the best computer programmers alive. These are people who can design new programming languages and produce good ones.
How does this scale play out? What practical conclusions can we draw from it? Ideally, it exists to plot the trajectory that most programmers will take. Sadly, the reality of the software industry is that the average software engineer never gets far above 1.0. Since the difference between these awful programmers is not (at least, in my estimation) a problem of intellectual ability– perhaps it’s one of curiosity and drive– this is unfortunate.
Software is, by far, one of the most structurally cooperative systems in the world. What I mean by “structurally cooperative” is that our own well-being is correlated positively with the performance of others in our industry, even when they’re nominally (and transiently) “competitors”. Great programmers teach other programmers to be great and build great technologies, which are often released into the open-source community. Conversely, the badness of the average software developer causes a world of suffering for the good ones. Why are so many programming jobs (and libraries) in brain-dead languages (such as Java) rather than functional-programming languages (e.g. Scala, Ocaml, Clojure, Haskell)? Because while the Java+IDE environment makes it extremely difficult for an individual engineer to have a 1.5+ impact –there are two cases in recorded history of programmers breaking 2.0 in Java; one is Martin Odersky, who wrote Scala, and the other is Rich Hickey, who wrote Clojure– the state of the tooling makes it possible for the 0.7’s and 0.9’s to get a 0.1- to 0.3-point bump, so long as they stay within their IDEs and don’t have to work with a computer (gasp!) at the (God, no!) command line.
Sadly, the “half-life” of a software developer is about 6 years. The trajectory of an “average” software developer looks like this: he leaves a JavaSchool at a competency around 0.6 and grows by approximately 0.1 point per year– that’s not blazing along this stretch (0.1/year would be quite fast above 2.0, but it’s poky below 1.0) but a reasonable pace for a person with little mentoring and a lackluster environment. Around 1.2, he reaches a technical ceiling, convinced that “programming” has intrinsic limits on individual contribution, except for “geniuses” who have 167 IQs and 40 years of programming experience (at age 44). This is because the Java+IDE environment, and operating systems like Windows, are designed to bring up the rear (0.7 to 0.9) while holding back the best programmers, artificially imposing that “ceiling” around 1.2-1.5; these technologies are intentionally designed for a performance-middling effect– to make it possible for huge teams of “commodity” developers to produce something while holding the excellent back from producing great things.
If he had spent some time reading Hacker News and learning about this fancy “functional programming” stuff, he might have seen a credible path (for non-geniuses like this writer) to 1.5 and beyond. But he hasn’t, so he burns out on “code monkey” work and moves into management. Or he goes to law school. Or business school. Because he wrongly concluded that this “engineering” thing (as he experienced it) was just too limited and dull to do for another decade. Even after six years, he was a mediocre, bottom-90-percent programmer and so no one misses that he’s gone, but with better guidance and exposure to superior technologies, he could have become great.
This is what’s at stake in “language wars” and arguments about the configuration of the software industry. It’s not just about hating to write (much less maintain) code in unattractive languages like Java and C++, or use hideous and inelegant operating systems like Windows. Far more is involved here.