This pages collects a variety of general information and random thoughts related to software development.
Every developer should operate from a baseline set of ethics in their professional capacity.
This is a personal belief since, for better or worse, there isn’t a formal path to being a software developer that flows through a single, unified professional organization that reinforces a shared set of ethics. And even so, it’s not as if that is a panacea for creating 100% ethical actors either. Still, I believe each individual should make a personal commitment to themselves and society.
The IEEE/ACM co-authored The Software Engineering Code of Ethics and Professional Practice is probably the closest thing to an industry-wide standard. Others existLike the British Computer Society’s Code of Conduct
ACM’s more general Code of Ethics and Professional Conduct for all its members is a reasonable reference point as well.
There is no algorithm to determine if this or that decision is the (most) ethical one and the aforementioned codes are not perfect nor all-encompassing rules to follow, they are merely a handful of principles to value. Some of the consequences of the principles are fairly straightforward to derive, others perhaps less so. But first and foremost, you have to care about what you are doing. Please care.
Recognize the influence of your work and consider its consequences. Push back against those that would use your skills for ill.
As a Profession
The term “profession” or “professional” gets thrown around a fair bit.
A formal profession is broadly characterized by:
- A distinct body of knowledge
- Training or education programs
- An established set of ethics
- Generally a full-time occupation
- Generally a component of continuing education (because of said knowledge and training)
Software development has varying degrees of these characteristics. But my point is not to get into a discussion about whether software development a real profession, but rather to highlight that I think many of these aspects are things that developers should be taking to heart. We should act as professionals even if some might argue the details of if development work fits a profession.
As the previous section touches on, I think upholding a set of ethics in your work is of real importance. Regardless of your personal feelings or practices, always keep in mind when acting in your professional capacity of what you are doing aligns with your professional ethics.
Another important point here is continuing education. Just as a doctor using a procedure that has been shown to be ineffective in modern research or a engineer signing off on building plans without performing all standard analysis, a developer working in a time capsule from a 10-20 years ago taking (professional, legal, and ethical) risk.
People are allowed to make mistakes, but when implementing things against the standard best practices of your field, you begin to take on greater responsibility for those decisions.
You are responsible for keeping up-to-date with your field.
Developer vs Engineer
You’ll probably be paid more if you call yourself an engineer, but “engineer” may be a protected title in your jurisdiction, so be careful.
In practice, it is more a craft or art than engineering.
It really hasn’t been broken down as a discipline. Objective measures and formalisms are hard/impossible to implement or are heavily resisted by practitioners (that theoretical stuff is too impractical, slows me down, I don’t understand - and don’t want to learn, etc.).
It also varies in time, place, and kind of work.
Have empathy and humility. Too often in technical conversations it’s easy to think something is objective and concrete, when it’s often just people trying to find the best solution in (usually) murky and complicated situations.
The GNU Kind Communications Guidelines are a short and simple starting point.
This doesn’t mean quieting your experience and expertise on a subject, but making effort to communicate that fact clearly.
Avoid feeding into the contempt culture that is rather prevalent in the developer community, most notably talking down about certain programming languages or tool choices. In private, among close friends, it can be fun and bonding to poke fun at each other, encouraging it in public discourse builds toxicity.
When designing systems, one must take care not to bake in poor terminology that then gets perpetuated for the life of that system. Some common examples.
Master/Slave terminology is at best inaccurate and should be avoided.
All better describe the situations.
Similar for blacklist/whitelist.
Are more accurate replacements.
Terminology, Power, and Inclusive Language in Internet-Drafts and RFCs contains some further discussion on this.
Know your tools
Like any crafts-person, know your tools and use them responsibly.
Really try to understand the things you are using. Often developer tools may not be the most intuitive, especially for folks just coming into the area. But avoid blindly copy-pasting commands. Look at the documentation and try to understand what something is doing. Read the documentation before using a tool.
This relates to software choices, languages, libraries, frameworks, etc., but also the physical aspects, your keyboard and mouse, even your posture. You are going to be living with this stuff, put some effort to optimize and understand how to most effectively utilize it.
Until we all have safe neural interfaces to utilize, our work must be actualized with physical movements.
- With your head in a natural position facing forward, your eyes should naturally rest in the center of the upper third of the screen.
- Screen should be about an arms length away.
- Your forearms should be a 90 degree angle with your hands on the keyboard.
- Move! Don’t say in one position for too long. Take breaks, walk around, stretch.
Generally speaking, laptops are ergonomic disasters. If you are on the move all day, you may be okay, but if you working on the computer to large chunks of time, your body will thank you if you aren’t hunched over the laptop.
At minimum get an external keyboard to use, allowing you to raise the laptop screen to a proper height when you are stationary. An external monitor would be the next step up.
Sweet government guides:
Don’t join a cult
Don’t unquestioningly adhere to some idea. We can’t do this or that because we’re Agile. Process and methodology are there to help, if they aren’t helping you in your situation, modify it, try something else entirely, or use your experience to come up with what works for you.
There is no perfect programming language or development process. There may be a “best” under a limited set of constraints, but often these things come down to which is “least bad”.
People who aggressively try to claim this or that language, framework, or tool is just the absolute best, bees-knees, magic that solves all your problems likely:
- Haven’t used it for real
- Just discovered it and are in the honeymoon phase
- Haven’t yet hit the edge cases with it
- Are trying to make money off you
- Or they joined a cult
Don’t be like them. There are good, even great tools out there, but virtually nothing that approaches perfection or is devoid of any characteristic that makes it unsuitable for certain situations.
Of course some advice/processes should be strictly followed unless you really know what you are doing, like don’t implement your own crypto.
So don’t automatically think you know better either. Some things are hard won lessons and some things are ideas pushed by people wanting to make money consulting on how to do something “right”. It can take a little experience to be able to sniff out the difference.
Avoid the cults. Embrace the useful. Stay open minded.
Most things are more complicated and nuanced than they seem. Any single individuals personal experience and knowledge almost never encapsulate the full scope.
This blog post in 2010 titled “Falsehoods Programmers Believe About Names” kicked off a trend of articles exploring common bugs made by those creating systems, particularly related to bad assumptions.
Most are worth reading. A good collection of them organized by topic: https://github.com/kdeldycke/awesome-falsehood
Laptop choice for Linux
My general recommendation is a Thinkpad X or T series computer. Used ones are great.
As a career
This might help you think about if it’s right for you: https://waitbutwhy.com/2018/04/picking-career.html
Common progression/expectations: https://etsy.github.io/Etsy-Engineering-Career-Ladder/
Think about if you are interested in management. Many places do not have a very tall ladder for technical work/folks, pushing management roles at higher levels. Every place is different, but something to keep in mind.
In an better world all workplaces would recognize fluid movement between manager, lead, and so-called Individual Contributor (IC)IC is a bad term, but it’s a common one, so using it. Better distinctions might be Makers and Organizers or Doers and Planners
role over time as a person’s desires and capacities change, managing for a while, transitioning to an IC for a bit, moving back to managing, transition to leading a team, etc. without being closely tied to compensation. Being a manger is not a promotion, being an IC is not a demotion. These are different skillsets to exercise.
In the most essential sense, you can not be paid what you are “worth” and you are not the money you make.
But having a sense of the going rate for your industry is a powerful tool you should have in the belt. Getting a good gauge of this can be difficult and it can vary wildly based on organization size, industry, location, etc., so take it all with a huge grain of salt, but some places to look at:
And note, for better or worse, compensation is almost always highly negotiable.
A disparity in salary for remote work makes little sense to me. People doing the same work should be paid the same.
Don’t self-select yourself out of a position, often the “requirements” listed aren’t actually hard requirements. Apply anyway if you’re interested, the worst case is they say no quickly and you can move onThough going through the application process can take a non-negligible amount of time, don’t mean to imply applying is free and easy. But if sufficiently interested in an opportunity, just want to point out job descriptions don’t always reflect the actual requirements.
, but you may also get a chance to show them all the things about you that aren’t captured on a piece of paper.
Any place worth working for is going to put higher value on you being a good person who cares about others more than raw ability. Tech skills can be built and honed pretty easily.
Experience and ability are important, of course, but don’t cut yourself out of the running because you don’t quite fit the “requirements” on paper.
Also, recognize that many (most?) jobs don’t get filled from cold contacts.
Types over tests. Aim to make invalid states unrepresentable in your system. States that can’t exist, don’t need to be tested. Types are tests you don’t have to write; the more of your problem domain you can encode in your types the more your typechecker effectively runs thousands of tiny unit tests.
This of course requires a reasonable type system, which may not be available to you. And even so, not everything can or shouldEven if possible, if it takes so much bending, contorting, and complexity to make happen, the cost often isn’t worth the benefit.
be encoded in a type system, you will still need tests to cover all the desired functionality.
The first step to writing tests is writing testable code.Even if practicing TDD, writing test code covering desired behavior before the implementation code, that’s still code and your test setup may need to guide the implementation to the right (outward-facing) architecture.
Structure as much functionality as possible as pure functions (and immutable data structure). Pass any required data into core functions (instead of having them fetch what they need), which they process and return new data (instead of mutating some existing state directly). Push state mutation and interactions with external systems further up the stack.Though the details vary, most popular software architecture ideas have this as a core aspect, Hexagonal architecture, Clean architecture/SOLID, Onion architecture and so on. Characterized by Gary Bernhardt, perhaps most simply, as Functional Core, Imperative Shell.
This makes writing tests much simpler.A sequence of data transforms flowing between functions is also easier to reason and understand in the first place, in addition to being easier to test!
When writing tests, in general want to focus on the behavior of the code under test should have, not its specific implementation.If you find yourself having to mock out a bunch of stuff, try to patch internal functions of some feature in order to test them, that’s a signal your architecture could be a little off. See if you can structure things such that your tests can run without having to mock out pieces.
Instead of manually creating and maintaining various kinds of test data, consider if property-based testing can be utilized to automatically generate test cases that cover a large degree of the possible data space (instead of only the situations you can think of):
- Haskell: The original property-testing library QuickCheck is still around, though a more modern implementation like Hedgehog is likely preferable.
- Python: Hypothesis
(for other languages, searching “<lang> quickcheck” will probably get you somewhere, though implementations vary widely in quality)
For web applications, tools like Quickstrom may be of interest.
Most applications will feature lots of interactions with shared state (e.g., databases) and external systems, only unit testingUnit in this context generally meaning the “smallest” testable piece of your system, this could be a single function or a class. This doesn’t imply every single function must be tested independently. For example, a function that itself calls a couple internal/helper functions, the helpers don’t necessarily need independent tests, you can just test the main function’s behavior, particularly if the main function is the only part used externally/outside the “unit”.
can miss capturing important aspects of these interactions. While it’s often impossible to write many tests directly against real external systems, testing code interacting with a real database can be useful.
The higher level functionality that strings together lots of the core functions (that should be well covered by unit tests) and does the I/O can have simple “integration” testsIntegration tests generally mean an test that covers multiple “layers” in your system, testing how parts integrate.
where they are provided with a connection to a real database and the critical combined behavior is tested.
These small integration tests, tests that actually touch the database, can be a pretty good value on balance since they cut across a stack of functionality, but are still only concerned about “your” system. Setting up and running database tests so that they are performantAt the very least, mount your test database on a tmpfs or turn off fsync.
and usefulFor example, you probably don’t want to duplicate every possible scenario you’ve covered in separate parts via unit tests. Focus on the integrated behavior for important spots.
is a topic for another time, but of various general strategies, the ones I’ve found the best are 1) wrapping tests in transactions (good for simple stuff) and 2) creating unique schemas for tests (good for more complex stuff and as a foundation for mixing with 1.).
Depending on the situation, it may be possible to write some tests that cross system boundaries, testing full lines of functionality from initial user input to some final state. These can be expensive to setup and maintain, likely only covering the most critical pieces of functionality.
TL;DR: Lots of types, many unit and property tests, some “integration” tests for larger pieces, and finally system/end-to-end (E2E) tests for major lines of functionality (where possible/necessary).
Like any field/group of people, there are words, phrases, shorthands, ideas that either more commonly pop up or are unique to the space.
I’ll try to stick to some of the most common or useful things you might come across, with maybe a few things I just find funny as well.
Much more complete glossaries exist, such as the older Jargon File/The (New) Hacker’s Dictionary (last updated in 2002), whose home page links a variety of versions/resources and whose glossary page may be of use and slightly newer The Newer Hacker’s Dictionary (last updated in 2012). Many historic versions are available at jargon-file.org.
- what people call whatever it was they were already doing to sound “modern”, anyone using this term unsarcastically is to be treated with suspicion
- Authentication, validate who someone is
- Authorization, validate what someone can access/do
- Benevolent Dictator For Life, often the case in FOSS the person who creates a project has control (informal or formal) over the project (but is generally kind)
- arguing over minor issues, e.g., committee debating what color to paint the bicycle shed when they are tasked with reviewing plans for a nuclear power plant, shorthand for the Law of triviality
- an unwanted or unintended behavior in a system
- Cathedral vs Bazaar
- contrasting software development styles explored in the essay/book The Cathedral and the Bazaar; roughly, the “Cathedral” being where development happens behind closed doors, the “Bazaar” where all development happens in public
- Command Line Interface
- Don’t Repeat Yourself, summarized as “Every piece of knowledge must have a single, unambiguous, authoritative representation within a system”, sometimes unhealthily taken to mean never duplicate piece of code, when in fact having similar code copy-pasted in two locations may in fact the simplest and most maintainable solution rather than choosing an incorrect abstraction (some will say 3 similar patterns is a sign to refactor, see Rule of three)
- Do What I Mean
- duck typing
- if “thing” X has matching properties/methods from Y, allow treating X as a Y when type checking, “If it walks like a duck and it quacks like a duck, then it must be a duck (even if it’s a goose)”
- dynamic typing
- type checking is done at run time, i.e., needing to run the program in order to check types, see static typing
- Editor War / Emacs vs vi holy war
- (generally) humorous “debate” about which editor is better that has raged since almost the dawn of modern computing
- Enterprise Grade
- often means Expensive Garbage
- foo / bar / baz / qux / quux
- metasyntatic variables, generic variable names often used in examples
- Free(/Libre) and Open Source Software, see Free Software
- Free Software
- software that promotes freedom in its usage, not related to cost, popularly captured in the phrase “free as in freedom, not free as in beer”
- Graphical User Interface
- Looks Good To Me, common expression for signing-off on/reviewing something as ready to proceed
- Multi-version concurrency control
- Minimum Viable Product
- Minimum Working Example, the smallest simplest thing that shows a behavior, often to reproduce a bug; similar/related terms: SSCCE
- Open Source Software, software whose copyright holder makes available to study, use, and distribute for any purpose; the “source code” is “open” to study and use; see FOSS
- Problem Exists Between Chair And Keyboard, i.e., a human is the problem
- The Purpose Of a System Is What It Does
- Project management triangle/Iron triangle
- “Cheap, fast, or good. Choose two.”
- Please Take A Look
- pure function
- a function whose output is totally determined by its inputs and has no side effects; think of a mathematical function
- regular expression, a search pattern
- Request For Comments, format/style of publication used by internet standards bodies and though the name implies something more in a draft state, RFCs retain their designation even after adoption/approval as formal standard
- Read The F-ing Manual, i.e., the thing you are asking about is explained in the documentation, so read that; often used in a hostile/dismissive way
- Rubber ducking/Rubber duck debugging
- working through a problem by trying to explain/talk through it to an inanimate object (a rubber duck being the classic example)
- side effect
- modifying state outside of a local scope
- Situation Normal: All Fucked Up
- Standard Operating Procedure, sometimes called a runbook
- sound type system/typing
- when a value is guaranteed to have the type that the type system determines; alternatively stated as if a program type checks at compile time it is guaranteed to have no type errors at runtime; can also been seen as stating it rejects all incorrect programs
- Short, Self Contained, Correct/Compilable, Example; similar terms: MWE
- static typing
- only needing to look at a programs source code/representation in order to perform type checking, see dynamic typing
- strong types/strongly typed
- broad categorization, a language where each “thing” has a distinct type and can communicate this among parts of the system, often avoiding implicit type coercion/conversion (e.g., if you want to use a number as a string, you have to explicitly convert it to a string), see weakly typed
- tech debt
- decisions to delay doing more complete/correct work in order to get a more limited/easier solution delivered quicker
- Version Control System, e.g., git, mercurial, darcs, pijul
- weak types/weakly typed
- broad categorization, often a language with very few distinct data types, often with lots of implicit type coercion/conversion, see strongly typed
- Work In Progress, used to indicate something isn’t done, that it’s still in a draft state and isn’t ready to be used as is
- What You See Is What You Get, generally more visual based system, what it looks to you creating it is what the final output looks like
- What You See Is What You Mean, interface that focuses more on the content over specific formatting, what you see is more the structure of something, the exact appearance of the final output is determined by style sheets or other processing
- Yak shaving
- when you are doing something several layers removed from what the problem you are actually trying to solve, see Hal fixing a light bulb
- You Aren’t/Ain’t Gonna Need It, avoid premature optimization
- Your Mileage May Vary, it worked some way for me, but it may not work the same for you
- Zero one infinity/ZOI rule
- general rule of thumb to not put arbitrary limits on the number of a particular entity/state, either it should be forbidden in the system (zero), unique (one), or any number allowed (infinity)
Proverbs/adages/things named after people
- Ballmer Peak
- (mostly humorous) idea that there is a small range of blood alcohol levels where one has heightened programming ability, further explanation
- Conway’s Law
- often stated as “organizations design systems that mirror their own communication structure”
- Fairbairn threshold
- point at which looking up or keeping track of a definition is outweighed by the effort of re-deriving it
- Goodhart’s Law
- perhaps best phrased as “When a measure becomes a target, it ceases to be a good measure.”; one of a number of related ideas broadly informed by the facts that 1) not everything that matters is measurable and 2) making a target out of a measure leads to its manipulation/perversion, in the process losing its value as a measure itself; restated slightly, when the measurement itself begins to matter, it ceases being a passive watcher of a system, it ceases being just a measure
- Greenspun’s tenth rule
- “Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.”, re-spun in various forms by someone wishing to express the folly of not providing extensibility, e.g., this tweet
- Hanlon’s Razor
- “never attribute to malice that which is adequately explained by stupidity”
- Hofstadter’s law
- “It always takes longer than you expect, even when you take into account Hofstadter’s Law.”
- Linus’s Law
- “given enough eyeballs, all bugs are shallow”
- Murphy’s Law / Sod’s Law
- generally taken to mean “Anything that can go wrong, will go wrong”Some will call this or a slightly stronger variant Finagle’s Law
, though perhaps Murphy’s Law is more accurately/originally stated as “If there are two or more ways to do something, and one of those ways can result in a catastrophe, then someone will do it.”; in whatever form, often is a call for defensive design, but equally invoked in exasperation
- Parkinson’s law
- adage that “work expands so as to fill the time available for its completion” with many corollaries; in computing applied as “data expands to fill the space available for storage” (which is sometimes called Parkinson’s Law of Data)
- Postel’s Law/Robustness Principle
- “Be conservative in what you send, be liberal in what you accept”I think this can often lead to less robust systems and/or be taken to unhealthy lengths, a system should generally be strict in both input and output
, also known as Postel’s Prescription
- Sturgeon’s Law
- “ninety percent of everything is crap”, also known as Sturgeon’s Revelation
- Zawinski’s Law/Law of Software Envelopment
- “Every program attempts to expand until it can read mail. Those programs which cannot so expand are replaced by ones which can.”