A project pattern language “distills and describes the essence and character” of a specific building project (Neis et al., 1994). It describes the project’s details at multiple levels of scale, along with the connection to its wider context, with a sequence of statements that are clear enough to visualise, but leave enough ambiguity for the implementation to adapt to local conditions during an integrated process of design and construction.
This project language was written during Building Beauty Online 2020 – 2021 to guide the design and construction of my individual project. It is an attempt at re-balancing the small home workspace of a remote knowledge worker away from the monotony of a typical desk setup towards a more varied workspace akin to the workshop of a craftsman of previous generations. It is tailored to me as an individual, but guided by background research and several interviews with colleagues and fellow students.
I’ve meant to get this finished off, but until then here’s where I got to for posterity.
Some slides make reference to APL – A Pattern Language – and a corresponding pattern number.
]]>
It surprised me that the ability to reliably calculate longitude at sea is a relatively recent innovation (late 1700s-early 1800s) – well into the age of maritime exploration and trading.
While latitude calculation was commonplace, it’s only half of the answer to the question of “where are we?”.
It’s a reminder of what can be done even with only partial information. This can’t be said without noting the significant cost, with countless lives lost to shipwrecks caused by veering off course, or disease and starvation caused by elongated journey times as they tried to find their destination.
The Longitude Act, offering monetary rewards to those who could solve the problem of calculating longitude at sea, was first passed in 1714 – around 100 years before any innovation was able to really meet the needs of mariners at significant scale.
The desire to solve the problem goes back way further of course, but even with the introduction of vast prizes it still took a significant amount of time to crack.
At the time, the problem of calculating longitude was seen as essentially attempting the impossible, to the point of becoming a common joke.
What seems impossible today might not be so impossible in the future, given enough focus and resource.
John Harrison, the inventor of the chronometer, was essentially an unknown carpenter with a self-taught interest in clocks. That’s not to take away from his clearly incredible skill and ability, but he was up against Sirs and Lords and men of means in trying to win the prize offered by the Longitude Act.
The Board of Longitude, set up to administer the prizes of the Longitude Act, favoured lunar methods of calculation. Part of this was a legitimate belief that it would be more reliable given the timekeeping technology of the day, but also seemingly some element was down to their personal interests in astronomy and it being perceived as a more noble and respectable field than the mechanical watchmaking.
Harrison dedicated his life to systematically improving the performance of clocks, and though lunar calculations were an important piece in the puzzle, in the end his inventions beat out the lunar methods. While chance no doubt played a huge part of this success, it’s nice to be reminded that some skill, perseverance, and ingenuity can win against the odds.
]]>To be effective is the job of the executive. “To effect” and “to execute” are near-synonyms.
Most knowledge workers are executives in some capacity, as they are expected to make decisions about their work.
There are four key struggles an executive faces:
An effective executive has five practices to manage these struggles:
What is often wanted when hiring is universal genius, but the only person in abundant supply is the universal incompetent. Humans are not logical super-computers. We are slow and sloppy, but we are able to have insight. If we can’t increase the supply of a resource we can only try to increase its yield. We have to extend the range of our capabilities through the tools we have to work with.
Results are co-determined at best. Outcomes are the result of your decisions and actions plus everyone else’s.
Outside events are often qualitative and not capable of quantification. The truly important events on the outside are not the trends, but the changes in trends.
Effective executives don’t start with tasks; they start with time.
Record: We’re bad at remembering how we spend time. At a minimum, log actual time use for three to four weeks at least twice a year.
Manage: Systematically identify ineffective uses of your time.
Symptom | Problem |
---|---|
Recurring crisis | Lack of system/foresight |
10%+ time on “HR-type” work | Overstaffing |
25%+ time in meetings | Malorganisation |
Multiple sources of truth/backchannels | Information malfunction |
Consolidate: Set your expectations low; 25%+ discretionary time is a miracle! Block time for deep work (90 minutes deep; 30 minutes shallow; ↺).
Deep Work: Most serious tasks require an amount of focused time. Breaking up this time into small chunks results in waste and ineffectiveness. Using focus time to get work up the hill allows the remainder of the work to be done in smaller instalments.
Managing People: People are time consumers. You can’t convey big impactful ideas in a few minutes; you need an hour. Building a human relationship requires infinitely more. Since knowledge workers are self-directed, they need a clear understanding of what’s expected and why. This requires a significant amount of information, discussion and instruction, and especially an understanding of the wider context and goals of the organisation.
Outcome Focus: A leisurely exchange up, down and across the organisation is needed to keep enthusiasm high and so that people direct their attention towards opportunities and results rather than inwards towards their specialty. Some good questions to ask on a regular schedule are:
People Decisions: People are always “almost fits” at best.
Meetings: An organisation in which everybody meets all the time is an organisation in which no one gets anything done. Too many meetings signify that responsibility is diffused and that information is not addressed to the people who need it.
Information Malfunction: Look at availability, timing and form of information.
Effective executives focus on contribution, They look outward towards goals and the performance and results of the organisation. The majority focus downward and become occupied with efforts rather than results, and what they believe they are owed.
Effective contribution covers three major areas:
The four basic requirements of effective human relations:
The tools of executives:
Know what to expect out of these typical work situations. Know what its purpose is, what it achieves and its output.
To ask “what can I best contribute towards results?” is to look for the unused potential in the job. What is considered excellent performance in many positions is often a fraction of the job’s full potential of contribution.
The world changes around you. The relative importance of between the three dimensions of performance changes. Failing to understand this will result in suddenly doing the wrong things the wrong way, even though they were previously the right things done the right way.
Knowledge workers are expected to take responsibility for being understood. If you want to be an executive – responsible for your own contribution – you must concern yourself with the usability of your “product”.The knowledge worker is usually a specialist. The task is not to breed generalists; it is to enable the specialist to make themselves and their specialty effective. The only meaningful definition of a generalist is a specialist who can relate their small area to the universe of knowledge. You should learn enough of the needs, directions, limitations and perceptions of others to enable them to use your own work.
The objectives set for themselves by subordinates are almost never what the superior thought they should be.
Only strength produces results; one cannot build on weakness.
To focus on strength is to demand performance. Organisation enables multiplying the performance capacity of the whole while making weakness irrelevant. The job is not to find genius – there aren’t enough – but to enable common people to achieve uncommon performance.
Look out for the impossible job | Role has defeated 2-3 able people in succession |
Make jobs demanding and big | Challenge brings out whatever strength a person may have |
Measure task-oriented performance | Don’t diagnose & remedy weakness unless it limits full development of strength |
Tolerate weakness | Focus on opportunity, not problems |
In every area of effectiveness within an organisation, one feeds the opportunities and starves the problem.
For the ability of a knowledge worker to contribute in an organisation, the values and the goals of the organisation are at least as important as their own professional knowledge and skills.
Job Descriptions: The tendency is to start with the job as being a part of the order of nature. Then one looks for a person to fill the job. It is too easy to be misled this way into looking for the “least misfit”. This invariably leads to mediocrity. Structuring jobs to fit the personalities available is worse than the disease of mediocrity. Jobs have to be objective, determined by the task not the personality.
Jobs in an organisation are interdependent and interlocked. You can’t change everybody’s work and responsibility just because you have to replace a single person in a single job. To structure one job to a person is almost certain to result in greater discrepancy between the demands of the job and the available talent.
Pick people for jobs based on what they can do. What do they need to know to use their strength, and how do I provide it?
To tolerate diversity, relationships must be task-focused rather than personality focused. Otherwise the accent will at once be on “who is right?” rather than on “what is right?”. Keep a distance between close colleagues to measure the relationship on task-oriented performance.
The effective executive tries to make fully productive the strength of their own superior. Start out with what is right and present it in a form which is accessible.
People are either readers or listeners; inform accordingly (sum up; document thought process; provide the figures; bring in early; ripen privately)
Finding your strength: What can I do with relative ease that others seem to struggle with?
In the American civil war, the “well rounded” men Lincoln had appointed were beaten time and agin by Lee’s “single-purpose tools”, the men of narrow but very great strength.
Andrew Carnegie chose for his tombstone: “Here lies a man who knew how to bring into his service better than he was himself.”
The more an executive focuses on upward contribution, the more he switches from being busy to achieving results.
If there’s any one “secret” of effectiveness, it is concentration. There are always more important contributions to be made than there is time available to make them. Effective executives do first things first, and do one at a time.
Doing one thing at a time means doing it fast. The way to apply productively mankind’s great range is to bring to bear a large number of individual capabilities on one task. The more one can concentrate time, effort, and resources, the greater the number and diversity of tasks one can actually perform. Doing things fast means you need much less time than others do.
Hedging by doing a bit of everything means that nothing gets done.
Allow margin for the unexpected; set an easy but steady pace.
Hire new people to expand an established and smoothly running activity. Start new things with people of tested, proven strength.
Look to tomorrow: If operational pressures set the priorities the important tasks of paying attention to the outside of the organisation will predictably be sacrificed.
Periodically review work programmes and ask “if we didn’t already do this, would we do it now?” Commit today’s resources to the future. Stop an old activity before committing to a new one – weight control.
Successful companies are those that innovate new technologies or businesses; not those that just expand their existing product line. Courage rather than analysis is needed for setting priorities.
Decision-making is usually a small fraction of time but is the specific executive task.
The important decisions are strategic and generic at the highest level of conceptual understanding.
Know when to make a principled or pragmatic decision. Know which is the right or the wrong compromise.
There are 4 types of situation. A decision will inevitably be wrong if the situation is classified incorrectly.
Elements of decisions:
Mistakes to be on guard for:
Bell Laboratories was deliberately designed to make obsolete the present, no matter how profitable and efficient. In most industrial laboratories, “defensive research” aimed at perpetuating today predominates.
Beware the longevity of the temporary. Improvisation is always going to be necessary, but ask “if I had to live with this for a long time, would I be willing to?”
A decision is a judgement, rarely a choice between wrong and right. Most are between options that aren’t obviously better or worse. There are no facts to base these decisions on, so you must start with opinions, treating them as untested hypotheses.
You must test a hypothesis against reality. Assume that the traditional measurement is not the right measurement, otherwise there would likely be no need for a decision.
Whenever one has to judge, one must have alternatives among which one can choose. Effective decision-makers create dissent and disagreement, rather than consensus, but starting with the commitment to find out why people disagree.
Is a decision really necessary? One alternative is the alternative of doing nothing. Every decision is like surgery; an intervention into a system carrying a risk of shock. You have to make a decision when a condition is likely to degenerate if nothing is done, but there’s no point if it will take care of itself or, while annoying, the decision is unlikely to make any difference.
The majority of these decisions will be between the extremes. You must compare risk of action to risk of inaction. Either act or don’t act. Don’t take half-action. This is the one thing that’s always wrong.
Decisions require courage as much as judgement. Ask if additional studies are likely to produce anything new, and whether that the new is likely to be relevant.
The strength of the computer lies in it being a logic machine, it’s strength being fast and precise. This also makes it a total moron. The human being by contrast is perceptual. This makes us slow and sloppy, but also bright and insightful.
The adaptation to the decision in principle has been going on for a long time. In WWII middle-level commanders increasingly had to know the framework of strategic decisions within which they were operating. They increasingly had to make real decisions, rather than adapt their orders to local events. As long as we handle events on the operating level by adaptation (feel) rather than by knowledge and analysis, operating people will be untrained, untried and untested when, as top executives, they are first confronted with strategic decisions.
]]>Programming for Humans is a talk I gave last year to a tutorial session for students of a foundation course for Computer Science at Royal Holloway University of London, organised by an ex-mySociety colleague.
I’m going to talk to you about programming for humans.
What does this do?
But not just this…
Here’s the other half of the file.
But there’s more. These lines include some more code…
…which renders some more stuff…
All that code is for rendering this!
But I don’t mean the whole page…
…just this section of a form with one field and some tabs for each translation of the value.
This was a question I was asking myself at the start of last week.
We’ll get back to this later.
Hey!
I’m Gareth and for the last 7 years I’ve been a programmer at mySociety…
We’re a civic tech charity and we make web services that help citizens hold power to account, engage in democracy and improve their local communities.
Most of my work is around WhatDoTheyKnow.com, a service that makes it easy to ask for information from public bodies.
It’s been running for over 10 years and accounts for around 20% of Freedom of Information requests in the UK.
It uses an open source Ruby on Rails platform that we built called Alaveteli, which is installed in about 25 jurisdictions around the world.
When I started university this was the state of mobile phones…
We’ve moved on a bit!
It’s probably obvious to most people that over time computer performance goes up while cost comes down.
But what hasn’t changed so much in all that time is the performance of the human brain.
Why does this matter?
We actually spend most of our time reading code rather than writing it.
In pretty much any software that’s not a hobby project, you’ll have more than one person working on it, so you’re often reading someone else’s code before you start writing your own.
Or you’re trying to remember what you yourself wrote 6 months ago!
It can feel like this a lot of the time.
This is exactly how I felt while I was trying to understand the code I showed you earlier.
Sometimes, you are actually trying to understand some really difficult concepts…
But more often than not it’s because what a machine understands is very different to what a human understands.
Fortunately, we’ve used the performance improvements in computer hardware to create languages that are easier for humans. We’re not writing machine code or assembly language day to day any more.
But even with these better languages, it’s still up to programmers to use them in a way that other programmers can understand.
We’ve all written essays and had them handed back like this.
Writing is hard.
It takes a lot of work to explain things coherently, and it’s no different with programming.
Finding the right words and concepts is one of the most difficult but important things you can do as a programmer.
Programming is a science, but it’s also engineering, and it’s also an art.
This often gets forgotten because we spend so much of our time looking at code and dealing with machines.
What makes life difficult for programmers is that we’re trying to communicate with both machines and humans at the same time.
Believe it or not, this is JavaScript, a fairly readable language.
It’s been compressed so that it’s quicker to send to a browser. Quicker for machines.
Machines can interpret this, but I sure as hell can’t.
This is another example from the Alaveteli codebase.
What does this do?
I can tell you it works. This code is probably running right now as we speak.
But for me to really understand exactly how this method works, I’d have to spend a minute or two concentrating on it line by line.
It might not sound like much – a minute or two – but Alaveteli has around 30,000 lines of code. The more complex each of these methods is, the harder it is to understand larger chunks of the system at the same time.
Let’s see what we can do to make this clearer…
I’ve extracted out this get_tag_values
method to a separate file and stubbed out some test data so that it’s a bit quicker to work with for this demo.
I’ve also created a little test suite so that the functionality stays the same after each change.
The first thing I’m noticing is that the argument name “tag_as_string
” isn’t quite right. In our case, a Tag
can have a name and an optional value. Given a tag with a name and value, when we say tag_as_string
, we’d represent this tag as foo:bar
(name:value) when converting to a String.
This method doesn’t handle splitting the name from the value, so what it actually accepts is a tag name in String form. As such, let’s change it to tag_name
.
The next thing that sticks out at me is the use of a for
loop. It’s a bit much detail to get in to here, but most of the time in Ruby we use iterators like each
. There are some specific reasons you might use for
, but we’re not doing so here, so we’ll change to an each
.
We can also remove the explicit self
as Ruby figures that out for you in this context.
We’ve cleaned up some basics, so now we need to really start looking at what’s happening in the current code.
The most obvious thing to me is the handling of a non-existent tag. Usually we use a guard clause to check for invalid data, so this feels like a good place to start.
It looks like we’re looping through all the tags associated with the PublicBody
instance, and then comparing their name
attribute with the tag_name
argument passed to the method. In other words, we’re raising an error unless the tag exists in the list of associated tags.
It seems like we can encapsulate this filtering in a method – tag_exists?
. We’ve introduced some duplication, but we can clean that up shortly, and it’s allowed us to write a really clear guard clause.
Now we’ve handled the edge-case of being given an invalid tag, we can look at the bones of handling extracting values of a valid tag name.
Remembering the logic from before – iterating through each associated tag and comparing by name – we can extract this filtering step so that we only check the values of tags that match the given tag name argument.
The previous step introduced tags_named
, which in implementation looks nearly identical to tag_exists?
. We can now re-implement tag_exists?
in terms of tags_named
.
Notice how we’re pushing the details down so that our higher-level methods are quite readable in human terms. Most of the time we won’t be needing to remember exactly how we find tags with a given name; we’ll take it as a given. It’s much easier to understand that tag_exists?
checks for any tags_named “foo”.
We’re on the home stretch now! The method is reasonably clear, but each time we read it we’ve still got to figure out what the innards of this loop is doing.
For the relevant tags, we’re checking whether they have a value and if they do, we’re storing that value in a “results
” collection. This isn’t terrible, but it still takes a bit of work to comprehend.
Instead of manually constructing our results Array
we’ll use a map
, which handles this internally. Now we can focus on writing only the domain logic that matters to our application – collecting all values
from the tags that we iterate through into an Array
.
That takes care of extracting the value, but we need to remember that we’re not interested in nil
values. To handle that we can just compact
the Array
returned by the map
. compact
just removes nil
values from an Array
.
You could argue that this is being “too clever”, but map
and compact
are bread and butter in Ruby, so while there is a small learning curve for a newcomer to the language, we’re not doing anything particularly esoteric.
I’m feeling pretty good about the code at this point, but there’s still a moment of hesitation as I figure out what we’re mapping over. Instead we can use another common Ruby trick to make the intent even clearer.
Instead of a block ({ |tag| tag.value }
) we can use the proc shorthand when the called method is the only operation of a block. Now it’s much clearer that we’re “mapping the values” – map(&:value)
.
We can also get rid of the temporary results
variable, since Ruby automatically returns the result of the last operation.
Finally, we could use a newer built in Ruby method called filter_map
, which does the map
and compact
in a single step. This is a little less common, but it’s no different to how we pick up new words and concepts in natural language. We used to say “The World Wide Web”; now everyone knows what you mean when you say “the Web”.
We’ve been running our tests after each step, and one final run shows our method still working as we expect.
Why does all this matter?
Think of the effect of trying to work with thousands of lines of the gross version every day.
It’s like working in a dump…
And that’s why it feels like this.
Our brains can only hold around 7 things in our head at any one time.
Which is why, for most of our work, we need to optimise our code for humans to read.
Look at the language and the number of concepts in this version.
Here, we’ve only got 3 concepts to worry about.
Let’s contrast that with the previous version.
This has at least 6 concepts, depending on how you count.
1. The idea of this “found” variable
2. A collection of results
3. Some idea of a group of tags that we’re looping through
4. A comparison between the input variable and the tag name
5. Some figuring out over whether to add the tag value to the results collection
6. Then we’ve got the idea of raising an error message if we couldn’t find something
Being 50% more complex is bad enough on its own, but look how each concept is sprawled all over the place.
Each line you read is to do with something different than the lines around it.
There are also more “moving parts”.
Each of these language operations have an effect on what’s happening
So when you actually try to read this, your brain literally cannot process it as a single idea.
You’re forced to read it in chunks, skip up and down it, and all this becomes really mentally draining.
And that’s why it feels like this.
Look familiar?
We’ve been working on a project to add some snippets of text to help our users challenge refusals to their requests for information. To manage these snippets we need an admin interface.
Before I started working on this I was thinking “oh, we’ve already got translated forms; shouldn’t be too hard to basically copy and paste”.
And then I opened the code and encountered the code I showed at the start of this talk. With enough time I figured it out, sure, but it’s pretty frustrating to re-work code like that.
It took me the best part of a week to reduce the complexity of the original code and then add the new admin form with this much clearer code.
If we’d have spent the time to make it clearer when the code was first added it would have taken me far less time.
I could have spent that time doing more important things that help our users, or at least being less frustrated if nothing else!
And it’s not just you that complex code affects. It’s your team when they’re trying to work with your code and people who work on the code long after you’ve moved on.
One of the most valuable things you can do as programmers is develop an eye for clarity.
If you want to be a good photographer, you’ve got to look at a lot of pictures, take a lot of pictures and critique them to understand why some are better than others.
You’re not going to take great photos just by knowing how to operate the camera mechanically. You need to know where to be and when to press the button.
And in the same way you won’t write good programs just by learning a language. You’ve got to learn how to communicate with the language.
So, to write clear code, you’ve got to read a lot of code.
Good stuff, yes, but you also need to read a lot of shit to learn what not to do.
And you’ve got to write a lot of code too.
Open source code is great for this. Go to GitHub, open up a library and read it. Try to understand how it works.
Then try to re-write it in a way that makes more sense to you. Or maybe port it to a different programming language.
The point is that you need to practice.
But not just code.
Learn how to convey ideas through writing.
Read a lot.
And remember, it’s not only the science parts that matter.
As programmers, we get to do a bit of everything.
And that’s what makes it fun.
Thanks for listening!
]]>Good strategy almost always looks simple and obvious.
It identifies the one or two critical pivot points in a situation and designs a way of coordinating resource and action to overcome them and make forward progress.
Strategy is not goal setting. Strategy must bridge the gap between ambition and action. Good strategy has a kernel that makes this bridge:
Recognising windows of opportunity and acting on them is key strategic thinking.
Most complex organisations spread rather than concentrate resources.
Strategy is at least as much about what an organisation doesn’t do as it is about what it does.
Strategy brings relative strength to bear against relative weakness.
The discovery of a hidden power can arise through a shift in perspective.
You can compete indirectly by using your relative advantage to impose asymmetric costs on an opponent.
The oft-forgotten cost of decentralisation is lost coordination across units.
Bad strategy is not simply the absence of good strategy. It is actively written “strategy” plans that are misleading or of little value.
Fluff: Superficial restatement of the obvious sprinkled with buzzwords and esoteric concepts to create the illusion of high-level thinking. A hallmark of true expertise and insight is making a complex subject understandable.
Failure to face the challenge: When you cannot define the challenge you cannot evaluate a strategy or improve it.
Mistaking goals with strategy: Many bad strategies are just statements of the desired state of affairs rather than plans for overcoming obstacles. You end up with a list of things you wish would happen; not a way of making them happen.
Bad strategic objectives: Objectives that fail to address critical issues or when they are impracticable based on the skills and resources that are available.
Underperformance: When a leader characterises the challenge as underperformance, it sets the stage for bad strategy. Underperformance is a result. The true challenges are the reasons for underperformance.
Bad strategy is not absence or miscalculation but an active avoidance of analysis, logic and choice.
Unwillingness to choose: Any coherent strategy pushes resources towards some end and away from others. In organisations, the longer a pattern of activity is maintained the more it becomes entrenched and the more its supporting resource allocations are taken to be entitlements. It takes enormous political will and the exercise of great centralised power to overcome the present levels of institutional resistance to change.
Template-style strategy: Leadership is not strategy. Template strategy often is reduced to the leader having a vision, inspiring the people to sacrifice for the good of the organisation and “empowering” people to accomplish the vision. Without clear strategy people don’t know what pursue and accomplish.
New thought: “Think it and it will be!” While work in the area provides a counterweight to bureaucratic and rational-action views of management, believing that thinking only of success will lead to success displaces the critical thinking necessary for good strategy.
The Kernel is a simple plain English description of the strategy – no sorting between visions, missions, goals, etc – and not split by business, corporate and product strategies.
The Diagnosis simplifies the complexity of reality by identifying the critical aspects of the situation. At a minimum it names or classifies the situation, linking facts to patterns and suggesting where to focus.
Guiding Policy is an overall approach that directs and constrains action without fully defining its context. It’s more about ruling out a vast array of possible actions.
Coherent Action is a set of steps that are coordinated, coherent and makes painful choices about where resource is allocated. Actions must not be in conflict or unrelated. They should amplify one another.
Strategic coordination is not ad-hoc mutual adjustment; it is coordinated action and coherence imposed on a system by policy and design through centralised power. Decentralised decision-making fails when either the costs or benefits of actions are not borne by the decentralised actors. Coordination is costly because it fights against the gains of specialisation.
Leverage is power created by focusing resource at the right moment on a pivotal objective. You can create it with a mixture of:
The more complex the situation, the poorer your foresight will be.
Proximate objectives are ones that are close enough to be feasible. The resolve ambiguity by taking a strong position with an aim of creating good optionality.
A system has chain-link logic when its performance is limited by its weakest subunit, or “link”.
In systems where each link is managed separately the system can get stuck in a low effectiveness state. There is no point investing resources in making your link better if other link managers are not.
There are little or no payoffs to incremental improvements in chain-link systems. Local measurement and reward must be shut down to focus on the change itself as the objective. It takes leadership and the willingness to absorb short-term losses in the quest for future gains.
If you have a special skill or insight at removing limiting factors, then you can be very successful.
Strategy is more design than analytical decision-making; there is rarely a clear set of alternatives to choose from.
A strong strategy creates a system where the whole is greater than the sum of its parts, and where the whole is designed to “fit” in its context.
The fewer the resources, the tighter the integration necessary between subsystems.
Focus is the coordination of policies that produces extra power through the interacting and overlapping effects; and the application of that power to the right target.
“Grow by x%” is not a strategy. Growth is the outcome of a successful strategy. Healthy growth is not engineered. It is the outcome of growing demand for special capabilities or of expanded or extended capabilities.
Changes to increase competitive advantage:
Look for and sense swells of waves of change. The mix of forces is richer than just skill and luck. Think about second-order effects.
“Above the details” leadership only works in stable times. In times of change leaders must understand the fundamentals and be able to question the experts.
Signs of waves:
Inertia is the resistance to adapt to changing circumstances.
Entropy is the natural direction of systems towards disorder.
Leaders must constantly work on maintaining purpose, form and methods, even if there are no changes in strategy or competition.
Nvidia case study.
Nvidia induced less coordinated responses by 3dfx through a carefully crafted fast release cycle.
Good strategy deals with the edge between the known and the unknown.
Like a scientific prediction, strategy is an educated prediction of how the world works. Its ultimate worth is determined by its results, not the strategy itself.
Anomalies in results can be a sign of opportunity. The anomalies are not in nature but in the mind of the acute observer.
Engineers start with complexity and craft certainty.
Attention is like a flashlight beam, illuminating one subject only to darken another. Like navigating in the dark, you need to frequently reassess the landscape and then refocus on what is both important and actionable.
Lots of conceptual tools exist to help you get oriented, but mechanical tools don’t create good ideas; insight does.
When coming up with strategy ideas we often stop at the first idea. Our minds unconsciously dodge the painful work of questioning our early judgements. Being able to think about and question your own thinking is more important than any strategy framework.
Social herding presses us to think that everything is OK because everyone else is saying so. The inside view presses us to ignore the lessons of other times and other places, believing that our company, nation, venture or era is different.
It is important to push back against these biases.
You can do this by paying attention to real-world data that refutes the echo-chamber chanting of the crowd, and by learning the lessons taught by history and by other people in other places.
]]>I’ve been having a few conversations with friends over the last year about what differentiates a senior developer, and it’s often quite difficult to put your finger on. I think one of the key day-to-day things that’s noticeable is not necessarily the end result that’s produced, but the journey taken to get there.
One of the items at the senior level of our technical job roles matrix gets at this…
Scopes and stages work into well-defined milestones to avoid a monolithic deliverable
…but only describes what to do, not how to do it.
Pilots have a pretty complex job, so they prioritise their actions: Aviate (fly the plane and don’t crash); Navigate (fly in the right direction); Communicate (tell people where you are and where you’re going). Software is not so dissimilar. We’re dealing with loads of moving parts and trying to get them to work together, we’re trying to create something of value, and we’re working with others while doing it.
Along with writing raw source code (aviating), developing software, and many other types of knowledge work, have several little cognitive tricks that help us navigate and communicate our way through complexity.
Here’s how I think about it:
Shape ⤴ Scope ⤴ Sequence ⤴ Spike ⤴ Sparkle ⤴ Ship →
Shaping is about de-risking work by taking a somewhat vague sense of what to do into a rough but solved and bounded description that you can schedule with the confidence that you’ll complete it within the time you budget.
For bigger projects someone in more of a product manager role may do a significant portion of this, but it’s still really useful no matter how small the work to make sure you’ve got a clear idea of what constitutes a success.
Scoping is about figuring out the orthogonal parts of what you’re building. Scopes are not tasks, but more like an outline of the system, or the rooms of a house.
Scopes help you pick the best place to start within the shaped work, and help you continually prioritise the remaining work and assess progress as you move through it.
Finding the epicentre – the scopes that deliver the core value of the work – is critical for being able to start in the right place and work on the parts of the project in the most effective order.
If we spend the majority of our time building incidental parts of the system before we get to the epicentre we’re really risking running out of time or hitting an unknown that jeopardises the entire project. Hitting a significant blocker in an incidental scope can often be worked around or ignored altogether, but if we can’t deliver the core value then none of the other things matter.
In all but trivial cases, much of what we build is new and unknown. When we encounter these unknowns, we want to sense-check our approach to uncover rabbit holes before we get too deep and don’t want to take a different approach because we’ve already put so much work in.
To do this we’ll “spike” (or prototype) the work – hack it together as quickly as we can to get a roughly working version to use and interact with. Once we’re confident that we can hook the main components together in a way that does what we want we can then finish off the work to a production standard.
When we’re over the hill and confident that we’re on the right track with what we’re building, we can finally add all the polish and finishing touches that we all love doing. We can finesse the language of the domain model, unpick our spike into well-factored methods, add edge-case tests and smooth out the UI.
Sparkles are the things that make us feel proud of our work, but it’s important that they support something that adds useful capability for the user. Otherwise they’re more like novelty tourist-tat that, while shiny, doesn’t really serve much purpose.
Shipping work is not just about getting the code merged, but creating a package for the work that’s as well considered as the work itself. Think about the experience of opening a new Apple product. The quality of the packaging, and the way everything fits inside it, all give you confidence that you’re opening a quality product.
Software development is no different. A Pull Request that contains a logical set of commits with good commit messages and a coherent overall description with screenshots and a release plan, if appropriate, all give others confidence that they’re about to review a quality piece of work. This creates a low-friction collaborative environment, and much of the effort that goes in at this stage can be re-purposed to show work in the open.
Each step represents an opportunity to pause and communicate.
Communication isn’t just about announcing progress (“I’ve done X”) but about refocusing on the wider whole rather than the in-the-weeds details (“I’ve done X; is it the right thing? Do I need to course correct? Is it actually going to work in the situation we’re designing for?”). If you’re not thinking about wholeness your product isn’t going to be coherent, just a load of individual pieces.
Not all of this communication needs to be for the here and now. Great commit messages communicate with a future you or colleague. Descriptive pull requests with screenshots and gifs create a foundation for documentation and blog posts. Even when your communication is more temporal, you don’t always have to wait for input. The main purpose is creating good, calm situational awareness for yourself and the others that you’re working with.
Before communicating outwards consider communicating inwards with yourself. Reflect on the work and ask whether it serves its purpose for the stage you’re at. Try to anticipate what questions and comments others may have. Self-reflection makes for better more articulate communication with others.
Thanks to Lloyd Wheeler, Aaron Evans, Louise Crow and Sam Pearson for reviewing drafts of this post.
]]>There is an allure to our belief in potential, allowing individuals to live in what could be, rather than what is.
Our wished-for lives limit self-examination in important ways.
Millennials seek purpose, meaning and impact in their work, and so an entire industry has been created built on the facilitation of purpose.
Hyper-connectedness is our default state. Millennials are the first generation confronted with the challenge of navigating online and in-person identities.
Universities encourage the ability to sell and take action rather than to inform oneself and ask questions.
Being busy all the time pushes out time for reflection. People do stuff because it seems like they should, or even need to, in order to keep up. It’s important to think about the moral aspect of what you’re doing and why it’s meaningful to you. Hyperconnected society makes solitude very difficult and non-default.
“Skills” are only a part of being human. Wisdom is as important. Adaptability is seen as vital, but it’s difficult to quantify and describe.
We must commit ourselves to building a deep understanding of a subject to be truly adaptable – gaining a fingertip-feel so that we just know how to apply our skills when faced with a novel situation. Our lack of attention and focus on adaptability do not allow us space to do this hard work. We just build a broad but brittle foundation.
There’s a lot to be said for learning from elders – people with wisdom. We don’t cherish this nearly enough to build meaningful mentoring relationships. We try to express and promote ourselves rather than listen and reflect.
Businesses people drive much of the desire for adaptability, but should universities just be training schools for the workforce? Our work is packaged into projects, but we never take the time to assess the experiences as a whole. It becomes difficult to feel settled.
Precarious work with high income instability is materially and psychologically damaging. Media narrative increases the perception of instability. We are restless. Comfort feels like falling behind; yet we crave stability and deeper meaning.
Slack – time & money buffer – enables an individual to think and experiment more freely. In this mindset we often double down on productivity hacks rather than to pause and contemplate. We think about success in terms of how much we’ve done rather than whether it was meaningful.
Busyness is a form of outward expression. It can be difficult not to feel lonely without a packed calendar, but it warps our sense of time. We can rarely remember a busy day. They feel empty without a sense of coherence. It’s the modern “keeping up with the Joneses”.
We want to create impact in our work – make the world better somehow – but impact becomes more of a rhetoric. Not all impact happens at scale, and how it happens is as important as the end result. The impact mindset risks individuals overestimating their abilities, creating unrealistic aspirations and ambitions, leading to disappointment and frustration. Meaningful change requires decades of collective action. Worthwhile impact is more likely to occur when expectations are modest and effort is sustained over time.
Modern life encourages thinking in options, creating constant stress about what we could be doing instead. This leads to downtime being completely avoided, but constant doing strains our ability to reflect when no time is set aside for aloneness.
Being “on” is to be showing our best selves, but hyper-connectedness promotes a false sense of authenticity. Networks promote more but offer less. Likely to make you less productive, more confused and more anxious.
Many take the view that much of an activity’s value is in the sharing of it. Not just doing X, but sharing parts of the experience. This creation of personal brand can corrupt the message through an excessive awareness of one’s audience.
Few consider what is lost through the online sharing of an activity. Undertaking things with a view to how it will be seen chips away at our integrity and diminishes our autonomy. Comparison gives us FOMO.
Being oneself is about confronting our limitedness. To be oneself is difficult when performance is so often mistaken for reality. Learning is ultimately social.
These networks are mostly a waste of time. They give members an inflated ego and focus on short term action and impact (which can be measured) over long term dialogue and building understanding.
They insulate the already successful and mostly attract the most confident and ambitious, rather than the most humble and intelligent. They risk becoming playgrounds for the average.
Comparison to others creates a belief that success comes quickly and that we can achieve our goals by understanding how others achieved theirs. Comparison entices you to look outside yourself to find meaning, purpose and definition of success.
Comparison can happen across 3 dimensions:
A focus on others takes us away from comparison against our own absolute performance over time. The comparisons we make are often based on incomplete information, which is especially true of Social Media highlight feeds.
Journalists who stay in the industry seem to be those with modest expectations of themselves.
Solitude is about cultivating a private self rather than about using aloneness with an aim to maximise productivity.
Aloneness is not solitude. It is possible to be alone but virtually tethered. It’s not fleeting aloneness while waiting in a queue. the difference is in the quality of self-reflection that one can generate while in it.
Solitude is philosophical – where we make time and space for considering the formulation of questions of significance to us and the responses they engender. It has purpose, but not a purpose to do. The purpose is to contemplate.
Solitude must be approached with seriousness; and embrace of frustration and patience, and a resilience against sharing.
We must ask “Why?” (p121), listen to responses, and continue to dig deeper. Solitude is largely about repetition. Not all responses will be positive. Solitude, as a search in aloneness, involves consideration as to which questions are worth asking, in addition to the reasons why.
Much of the modern discourse is around bringing people together rather than encourage them to spend time in solitude. Those in a scarcity trap (of time and money) suffer a bandwidth tax that inhibits the prioritisation of solitude. That said, material advantages do not in themselves enrich solitude. What matters instead is how a person uses social experience in the formulation of questions and the subsequent listening that takes place.
Millennials do not like to acknowledge external sources of wisdom. Communities that involve commitments in which tradition and authority play important roles are avoided. We lack communities that offer individuals a sense of their history and how they contribute to a bigger picture.
Family, in all its forms, can be where we find our richest experience of love and belonging. It provides the existential security needed to practice solitude, secure with ourselves and with our questions and responses, without feeling the need to perform and share results.
Universities should drop all language about competitiveness, prosperity and economic contribution to society and remove themselves from rankings which only institutionalise the needless focus on competitiveness. They should no longer refer to students as “customers” and the course selection should be more limited and done for them, with the university demonstrating conviction as to the courses that it believes matter. Students should have more time off to spend thinking about what they learn.
Solitude and community are mutually reinforcing concepts.
]]>Whether it’s adding a website snapshot to a presentation, before/after comparisons for GitHub Issues and Pull Requests, or just as a quick method for saving a cropped version of an image, I take a lot of screenshots.
I recently discovered Screenotate, which integrates with macOS to automatically OCR images and generate a HTML counterpart page. This makes finding a particular screenshot a little easier, if you can remember some words on the page, and saves you re-typing text.
I tried it, and while I’d happily pay for it, there were a couple of issues that meant it didn’t really fit for me.
~/screenshots
directory in the Dock as a fan to quickly drag the latest screenshot into another app, and I’d frequently pick the previous image because the latest screenshot hadn’t written yet.Screenotate mentions it uses Google’s Tesseract OCR engine. I quickly found several libraries, so spent an hour getting a basic Ruby version up and running.
#!/usr/bin/env ruby
require 'pathname'
require 'rtesseract'
class Screenshot
def initialize(file)
@file = file
end
def text
RTesseract.new(file.to_s).to_s
end
def filename
file.basename
end
def realpath
file.realpath
end
protected
attr_reader :file
end
class Html
def initialize(screenshot)
@screenshot = screenshot
end
def to_s
<<~HTML
<html>
<head>
<meta charset="UTF-8">
<meta name="generator" content="ScreenshotToHtml">
<title>#{screenshot.filename}</title>
</head>
<body>
<div>
<img src="#{screenshot.realpath}">
</div>
<div>
<tt><a href="file://#{screenshot.realpath}">#{screenshot.realpath}</a></tt>
</div>
<div>
<pre>#{screenshot.text}</pre>
</div>
</body>
</html>
HTML
end
protected
attr_reader :screenshot
end
SCREENSHOT = Pathname.new(ARGV.shift).freeze
puts Html.new(Screenshot.new(SCREENSHOT))
With my proof of concept working well, I just needed to use an Automator Folder Action to run the script for new items added to ~/screenshots
.
This is where things got difficult. Automator doesn’t use your usual shell environment, so it didn’t have my homebrew-installed Ruby and associated gems in the PATH
. I played around with this for a while, but in the end it just got so complicated and brittle that I gave up.
I noticed the author of the Ruby tesseract library also wrote a Crystal version, which looked suspiciously similar.
I love Ruby, but it is frustrating that you need a full Ruby install for a simple little CLI tool. Crystal is a compiled and statically typed language with a syntax that’s heavily inspired by Ruby. Even the standard library feels very similar in naming conventions and API.
It didn’t take me long to convert my Ruby script to Crystal. I literally copied Ruby version and worked my way through the compiler errors. I barely had to change anything!
require "path"
require "tesseract-ocr"
class Image
def initialize(image_path : Path)
@image_path = image_path
end
def text
Tesseract::Ocr.read(real_path.to_s)
end
def filename
real_path.basename
end
def real_path
image_path.expand.to_native
end
protected def image_path
@image_path
end
end
class Html
def initialize(image : Image)
@image = image
end
def to_s
<<-HTML
<html>
<head>
<meta charset="UTF-8">
<meta name="generator" content="ImageToHtml">
<title>#{image.filename}</title>
</head>
<body>
<div>
<img src="#{image.real_path}">
</div>
<div>
<tt><a href="file://#{image.real_path}">#{image.real_path}</a></tt>
</div>
<div>
<pre>#{image.text}</pre>
</div>
</body>
</html>
HTML
end
protected def image
@image
end
end
image = Path[ARGV.first]
puts Html.new(Image.new(image)).to_s
I then compiled the program to /usr/local/bin/image-to-html
and then it was just a matter of calling it from Automator.
I’ve since developed the little script into a more well-designed library, but in essence it’s just as simple.
I don’t get some of the nice extras of Screenotate – automatically adding text to the clipboard and its integrated search – but for me this has been working much better, and I’ve learned some Crystal too!
]]>A book inspired by the experience of doing communications in GDS and other government departments. The book is self-published, so buy direct from the author.
I found some of the book less practical than 256 Bloghacks, but this is obviously more directed at “organisations” rather than individuals.
Here are the bits that I enjoyed most.
Your comms strategy should simply be: communicate.
Don’t start with a “comms strategy”, because most of the time, you probably don’t need one. It’s about telling the story as it happens. Good comms describes how you did what you’ve done. Bad comms just says that you’ve done it.
Consider what you’re trying to communicate through each post. The purpose of a post containing some WIP screenshots might be “remind people that we’re actively working on Project X”, or it might be “to temperature-test a new UI direction”. Really understanding the purpose of communication helps fine-tune the three layers.
Most people are too busy most of the time. Breaking your communication into three layers helps people understood quickly and at the right level of detail for their current situation.
Each layer should be considered separately as they have very different jobs. A great context will likely be much more conversational than is appropriate for an authoritative details. An effective lure might not convey the main point of the context, but instead ask a profound question that compels the reader to dig deeper.
A couple of examples:
Lure: A Tweet Context: A blog post Details: A research report
Lure: An email subject Context: The email body Details: A PDF attachment
TV scientists may have published academic papers, but to reach a wider audience they create simplified versions in the form of TV shows, and lure people with their social media accounts and breakfast show appearances.
I’m writing a first draft and reminding myself that I’m simply shovelling sand into a bucket, so that later I can build sandcastles – Shannon Hale
All first drafts are bad. Once accepted, you remove the pressure on yourself to “be a great writer”. Just get the ideas down; others can help you edit.
Bad drafts help you fix issues early on.
They also build a catalogue of ideas to pull from. Even if most drafts never go anywhere, in some posts you’ll make connections to past drafts that you can pull in and finally get the idea over the line.
Try to keep feedback on drafts at a really high level. “Make the point earlier” or “try arguing your case from the other side”. Drafts will need to be chopped and changed so much that it’s not worth worrying about formatting and grammar changes. These are usually uncontentious and can be picked up at the end.
At GDS they intentionally made cheaper looking videos to avoid getting hassled for spending public money on slick production.
If you’re not driven by advertising revenue, then who you reach is more important than how many you reach.
]]>Programming and writing have common traits and similar processes.
Code is not a natural language, but its fixed grammar makes certain formulations naturally understandable and others, while formally correct, will be hard to grasp.
A good program and a good novel are both the sum of local and global elements that work well. As well as single statements being well written and readable, a coherent structure and pleasing relationships between the parts is also crucial.
Almost all programs and written works are complex enough that you can’t hold their entirety in your head. To be successful at both programming and writing you need to make constant, consistent progress. You must probe the environment to see what works.
Once complete, writing remains immutable. Programs suffer from entropy so must be continually updated to remain functional as the environment changes around them.
Programmers often believe that the first version of a system can be quite imperfect as it always evolves. Writers know they have a single bullet for every novel, to the point that writing prose is mostly an act of rewriting.
A good initial structure will result in a better system as it grows organically.
A programmer should pretend the primitive kernel of a new system is their only bullet, and rewrite it again and again until it is the best possible design. Even after years of distance from the original creation, and even if the original core was just a tiny faction of the future mass, the initial design greatly informs what will happen later.
Source: http://antirez.com/news/135
]]>