Distillating years of experience in such tiny concepts is a bit harsh on the reader. Without any concrete example, the advice could easily be very misunderstood, or not understood at all.
Being a fairly seasoned developer myself, I kind of intuit what they mean, but I could very well be projecting what I think I am doing right into each of these, and conclude that I'm a master programmer... yay!
This is the crux of the problem with a lot of software engineering culture as it stands today - blog posts and talks frequently deliver abstract concepts that only really make sense to people who have already grasped/discovered those concepts.
The enlightened sit nodding along, while the unenlightened go away confused or misled. Positioned this way, half-understood ideas frequently do more harm than good.
TDD is a great example of this.
In this case, though, I think the article does a fairly good job - it highlights productive ways of thinking that will incite useful self-reflection ("Do I do this? Could I do it better?") rather than half-communicating ways of doing.
> The enlightened sit nodding along, while the unenlightened go away confused or misled. Positioned this way, half-understood ideas frequently do more harm than good.
I think this puts a lot of things into perspective for me. There will be a blog post about some topic on HN, and it seems that everyone in the comments just gets it. Yet I'm over here like, "Yes. I know some of those words. Maybe I'll get the concept a bit more next year." Time passes. I'm still none the wiser.
Functional programming was one of those weird topics for me when I first started programming. It's pretty straight forward on the surface. Some X has to go in. Some Y has to comes out. If it didn't originate inside the function, then it does not get touched. Yeah but why? Who cares if I have a variable outside of the function scope that gets modified? Didn't I declare it globally specifically to have access to it anywhere? What's the point of all these stupid rules when languages give me the ability to do so much more? But all these people can't be wrong, can they?
So I shoehorned it in. I tried to make everything I wrote as functional as possible. I started creating convoluted, over-engineered garbage that was needlessly complex. Nothing felt right about it.
Then I actually tried it. I sat down with a somewhat pure language to learn functional concepts, and it clicked. I see why people extol the virtues of functional programming. Like you've noted, not understanding the reasons behind using functional programming can lead to a convoluted mish-mash of cleverness that doesn't belong.
Another problem that I've noticed with FP especially (although I get the impression that OOP had this problem too when it was the new hotness, and I've seen hints of it happening with Rust) is that there seem to be a lot of novices who fall in love with the concept and start evangelizing it, convinced that This Changes Everything. But they can't back it up with a lot of practical experience, can't describe any caveats or limits to its scope, don't have useful knowledge of the practical pitfalls, and so on. So when you bring up something in your domain that seems like it would be difficult, they don't have the foundation to say "this is how you solve that kind of problem" or "yeah, that's still difficult". Instead they deflect or try to subsume it under some vague principle that doesn't actually address your concern.
> ...deliver abstract concepts that only really make sense to people who have already grasped/discovered those concepts...TDD is a great example of this
Thank you! I'm glad I'm not the only one who thinks this. There's an abundance of articles explaining how to "best" test, usually using an overly simplified example (I'm looking at you, `add(a, b)`). When you try to apply it in the real world, things break down because no one explains how to deal with the icky practical issues.
Despite all these resources online teaching you how to test, I feel that how to test well in real-world scenarios remains tribal knowledge.
> The enlightened sit nodding along, while the unenlightened go away confused or misled.
It's the same with maths. It's even worse when the concepts are explained in a circular way. Go to wikipedia and search for a random mathematical concept. I guarantee you that most of the terms used in the explanation have wikipedia articles that link back to the concept you looked up in the first place! Frustrating beyond belief. You need to get a foot in the door and then it's easy, but before that it's hell.
I think this is a fundamental problem of learning and teaching, especially via text.
It's also that most people who teach just don't have Feynman levels of understanding. Mostly we are all kind of groping in the dark, and we all participate in some kind of cargo cult.
I also think there's a deep problem with how people want to learn math, and other abstract concepts. Look at how frustrated many students get by notions like imaginary numbers, groups, and monads. These things provoke some serious anxiety and confusion because students want to understand what they "really are" in some clear and straightforward way, when really all they are is hard-won abstract definitions that have proven interesting or somehow useful.
In a way it's disappointing that math books need to have "exercises." Why can't they just explain in a comprehensible way? I guess it's because the topics of study are abstract relations that only sometimes have some analogy in the "real world" (of course, some mathematicians believe that the structures of mathematics are in some sense the most real of all)...
> The enlightened sit nodding along, while the unenlightened go away confused or misled.
It's even worse (and quite common) when those who don't understand are the ones nodding along. Knowing when you really understand something, and when you don't, is such an important milestone for people to get to, and quite hard to teach.
> This is the crux of the problem with a lot of software engineering culture as it stands today - blog posts and talks frequently deliver abstract concepts that only really make sense to people who have already grasped/discovered those concepts.
I'd like to see a blog post on just that point. well said.
Perhaps this format is not for everyone, but I like these concentrated nuggets of wisdom. Sure, you could write a paragraph or two on each. But with this approach, each item gives the reader a prompt to think about, to identify areas in their own practice that need more focus and improvement.
yes im part of the master programmer club too, unfortunately though, i will not live 3e9 seconds :( and certainly will not have 3e9 seconds in my life to spend on programming.
> Multiple scales. Move between scales freely. Maybe this is a design problem, not a testing problem. Maybe it is a people problem, not a technology problem [cheating, this is always true].
The key to this is realizing that once you decide a problem is at a certain scale, the fix needs to be at that scale too. So you might have a data problem, a code problem, a workflow problem, a design problem, an architectural problem, a team problem, a project problem, an organizational problem, a leadership problem, or an existential problem. (on the level of the company)
Each type of problem has to be resolved by the resources on tap at that level. You fix data problems by editing the data. You fix code problems by changing code. You fix leadership problems by changing leaders. You fix existential problems by changing jobs.
Becoming a more effective programmer involves understanding at a deep level how everything interlocks and moves together. If you can't solve it at one level, escalate to the next level and try to solve it there.
So you might have a code problem that you get pushback on fixing, this makes it a design problem. So you get the stakeholders in a room to come to a decision about what the code should be doing. If they can't come to a decision then it's an organizational problem, so you go to the leader for a decision. If he can't make a decision then you've got clues to a hidden leadership problem at the company.
Problems should be instantly solvable once you get to the level they're really at. You don't escalate though until you know enough about it to make a short presentation to the next person in the chain.
Once you get above the workflow level, you're in the realm of politics. Political problems are defined by the fact that multiple people in the organization care about it and you need to get sign-off before you go and unilaterally change something.
I think the best way of thinking about it is to split problems up across levels. So if you have a code problem that you've worked out to be a design problem, you now have two problems. The higher level one needs to be fixed before you can fix the lower level one.
So the client complains about software behavior. You now have a client problem. You isolate the issue down to a problem in the data. You fix the data but the problem recurs. You now have two problems, a client problem and a code problem, that's generating the bad data. You go to change the code but find a design problem. You now have three problems. You have to solve the design problem so that you know how to fix the code, so that you can then go tell the client that his problem's fixed and here's a free month's service for your trouble.
Well analyzed, this is how real-world 'software problems' are interlocked one level to another and YES splitting problem across levels is way to go.
Here is one thing I gained from this Analysis. At times we encounter 'a Code problem' partly caused by ' a workflow problem' and partly caused by 'a Design problem' .
We may do a CODE patch fix for time being (ex. production bug), but having it documented as '40% Workflow problem, 60% Design problem' will help to consolidate all these 'contributing percentages' to come up with permanent fixes at a Later time.
> The higher level one needs to be fixed before you can fix the lower level one.
well sometimes problems have workarounds, otherwise the poor 100x programmer would have to solve all existential problems first. (maybe a 1000x programmer could do that, when he finally reveals himself)
More complex though, is the ripple effect each has on others, dependency on others etc...
Far more nuanced than Maslow's
A shitty team can produce great code - a great team can produce shitty code. A shitty leader can kill a great team. an existential problem can destroy the value of any data-set. etc...
overall I totally agree with you and OP, and thinking through this is a great idea.
The corollary to this is to never solve the problem at the wrong level. It's always a recipe for pain when you, say, have a data issue and you decide you'll solve it with some clever code. Or perhaps you have a fundamental design problem, but maybe you can just tweak the data...
There's a concept from SEI's CMM levels that attempting to maintain an impedance mismatch of greater than 1 between different parts of the organization ends in pain.
I think in this case I agree with GP that it is possible to 'solve' a problem at one degree removed from the source if there is no way to actually solve the problem at the source.
So for instance, lots of people write code to scrub janky data from a partner (indeed, that may be part of the value you add to the system).
Projects exist to serve a business need. Teams serve the project. Projects can develop problems that the team can't solve, for instance if an e-commerce project is losing revenue for business reasons rather than technical reasons.
These problems have to be tackled by management. Management has to change the scope and goals of the project so that the design team can better create deliverables for the engineering team to build.
Once you get to this level, generally the coders can only raise issues, they don't have the expertise necessary to actually recommend solutions.
About the only thing a coder can do if he sees something like this is to work really hard to actually understand what's going on, raise his concerns to management, and if he doesn't like their answer, get another job. Because chances are, if the project dies, so will his job.
Having spent entire days years ago poring through the JUnit 3 source code and having been completely dejected by the quality of the code there, I don't really trust Kent Beck to give advice on anything related to programming.
TestNG exists because of how inflexible and leaky the abstractions were in Junit 3. Junit 4 exists in large part because of TestNG.
I think that pretty clearly illustrates that Kent and Ward were wrong and Cedric was right. And yet I still listen to both of them about other things.
Nobody has it all figured out. You figure out what things you can trust a person about, and you learn from them, and you move on to someone else for some of the rest.
[edit] But I confess that I have a similar relationship to Josh Bloch that you have to Kent Beck. I can't listen to code advice by someone who wrote 2 collections APIs without understanding the basics of variance or apparently even the Liskov Substitution Principle. Throwing exceptions because you decided not to implement part of a public interface is an unforgivable offense that others have duplicated because if it was good enough for Josh it was good enough for them. He has done next to nothing to atone for that sin. You aren't an effective programmer. I don't want to hear you talk about the subject you so obviously know nothing about for 500 pages.
I've seen a lot of programmers that love design patterns, SOLID code, and hip new frameworks; but hate talking to users, getting stuff shipped or keeping things running.
Even if the code is "messy" and given that JUnit is used by millions of programmers hourly without trouble, I suspect Kent prefers the latter to the former and which makes him a master programmer in my book.
> I've seen a lot of programmers that love design patterns, SOLID code, and hip new frameworks; but hate talking to users, getting stuff shipped or keeping things running.
I think these tasks are not meant for programmers in the first place. But indeed it's beneficial when programmers know how to handle those things properly.
Hrmm, this is an interesting observation. In general I'm not a huge fan of Kent Beck or Uncle Bob as I've felt that their zealotry for "clean code" gets in the way of them actually creating valuable software.
I've always been of the mindset that if the code isn't a little "gross" it's probably not doing anything very interesting.
> completely dejected by the quality of the code there
Please list a project of equal complexity that has been written beautifully from start to finish in your opinion.
This myth of beautiful coding needs to stop! Code is not a masterpiece from Van Gogh, it needs to ship. This determines quality, not the usage of some obscure/mainstream/unreadable/oh-look-how-cool-I-am idiosyncracy of the language.
If you ain't shipping, it's completely useless.
The biggest thing holding programming back is that we insist that our domain is somehow unique from hundreds of other domains that have centuries more wisdom at their disposal than we do. We reject out of hand the notion that because we've only been doing this for 60 years means that we really have no idea what we're doing yet.
We believe we are more like machines than like other people. But at the end of the day we're the same trumped-up monkeys smashing away with imperfect tools.
If you look at our fellow productive monkeys, they aren't using the prettiest tools, no. But the tools they are effective with have a certain beauty to them. They often have a single purpose, and they do it very well (the Unix model knew this 40 years ago). Nicks and dents don't matter, unless they're on the working surfaces, in which case they have to be repaired or replaced, so resilience in certain dimensions is an absolute must.
A master does learn to work with their tools instead of against them, but within reason. If a better tool is available, or they can modify the existing tool to fit them better, they won't hesitate for a second to do it. That is what is meant by 'A craftsman does not blame his tools.' If you know you're using a bad tool, that's your fault. Get better tools.
I'll take your assessment at face value (although a quick look at github repos, it seems that junit is way larger).
My point wasn't to ship crap, it was about obsessing on quality over actually shipping (and cutting some corners). This is something I learned at my first job, we obsessed over quality and never shipped. Guess what happened? :)
wow thats the biggest cop out i've ever heard. quality 100% matters, if not even more. shipping crap code still makes it crap and it will come to bite you in the end.
libfreetype is an example of a great library, clean and well documented...
beautiful coding isn't a myth, it actually works... write code like poetry and it pays off 10 fold... less errors, easier to reason about, malleable... the benefits are extreme... try to actually experience something before making unfounded claims... i've been writing beautiful for over a decade now... once you realize code is written once and read 100 times, you'll come to the realization of doing it clean and right the first time pays of in the future, which means less work and bullshit...
Just because I say beautiful code is a myth, doesn't mean I and other people write crap code. If you have to make an argument, don't start off with extremes. I'm sure you've heard much worse things than some random stranger saying beautiful code is a myth. Dial down the hyperbole...
> write code like poetry
When a code base reaches a certain size it's hard to write "beautiful code". Please don't pretend that it is just as easy when you have multiple complexities/priorities. If you write so called beautiful code in complex projects, good for you.
I think such posts (and books) are usually meant like checklists for people who already knows that stuff (not learning it), but want it formalized. Then when you have issues for example with team members, you can look at those resources and try to assess why something is going into the wrong direction. It's easier to enumerate those points then.
It seems this kind of posts/books is more aimed to selling oneself as a consulting business process expert in a corporate market than to teach anything to the practitioners. It's a bunch of soundbites aimed at a dilettante.
I had a friend in college who wanted to be a writer. She was paranoid about spending too much time on comparative lit and setting the bar too high for herself before she ever got good at it.
As far as I can tell, she didn't avoid that trap, despite identifying it. Occasionally I wonder if I avoided it. There are so many ways for a project to fail and when you know too many you can become a nervous wreck. Over most of the course of the '10s I've noticed that I'm a lot more comfortable with certain classes of imperfection, because they are immaterial to the job at hand, or represent an unknown that we haven't tackled yet (if you don't know how something should actually work, making it 'perfect' might make it perfectly wrong, and then where are you?). It's like a chess game. Half the board is full of pawns to be sacrificed for some higher priority. You have a contingency plan for any threat, but you can't act on them all at once.
Probably everybody does this, but their set points are different than mine, so we argue over code reviews.
I think all code at a certain scale has it's fair share of messiness, it's just unavoidable as the battle becomes not so much about code quality, but the cognitive difficulty of keeping everything in the human brain. I am no fan of the OO design-patterns dogmatic approach and that whole cultish paradigm hurts my eyes when I look at it in code form, but I understand how even the best programmers in a field get into this situation.
If you're a new programmer, I don't think you should start from OO. OO-based languages are built on procedural, structural and imperative programming foundations. Starting from OO may force you to see everything as an object even when it doesn't fit.
The less you start off with, the better your understanding will be, and then you should learn to expand your horizons with other programming paradigms: logical, functional, and many others.
I know that a lot of universities (mine included) introduce programming through object oriented programming so this could be a problem for a lot of people going into university without much if any programming experience, much like I did. I've been interested lately and reading more about functional programming though.
Through object oriented programming or through a programming language that can do it? Many programming introductions start with mostly procedural/imperative, while using a language that has OO (and which is then introduced later in detail).
Totally agreed on other paradigms not being teached enough though.
OO is more an organizational method than a programming method; it still falls down to being imperative (do this; do that). OO is nice when you have a lot of types and few actions whereas non-OO languages are nice when you have lots of actions and few types. When there are a small number of types and actions, it really doesn't matter which organization method you use, but if you expect the types to grow, use OO. If you expect the actions to grow, don't use OO. If both are expected to grow to large numbers, there still isn't a good organization method yet.
A lot of the comments criticize the article for being inaccessible to beginners, and I think they're justified—without examples it's hard to know what the author is talking about without having first passed through the fire.
Having said that, I think he's talking about a crucial part of programming that beginners simply don't appreciate: how to break big problems into small problems. In other words, how to unstick challenges (and even find joy in programming) before writing a single line of code.
For example, make a list. Prioritize the items. Strike some. Put the simplest at the top. Figure out which item causes you the most anxiety. Chop away at the branches before attacking the trunk. Even intermediate developers often fail to see that the best programming takes place in the form of a plan.
I would say don't work on the branches first. If something is simple and predictable, it can be done later. (This also allows you to slowly converge on a completion date since all the stuff you've put off is simpler and easier to understand and predict in terms of schedule.)
Best to work on the challenging, unknown items first, especially if they form the core that everything will rely on. It gives you time to work out the kinks in the overall architecture. It's much harder to change those things later and harder to predict how long it will take. It's also easier to mock out and fake the branches.
I think we're talking about the same thing from two angles—when a task appears uncertain, it's important to isolate it. Sometimes, as you suggest, it's an exploration (build the engine before the body to see it turn over), but other times you can chip away at a problem, piece by piece, until there's no problem anymore.
This looks like an outline for a potentially interesting article. But the language is too vague to even know how to react to the ideas. What is meant by "extracting a subelement"? "Make the problem easy" sounds great but could mean lots of different contradictory things. So please write the articles being hinted at in this outline, but as is, it's a bit tough to get anything from it.
I agree with you even though I disagree with most of the criticism of the article here.
I feel like I know what Kent is talking about behind most of these points, even though his words only hint at the deeper principle. He's trying to be too brief, but I can tell there's depth there.
For many of the points, I had to think a bit, and then it clicked, "Oh, he's talking about xyz. Yep, he's right. But his words don't really say that."
Kent Beck is not some AbstractFactoryStrategySingleton fool. I've learned a ton of insights from him, and I've seen him articulate insights that I had stumbled across and incorporated, but had not been able to articulate.
I'll grant you that some other talking heads often lumped in with Beck have been overhyped and their rhetoric has run ahead of their insight. And no one is perfect. But Beck usually has real insight behind what he is saying, and this IMO is no exception.
Extremely disappointed in this post to the point where I believe that the only reason people upvote this is because it's written by Kent. A lot of it reads just like motivational instagram posts. For example:
> Call your shot. Before you run code, predict out loud exactly what will happen.
M, okay, but what exactly do you mean by that? Or even poetic, kind of:
> Rhythm. Waiting until the right moment preserves energy and avoids clutter. Act with intensity when the time comes to act.
I have no doubt that each point has some very specific examples behind them and knowing them could actually be useful. But right now, you can only guess what was intended behind these #deep thoughts.
True, they are a bit vague (particularly the one on "Multiple scales"). But a couple of them articulate my experiences better than I could. I think some of the overlooked value of things like this is having a short phrase to encapsulate those principles for your own use.
In particular:
> Rhythm. Waiting until the right moment preserves energy and avoids clutter. Act with intensity when the time comes to act.
I've sometimes gotten bogged down in trying to pull off a major refactor or internal initiative that I had to abandon because it was at the wrong time. It's important to wait for the surrounding social context/business context/preliminary work to be in place before making a major change.
> > Call your shot. Before you run code, predict out loud exactly what will happen.
> M, okay, but what exactly do you mean by that?
I frequently do a variant of this, although not always out loud. One way to debug a problem is to randomly vary various bits of the program until the problem no longer appears. Another way to debug a problem is to use the scientific method: develop hypotheses, then test those hypotheses with an experiment. I think he's saying to develop hypotheses, and then run code to test them.
I routinely use the "scientific method" to debug. But usually by then it's too late: the code is too hard to reason about so I have to treat it like a blackbox and "observe" its "responses" to the "stimuli" I'm changing.
The Rhythm one baffled me as well. I've been coding for 15 years and this bullet was one I couldn't find something to relate to or guess at its meaning.
Maybe it was more of a business aspect/market timing for a new product?
The way I interpret this is: when you work at a company with a fair size, you have to work with the release schedule of the whole company. If you have a large change you want to push (such as a breaking change in a widely used internal library), timing is very important.
You will sometimes need to work very fast in order to push your change while everything else does not change much. In these cases, it's important to be able to enter crunch mode, and it's equally important to alternate crunch modes with slower paced work to not burn out.
I remember writing an essay like this for an assignment. The professor called it 'strange'. Even if I had made some valid points, there was no way to validate them as it lacked real flow. Just bullet points with messages I wanted to communicate but with no real value on their own (and some symbolic paragraphs in between). Good to see a post calling out the naked emperor. The same post had received a better reaction in the comments the last time.
The best way to be a better programmer is to keep motivated, overcome roadblocks, ask the tough questions, and envision the final product. Its that easy.
This document clearly shows that "master" programmers focus on very different things than a beginner might expect. A beginner can get really excited and proud making something complex work without noticing the flaws. After years of debugging your own code you'll find out that getting complex things done is not really the issue, it is HOW it's being done that makes the difference.
Beginners tend to focus on new language features, premature optimisations, having unnecessary strong opinions about wether using a for loop or map or reduce etc.., using too many and buggy libraries, literally copy and use code from others without noticing it's flaws, getting pride from writing complex code that almost no one can understand, trying to beat the calculator, trying to beat Google with your own memory, over estimating the value of linters, CI, TDD, agile, what editor to use, etc.., etc...
All these things take up so much space and energy at the cost of what really matters if you want to do what a master does: write bug free code that is easy to maintain and a joy to read.
'Ideas are like frightened little birds. If you scare them away they will stop coming around. When you have an idea, feed it a little. Invalidate it as quickly as you can, but from data not from a lack of self-esteem.'
Slicing: No. Cut the project into appropriate-sized slices. Cut big slices into sub-slices. Hierarchy is your friend.
One thing at a time: Yes.
Make it run, make it right, make it fast: Yes.
Easy changes: No good changes are hard once you own the result. If a change feels hard it's probably not good yet.
Concentration: That's one of two approaches. IMO either rearrange the code so you only need to change in one place, or rearrange your change so that the code only has to change trivially in any place.
Isolation: Depends.
Baseline: Yes.
Call your shot: Yes, but only because it means "know what you think will happen" which means "understand the codebase". If you're working on someone else's codebase, discard this and replace it with "try things and learn from them."
Multiple scales: Yes.
Symmetry: You mean 'factoring'. But yes.
Aesthetics: We define beauty as solving problems efficiency. If it's ugly but it's the best answer, we'll learn to think it's beautiful.
Rhythm: Yep. A time for all things.
Tradeoffs: Yes. You can't make a call til you understand the context.
Fun list: I guess that works.
Feed ideas: Never be afraid to ask what-if.
80/15/5 rule: Situational. If current low risk work is gravy spend 100% on that. If not, dig into R&D.
"Poor workers blame their tools. Good workers build better tools. The best workers get their tools to do the work for them."
Right now, i am finishing a system that took me 2 weeks do develop. With the standard way, i should have finished it around January of the 2018.
Programming is like anything else... it's a learned skill. Some people will have unusual high aptitude for it, while others will have unusually low aptitude for it. While it's fun to read existential abstracts of programming(like this article), it's better(for me, and all my coworkers, from every job I've ever had) to just practice. Learned skills are refined through repetition. Learn from your peers, and practice, practice, practice. No amount of reading blog posts, or "transcending logic" as the blog post suggest, will make you one iota better at programming.
Stopped reading right there. My experiences have led me to believe that 9/10 Facebook posts of this nature are purely for publicity's sake and not being taken seriously by the author.
I find Beck to be mostly spot on, enjoyed his books on smalltalk and unit testing back in the days. I get the feeling that he couldn't care less who is a master according to what measure, he's just trying to make the best use of his experience by doing and sharing, which is the the only thing that makes sense once you go deep enough down the software rabbit hole.
He talks about common patterns of master programmers, but does not define what master programmers are, and why he thinks they are masters in the first place. I really don't get the point of this article.
If you know you will be stuck working on something for a while, spend a little extra time on each progression, like solving edge cases, performance issues, compatibility, and writing automatic tests for regression. That way you can spend more time on actually adding value, rather then catching fires and debugging.
And if you're new to a team or a company, do not underestimate the value of confirming documentation and test cases(if they exist!) and improving upon them if it's possible. This helps in multiple ways: you gain a reasonable understanding of the codebase through reading and testing; you are immediately contributing value to the team by improving upon the process and making it easier for you to onboard new people when the time comes; you gain the confidence of your team by showing interest in details that may have been overlooked for significant periods of time, allowing cruft to build up and plenty more.
From years of watching master programmers, I have observed certain common patterns in their workflows. From years of coaching skilled journeyman programmers, I have observed the absence of those patterns. I have seen what a difference introducing the patterns can make.
Here are ways effective programmers get the most out of their precious 3e9 seconds on the planet.
The theme here is scaling your brain. The journeyman learns to solve bigger problems by solving more problems at once. The master learns to solve even bigger problems than that by solving fewer problems at once. Part of the wisdom is subdividing so that integrating the separate solutions will be a smaller problem than just solving them together.
Time
- Slicing. Take a big project, cut it into thin slices, and rearrange the slices to suit your context. I can always slice projects finer and I can always find new permutations of the slices that meet different needs.
- One thing at a time. We’re so focused on efficiency that we reduce the number of feedback cycles in an attempt to reduce overhead. This leads to difficult debugging situations whose expected cost is greater than the cycle overhead we avoided.
- Make it run, make it right, make it fast. (Example of One Thing at a Time, Slicing, and Easy Changes)
- Easy changes. When faced with a hard change, first make it easy (warning, this may be hard), then make the easy change. (e.g. slicing, one thing at a time, concentration, isolation). Example of slicing.
- Concentration. If you need to change several elements, first rearrange the code so the change only needs to happen in one element.
- Isolation. If you only need to change a part of an element, extract that part so the whole subelement changes.
- Baseline Measurement. Start projects by measuring the current state of the world. This goes against our engineering instincts to start fixing things, but when you measure the baseline you will actually know whether you are fixing things.
Learning
- Call your shot. Before you run code, predict out loud exactly what will happen.
Concrete hypotheses. When the program is misbehaving, articulate exactly what you think is wrong before making a change. If you have two or more hypotheses, find a differential diagnosis.
- Remove extraneous detail. When reporting a bug, find the shortest repro steps. When isolating a bug, find the shortest test case. When using a new API, start from the most basic example. “All that stuff can’t possibly matter,” is an expensive assumption when it’s wrong.
> E.g. see a bug on mobile, reproduce it with curl
- Multiple scales. Move between scales freely. Maybe this is a design problem, not a testing problem. Maybe it is a people problem, not a technology problem [cheating, this is always true].
Transcend Logic
- Symmetry. Things that are almost the same can be divided into parts that are identical and parts that are clearly different.
- Aesthetics. Beauty is a powerful gradient to climb. It is also a liberating gradient to flout (e.g. inlining a bunch of functions into one giant mess).
- Rhythm. Waiting until the right moment preserves energy and avoids clutter. Act with intensity when the time comes to act.
- Tradeoffs. All decisions are subject to tradeoffs. It’s more important to know what the decision depends on than it is to know which answer to pick today (or which answer you picked yesterday).
Risk
- Fun list. When tangential ideas come, note them and get back to work quickly. Revisit this list when you’ve reached a stopping spot.
- Feed Ideas. Ideas are like frightened little birds. If you scare them away they will stop coming around. When you have an idea, feed it a little. Invalidate it as quickly as you can, but from data not from a lack of self-esteem.
- 80/15/5. Spend 80% of your time on low-risk/reasonable-payoff work. Spend 15% of your time on related high-risk/high-payoff work. Spend 5% of your time on things that tickle you, regardless of payoff. Teach the next generation to do your 80% job. By the time someone is ready to take over, one of your 15% experiments (or, less frequently, one of your 5% experiments) will have paid off and will become your new 80%. Repeat.
Conclusion
The flow in this outline seems to be from reducing risks by managing time and increasing learning to mindfully taking risks by using your whole brain and quickly triaging ideas.
Engineering is basically how to be solving problems given constraints and how to properly solve it. I think breaking down the problem in small steps is the method to use to get you 80% of the work done in 20% of the time.
Making it run right is usually the hard part. I say 'run right', because if there is an assumption (explicit or tacit) that 'make it right' is a matter of relatively small incremental fixes to running code that is fairly close to being right, then this aphorism is coy about where the hard part gets done.
I am taking 'right' to mean 'correct', and not some lesser metric of quality, or an aesthetic preference.
For those cases where making it fast is the hard part, one could make the same argument, perhaps even more clearly. Having something that runs, but which uses an algorithm that will never be fast enough, could be the first step down a long dead-end.
This is good advice in general, and so it amuses me when i come across problems which invert this order. Now and then, you can say "if we could do this thing that currently takes time T in T/100, it would be a game-changer" - it would enable whole new approaches, businesses, etc. In that case, your primary goal is to make it fast, and if often doesn't matter if it crashes, fails, or gets a slightly wrong answer 10% of the time, so you start by making it fast, then improve the code, then work on the improved code to make it reliable.
No. It might take someone else time T to do it, and we don't do it at all. It might take another program, whose codebase we are not going to touch, and which does it in a different way, time T to do it. In the cases i am thinking about, this was a new program, written from scratch, which did not go through a "make it right" phase before being made fast.
Side discussion : Discoverability of Facebook articles is non-existent. Kent Beck other posts are quite interesting but to find them you have to go to his profile, click on a mysterious "more" menu item and then you can select his articles...
Being a fairly seasoned developer myself, I kind of intuit what they mean, but I could very well be projecting what I think I am doing right into each of these, and conclude that I'm a master programmer... yay!