(updated 2017.018.20.32.54)
The term "craftsman" is unfortunately afflicted with a historical gender association, but alternatives are clumsy and distracting, overloaded with (often contrary) buzzword uses, lacking in appropriate nuance, or some combination of more than one of the above. Let the gendered form of the term not stand in your way. Both men and women may be craftsmen; other-gendered people may be craftsmen, for whatever gender identification may apply; and in fact we may not be many years away from craftsmen who are, in fact, artificial intelligences.
To paraphrase the old sage, I did not have time to write a short essay, so I wrote a long essay. A better, earlier essay of mine on the subject of software craftsmanship is also much shorter, though it represents a somewhat different perspective on the subject. I believe these essays are complementary, or perhaps supplementary. If you do not have time to read this essay, read The Woodcutter's Craft instead. If you do have time to read this essay, read The Woodcutter's Craft as well -- probably first.
That said . . . here's my take on the work of the crafty coder.
The word "amateur" comes from the Latin word for "lover". The American Heritage Dictionary defines it, first, as "One who engages in an art, science, study, or athletic activity as a pastime rather than as a profession." An amateur craftsman, therefore, pursues a craft for the love of the craft.
Among the implications of this are:
a dedication to doing good work, applying good "craftsmanship" to the task at hand
always learning better approaches
adapting technique to individual talents and perspectives with the aim of applying one's own characteristics to best effect
acquiring the best tools for the job, to make the act of craftsmanship ever more enjoyable and effective.
Quality work is central to the love of a craft, with attention to detail intrinsic to the fact of enjoyment. Any true "amateur" craftsman -- one who is a lover of the craft, who deeply cares about the quality of work produced -- develops opinions and useful observations. Many of them may even disagree, sometimes almost violently, about matters that may seem entirely esoteric or even inherently opaque. This kind of confrontational opinionation is, perhaps surprisingly, often a good (but neither necessary nor sufficient) sign of the craftsman's dedication to doing quality work.
It is the job of the professional to work oneself out of a job. By completing quality work, by conveying an understanding of the work to the client, and by doing work that helps clients achieve these same goals within their own personal and professional lives, the professional works toward the day one is no longer needed.
Many people want to just hand something off to an auto mechanic one day, pick it up the next, and never understand what happened to the car between those times or even what really precipitated the need to get the car fixed. Despite this common case, an auto mechanic who takes the time to try to explain things to a client to help ensure the problem does not recur, and to ensure the client can do something next time around before turning to a professional to minimize the costs and other inconveniences involved in retaining someone's services to maintain continuing smooth operation, is the auto mechanic with a healthy, ethical ethos of the craft.
Every craft comes with its own culture, its own set of characteristics common to quality craftsmen, and its own (sometimes contradictory) requirements and motivational factors for quality work. Software development is rife with its peculiarities along these lines. The term "software development" is also deceptively simple beside the reality of what it labels; software development constitutes a myriad of related crafts, each with its own differentiating versions of these peculiarities.
Some generally applicable truths seem to emerge, however. Examples include DRY (Don't Repeat Yourself), the Law of Demeter (or Principle of Least Knowledge), and the principles of the Unix philosophy (encompassing composability, minimal responsibility, and generality of design: "design small tools that each do one thing well"). A synthesist and systems thinker might derive more generalized principles that govern the beneficial nature of techniques to enhance the quality of code craftsmanship, though. Consider the abstract principles of leverage and virtue:
In general, the best innovations are those that enable further innovation. One of the most remarkable things about this period in human history is the simple fact that the technologies we have available to us are more broadly accessible, and serve better to enable further technological advancement, than at any previous time. As remarkable as that is, it is also pretty singularly unremarkable, in that it has been true of essentially every moment at least as far back as the dark ages, and limiting it there is likely a Eurocentric conceit. It will also continue to be true for every moment in the foreseeable future.
The most empowering characteristic of technology is the leverage for further advancement provided by the introduction of previous generalized advancements. Almost all technical principles of good software design embody some aspect of this principle of innovative leverage. Three examples come to mind:
Improvable software provides a form of future-proofing so that, however useful it is when first created, the design of the software does not hinder incorporating greater utility.
The software with the most utility tends, almost invariably, to be the software that provides the most facility for reuse as components of larger systems with even greater utility, and the most facility for improvement to both do its specific job better and make it more useful as a component of larger systems. This facility for improvement also translates to both maintainability and portability, each of which is something of an iconic, nigh-universally asserted tenet of good software design.
Intelligible software is comprehensible in design, both with regard to the developers who maintain and improve it and to the people who ultimately use it (or use the larger systems incorporating it).
This intelligibility offers not only an ease of improving upon, learning, and using it, but also an understanding of it that lends to means of extending its use in ways the developer did not intend, to great positive effect. Elegance of both implementation and design, conceptually clean architecture, and minimization of bug-prone repetition are all development concerns that derive from, and help ensure, intelligibility of software systems.
Intentional software is software that serves intentions.
Such concepts as the principle of least surprise (POLS) induce attention to concerns that aid intentionality, and others such as deferment of design (sometimes known as YAGNI, short for "You Ain't Gonna Need It", encouraged by practices like agile iterative development) provide natural paths to maximize intentionality when judiciously applied to development decision-making.
The most obvious consequences of failing to produce intentional software are "Heisenbugs" (incidental unintentional software behavior that seems to manifest sporadically), misfeatures that appear to offer a particular benefit but reliably end up doing something different than expected, and the kind of essentially non-deterministic results of various user operations that become increasingly common as "user-friendly" feature enhancement development runs amok to the point that the only way to "fix" a problem is to reset the entire system to a previously more-predictable state (by, for instance, restarting a computer to get the network configuration working again).
Software development, as a field, represents one of the most important technological advances in human history. It is the magical act of defining systems for automating automation at a level of abstraction unsurpassed -- unless you count metaprogramming as a distinct field. Archimedes is credited with the idea that, given a long enough lever and a stable fulcrum, you can move the world. The lesson to take from this is that greater leverage provides greater power to effect change. Block and tackle provide additional leverage when connected to a simple lever, but parallelization of effort is achieved when you attach a water wheel to the block and tackle, allowing for additional effective leverage by freeing the human operator to work on something else at the same time, thus automating the system, only requiring enough attention from the operator to disconnect the apparatus when the job is done. Automated control systems can abstract away that part of the operation as well, so that we no longer need to even devote that scant amount of attention to the initial task.
Computers, as we generally understand the term today, greatly increase the flexibility of automated control systems, and software development allows us to increase the sophistication of these systems' flexibility of application. Every time a software developer performs the same task several times, that developer should consider automating the task. The most productive software developers spend their lives spawning automated operations, sometimes new and discrete operations, and sometimes meta-operations that are each composed of groups of other operations that are, in turn, each potentially composed of still other operations, to arbitrary levels of sophistication.
The leverage provided by so much automation and parallelization of effort yields power on an ever-growing scale, ever more difficult to measure as it grows. The truth of the matter is that a well-design automated system can provide power through not just primary, but secondary, tertiary, and even more indirect benefits, not only in our own hands but in the hands of others who pick up the same tools and use them in unforeseen ways. Considering the implications of every reusably-generalized software module can be a dizzying experience sometimes.
With great power comes great responsibility, though, as your friendly neighborhood trademark might say. To the extent that we do not exercise that responsibility wisely, the damage we do can undo all the benefits our work could otherwise provide, and the indirect benefits can be eclipsed by indirect detriments as poorly designed reusably-generalized software modules not only end up wasting users' time (as in the case of, e.g., point-of-sale systems), but can even stand in the way of the development of improved solutions to the same problem. A software development craftsman, then, must consider the implications of decisions made in the practice of this craft. Some examples of the generalized principle of virtue may be in order:
Safe software is, as Rainer Maria Rilke characterized beauty, "nothing but the beginning of terror which we are barely able to endure, and it amazes us so, because it serenely disdains to destroy us."
That benevolent serenity may seem natural, and even inevitable, in well-crafted software. The developers who labored over it, however, know that such mercy is the result of painstaking labors, great effort and care, on the part of conscientious software developers who care deeply about the consequences of their work. Just as the "natural grace" of a world-class athlete comes from years of dedicated work far beyond the tolerance of most mortal human beings, so too does the most elegantly designed, humane software come only from the dedication of a craftsman consumed by the need to meet the highest standards of quality.
In practical terms, some of the conceptual constituents of safe software development are careful conceptual design, without compromise in the focus on clean, purpose-built systems; attention to both the fundamental principles of security and the very practical requirements of providing security actual humans will use; and the (limited) guarantees provided by quality software development assurance techniques such as test-driven development.
Benevolent software goes beyond merely not causing harm: it actively does good for the world.
The practical realities of the world make it exceedingly difficult to write code only for projects that set out to improve the world, but the best software -- and, thus, the software the best craftsmen prefer to build -- is intrinsically benevolent. While some such software provides a service or otherwise directly aids some philanthropic purpose, other software simply provides the tools necessary to achieve great things. One of the most broadly beneficial forms of software development is tool building because, while good tools may not enjoy the glamor and drama of slick, marketable products, they increase the capabilities available to tool-users such as the people who build those products. Someone trying to crunch numbers for a medical research project (such as protein folding modeling) can always benefit from more capable, efficient number-crunching systems, and the people developing such systems can always benefit from more capable, efficient number-crunching libraries that make up some critical part of the system's greater whole.
A key consideration in ensuring the benevolent character of the software tools you build is a focus on empowering, rather than restricting, your users. Beyond that, the most important factors in the benevolence of your software are likely to be your own judgement and the opportunity to exercise it. Where you find too little opportunity to exercise such judgement, it may be time to consider moving on to an environment where your ideals may have more influence.
Accessible software is more easily acquired and used, ensuring that its benefits apply to as many lives as possible, and enable as many other developers as possible to do good things with it.
The concrete application of such accessibility may vary wildly between particular cases. Every major change in design and implementation policy should be subject to the consideration of accessibility, though. While bells and whistles may make investors in your new startup happy, with dollar signs in their eyes, and this may be an important consideration for the survival of your world-changing business plan, it is also worth recognizing the loss of accessibility some approaches may impose. If blind users are potentially your best customers, seeing the greatest benefits of using your software as a service, it is worth considering whether a fancy dynamic widget utterly breaks the functionality of screen readers even if they represent a statistically insignificant percentage of your potential customer base. Conversely, if some consideration for blind users would interfere with portability across platforms for your software as a service, when the software does not particularly benefit the blind anyway, you could lose thirty percent of your potential user base for no good reason. It may be worthwhile in those cases to ignore the matter of screen readers until either more resources or better approaches (suitable to addressing more problems at once) become available. Beware any tendency to imagine every such decision features only two options, though; one of those "better approaches" may already be available.
A concern all too often invisible to many would-be technological philanthropists that regularly imposes significant hurdles to accessibility is the matter of licensing. As a license grows more complicated and restrictive, it hinders accessibility more. At the same time, the very existence of a restrictively licensed software tool often stands in the way of the development of replacements with less restrictive legal distribution terms as some of the people most able and inclined to create a suitable, legally accessible replacement are too busy making do with the restrictive implementations already available. At the least restrictive end of the spectrum is software released under copyfree licensing policy without applicable patents, or covered by patents that have been explicitly opened for general use. At the most restrictive end is anything covered by both default copyright restrictions (including anything "released" on GitHub that does not come with an explicit license grant) and patents. Somewhere between the two lies the whole spectrum of software with explicit license terms subject to limitations (copyleft software, software with non-commercial licenses, and so on) and anything with legally treacherous licensing ambiguity.
One of the biggest problems of license restriction, however, ties back into the matter of safety. When your software does exactly what it is intended to do, securely and reliably, to the extent you have the capacity to guarantee such benefits on your own, that does not mean it is perfect. It simply means that other people with different perspectives are needed to see the flaws that remain. Sometimes, you may be lucky enough to be one of those other people at some later time when you look back at what you've created with fresh eyes, but it seems inevitable that for any program more than fifty lines long there will be flaws and limitations you will never find on your own. The aphorism, coined as "Linus' Law", reminding us that "given enough eyeballs, all bugs are shallow", may not provide quite the sustainably exponential software quality benefits we imagine, but it still conveys the essence of an important truth: the more strangers see your code, the greater the opportunity to improve it. Visibility and communication are of critical import in achieving the highest standards of quality. It seems inconceivable to anyone who has spent significant time writing for the consumption of other readers that any great author of the last century would produce work as good without the aid of some editorial feedback, and the fact many professional software engineers disdain all commentary from the peanut gallery is a sad commentary on the state of software development in general.
Care about your code. If you have any talent for it at all, approach your craft conscientiously with attention to even indirect consequences (both good and bad) of your work, learn as much as you can about it, and practice care for the product of your work at every turn, the rest will come naturally. On the other hand, if you find you do not love your craft not only in its immediate particulars but also in its potential (even when the work frustrates you), it is possible your calling lies elsewhere.
The final prerequisite for craftsmanship -- or, perhaps more appropriately, the first prerequisite -- is the love of the craft.