Came across a great passage from Ben Horowitz' The Hard Thing about Hard Things.
In it, Microsoft had just announced IIS (Internet Information Server) which competed directly with Netscape's web servers, offering the same features and five times the speed ... for free. Ben faces a crisis and starts looking for ways to pivot the business and presents ideas to the veteran engineering lead Bill Turpin, who responds with:
This, I think, is a valuable little metaphor.
All too often, in any context (trying to learn a new skill, trying to lose weight, trying to find that new product edge) people have this implicit quest for that magical silver bullet that somehow solves the problem. Problem is: it doesn't exist. Producing a valuable result is by definition difficult and by definition demands a long, hard grind.
You're going to have to use a lot of lead bullets.
Love this video. In the production of a film, the artists must place their skills at the service of a common goal, modifying their pet ideas to build towards a consistent style.
But on a field trip on a holiday, they decide to render a tree and individually come up with wildly different ideas, exploring different aspects of the tree. Despite painting the same subject, the ideas (and thus paintings) that emerge are completely different.
Came across this paper by Richard I. Cook, MD recently. Yep, it's written by a medical doctor and has amazing parallels to software systems. Anyone involved with software, especially engineers, should give this paper a good read.
The main bullet points:
1) Complex systems are intrinsically hazardous systems.
2) Complex systems are heavily and successfully defended against failure.
3) Catastrophe requires multiple failures – single point failures are not enough.
4) Complex systems contain changing mixtures of failures latent within them.
5) Complex systems run in degraded mode.
6) Catastrophe is always just around the corner.
7) Post-accident attribution accident to a ‘root cause’ is fundamentally wrong.
8) Hindsight biases post-accident assessments of human performance.
9) Human operators have dual roles: as producers & as defenders against failure.
10) All practitioner actions are gambles.
11) Actions at the sharp end resolve all ambiguity.
12) Human practitioners are the adaptable element of complex systems.
13) Human expertise in complex systems is constantly changing
14) Change introduces new forms of failure.
15) Views of ‘cause’ limit the effectiveness of defenses against future events.
16) Safety is a characteristic of systems and not of their components
17) People continuously create safety.
18) Failure free operations require experience with failure.
Arduino has the advantage of being super simple and dumb and just running one program at boot. If you want your rPi to behave similarly, like an appliance (plug it in and go) then you'll need to do this:
sudo vi /etc/rc.local
Assuming your program/script is called MYSCRIPT in this example, all you gotta do is...
Edit the /etc/rc.local script, adding an invocation of your script before the "exit 0"
printf "Running MYSCRIPT now!" sudo /home/pi/MYSCRIPT & exit 0
(Use the ampersand to background the process if your program is blocking for a while -- e.g. a server)
I stumbled across a pile of Bruce Lee quotes today; and it seems to me given the spirit of these one-liners that he must've been a deeply experienced programmer. In spirit. Maybe. Anyway, here they are:
Translation: Don't reinvent the wheel. Import that fuckin' library.
Translation: There's no silver bullet. There are no absolute design patterns. Every abstraction has its exceptions.
Translation: Just SHIP IT. Don't over-engineer or overthink the damn thing.
Translation: Delete code. Refactor, refactor, refactor. Less code is better code. Simplify that feature. Do they really need that checkbox?
Translation: Just try and see. Don't wring your hands forever over that new product or feature.
Not sure what to do with this one but I liked it.
Fred Brooks (author of The Mythical Man-Month, an awesome book on software development) wrote another, lesser-known (but also great) book called The Design of Design. It’s broader in scope, less focused on software architecture and more on the process of design. (BTW: the terms “design” & “designers” are used in a very broad sense here)
He does not prescribe any faddish low-level process (“scrum! flat design! agile! stand-ups! story points and post-it notes!”) but rather walks you through examples of the many mental foibles that designers may stumble over.
In pointing these out, he pushes you to be more reflective about your own habits and basic assumptions. For instance: consider the value and handling of brainstorming, which is typically just assumed to be valuable. Are the ideas produced actually better? (Actually, individuals outperform groups in the quality of ideas in their originality, feasibility, and effectiveness) Do the results tend to be better when you remove criticism from the conversation? (You sure do get a greater quantity of ideas and can reach much wilder solutions than if you allowed the naysayers to shoot ideas down prematurely)
My favorite chapter, I have to say, is the one entitled “Esthetics and Style in Technical Design”. In it, Brooks explores that fuzzy idea of what makes for a “beautiful system”. People can talk about beauty for cars, airplanes, houses, sculpture -- where the object is physical and has visual beauty. But people judge totally abstract things as being beautiful too: a theorem, a programming language, even a “visually ugly” but “logically beautiful” system such as Minecraft. Visual beauty is pretty apparent; so you might wonder, what does it really mean to be bear “logical beauty”?
Brooks lays out the prime attributes that define a logically beautiful system. I’ll list them briefly here:
The property of being able to accomplish a great deal with few elements. This is positive only up to a point, so beware of following this to the extreme: excessive parsimony leads to the use of non-obvious idioms. You can design a language with very few elements that’s completely insane to actually code in. You can have an API that only allows incrementation (but with negative numbers): parsimonious, yes; intuitive, no.
There must be a direct path from what you want to say to how you say it. The basic structural concept is plainly evident and if not obvious, then easily explained. Familiar and simple metaphors aid in this (e.g. the "Desktop" of Macintosh, the "spreadsheet" of VisiCalc, the "blocks" of Squarespace).
Given familiarity with just part of a system, you can predict the rest of it. You'd expect all functions in a package to throw similarly formatted exceptions, use similar error codes, take similar input types. If the $increment function takes a path and number, so should the $decrement.
Do not link what is independent. A change in one function does not affect another. In other words: no side effects. Air conditioning in your car shouldn’t affect the lighting (though in reality, at a certain point all these systems draw from the same power supply and in extreme situations, orthogonality breaks down)
Do not introduce what is immaterial. Do not expose incidental complexity, where extraneous implementation details affect the interface. Shifting of gears in a car is completely incidental and do not belong in its interface. An example of an egregious violation of propriety: iPhones being unable to use Facetime unless connected to WiFi. This limitation is completely arbitrary from grandma’s perspective.
Do not restrict what is inherent. Generality is the ability to use a function for many ends. Designs should not make too many assumptions about the use of a function. This is where Unix really nails it, keeping standard i/o, pipes, and files completely general.
A great story I remembered reading once on someone's blog. The link is now broken but I found the story copied on Wayback machine:
The Black Triangle
Reposting of a .plan I released a little over a year ago at GarageGames:
In October of 1994, I’d just started as an honest-to-goodness videogame programmer at a small startup called SingleTrac – which later went on to fame and glory (but unfortunately not much in the way of fortune) with such titles as Warhawk, the Twisted Metal series, and the Jet Moto series. But at the time, the company was less than 20 employees in size and had only been officially in business for about a month. It was sometime in my first week – possibly my first or second day. In the main engineering room, there was a whoop and cry of success.
Our company financial controller and acting HR lady, Jen, came in to see what incredible things the engineers and artists had come up with. Everyone was staring at a television set hooked up to a development box for the Sony Playstation. There, on the screen, against a single-color background, was a black triangle.
“It’s a black triangle,” she said in an amused but sarcastic voice. One of the engine programmers tried to explain, but she shook her head and went back to her office. I could almost hear her thoughts… “We’ve got ten months to deliver two games to Sony, and they are cheering over a black triangle? THAT took them nearly a month to develop?”
What she later came to realize (and explain to others) was that the black triangle was a pioneer. It wasn’t just that we’d managed to get a triangle onto the screen. That could be done in about a day. It was the journey the triangle had taken to get up on the screen. It had passed through our new modeling tools, through two different intermediate converter programs, had been loaded up as a complete database, and been rendered through a fairly complex scene hierarchy, fully textured and lit (though there were no lights, so the triangle came out looking black). The black triangle demonstrated that the foundation was finally complete – the core of a fairly complex system was completed, and we were now ready to put it to work doing cool stuff. By the end of the day, we had complete models on the screen, manipulating them with the controllers. Within a week, we had an environment to move the model through.
Afterwards, we came to refer to certain types of accomplishments as “black triangles.” These are important accomplishments that take a lot of effort to achieve, but upon completion you don’t have much to show for it – only that more work can now proceed. It takes someone who really knows the guts of what you are doing to appreciate a black triangle.
When I was working on Void War's principle development, I remember chatting with another SingleTrac alumni, and getting very excited about my multiplayer code. I’d spent a little over a week on the underlying architecture, trying to make it clean and reliable and easy to use. It’s all UDP rather than TCP/IP (for speed), so I created my own “guaranteed delivery” protocol for those rare packets that need to be guaranteed. I’ve rarely worked with UDP before, so it was kind of a new experience. When all was said and done, I had another computer join the game – and boom. There it was, on the host machine. Wow. No updates, it did next to nothing, but the core architecture was there. The rest SHOULD come together quickly. Explaining this to my buddy over messenger, I explained, “It’s a black triangle.” He understood what I meant immediately. It’s a convenient shorthand metaphor.So feel free to steal the term. And when progress seems a little slow because you are doing a bunch of hardcore architecture work, just remember – it’s a black triangle.
- posted by The Rampant Coyote @ 1:09 PM (Permalink)
Dynamic Typing is like stuffing all your data into a pile of <String, Object>HashMaps and calling it a day.
It's fucking insane.
- You lost all compile-time checks.
- You will have to implement a million unit tests where a type system would have made these guarantees.
- You literally have to find a way to exercise every single code path in your system in order to avoid the simplest of type mistakes. In this sense, you are forced to write exhaustive tests.
- It's impossible, just from looking at a function, to know with any certainty what values are provided or generated.
- Given a variable, it's impossible to know the valid range of values it may contain.
When I first heard this quote I thought gee, that's really true. In my experience it happens all the time; I have some foggy notion of something and when I start to write it down I start to see the gaps in my initial logic and assumptions, paving the way for a much better idea. Eventually I can evolve it into a much stronger piece.
It's a great habit to just write things down, as they say. When I think about why this bit of writerly wisdom seems to be true, it jumped out at me that this is rooted in a basic physical fact:
Creating a good idea is NP-Hard.
This basic bit of Computer Science theory means that solving real problems is hard (generally believed to take exponential time) but verifying their solutions is easy (doable in polynomial time).
Mozart composing a great symphony is immensely hard, but appreciating can be done by anybody. Generating a mathematical proof to a tough theorem is hard and takes years, but verifying the theorem can be done by any trained mathematician. The pattern of examples of our society enjoying this relationship between creator and consumer can be found in every creative endeavor. (Off-topic: part of why education is so incredibly important is because it vaccinates everyone against outright lies...)
So when you finally write something down, you make the solution available to your own verifier. You've probably already vaguely known this intuitively (that you tend to sniff out a shitty proposal much faster than you formulate a good one) but without knowing why it worked or without much discipline. So now I urge you to remember and leverage this fact regularly:
Next time you struggle with any problem, it's probably because you're thinking too hard. It's really hard to judge the million half-formed ideas when they're in your head, but when you can finally read them, the flaws are obvious and only then can you improve on them. Just write! Draw! Make 20 prototypes! Do anything to get it into a medium that you can lay your eyes on!
Alan Kay gave a great talk called "Normal Considered Harmful"
At 51:35 there's quite a gem. He advises us:
Don't be in the past. You need to put yourself into the future in order to skate to where the puck is going to be. You need to leverage up!
The way to get leverage is to get a ton of computer power and write a ton of very simple, non-optimized languages that run very very quickly. And you should be able to do them every couple of days to get power and then throw them away, use them like kleenexes.
Its rather easy to do that if you don't have to optimize and you don't have to optimize if you use hardware that runs 100x faster than what you have today.
So unless you do that, you can ONLY do incremental stuff today.
Another great point at 59:00
The MacCready Effect.
Always do the minimal thing you can do that is qualitatively better. Before building anything, MacCready spent a long time thinking about where to spend 80% of his effort beore he did a darn thing. That's why he solved an immense number of problems in his life.