I’ve started reading Thinking Fast and Slow by Daniel Kahneman(check out my Kindle highlights)
Kahneman was one of the first to identify cognitive bias in our thinking, and this book describes a metaphor for two systems of thinking; System 1 (fast, intuitive, prone to bias) and System 2 (slow, methodical, conscious) working together to influence our interaction with the world.
System 1 is generally to do with emotion and feeling, but it also deals with facts if those facts have a strong belief behind them (for example, 2+2=4; Paris is the capital of France).
I have often coached people to use strong metaphors to express their ideas, and reading the early chapters of this book, I think part of the reason that I do this is that strong metaphors are much easier to absorb into System 1.
An engaging story is easier to absorb and express to others than a complicated description that requires conscious attention. This applies as much to code as is does to writing or speaking.
]]>The seven steps are:
git clone https://github.com/andypalmer/easy-wordpress.git my-new-wordpress
cd my-new-wordpress
heroku apps:create my-new-wordpress
heroku addons:add cleardb:ignite
heroku config:add DATABASE_URL=`heroku config:get CLEARDB_DATABASE_URL`
git push heroku master
heroku open
There are a couple of other tweaks required to allow uploading assets, but that’s essentially it.
Happy blogging
]]>BlahBlahState
, then refactoring to a Strategy
is quite invasive, but if it’s phrased in terms of the why, then the names don’t need to change.
A good analogy here is the relation of unit tests to implementation; you should be able to change the internal implementation of the class without changing the tests. If you can’t, then the tests are too brittle. Likewise, you should be able to change the implementation without changing the class name; if your class name is tied to the implementation, through the pattern name, then it’s too brittle.
]]>This might seem a little cute, but it has immense power. Security features can now be tested by having Carl try to do something that only Sharon is permitted to do. The team can push back on features that seem at odds with the stories they’ve built so far; “This feature is labelled as a Sharon feature, but it seems more like something that Kevin and Carl would be doing day-to-day. Is there a reason for that?”
It gives the team something to identify with. Just as somebody can jump into a soap opera at any point, and infer the backstory; new team members absorb the characters as they listen to discussions during planning or story writing. It enriches the experience and gives another dimension for people to ask questions.
In soap operas, characters sometimes suddenly reveal a secret history; Phil is in witness protection from the Mafia. As long as the revelation doesn’t completely invalidate the character we’ve come to know, we’re happy to accept it. Our personas can also cope with significant changes when key aspects of the project change, allowing stories and automated acceptance criteria written in this style to adapt as the project progresses.
Like with all good characters, once you get to know them well, the stories write themselves.
]]>While I’ve been writing new recipes, I’ve started using a pattern that ensures good separation of responsibilities while making the recipes themselves easy to read.
In my pattern, the default.rb
file in the recipe consists only of includes. The default recipe is used to make sure that something useful happens.
For example, I created a recipe to install and configure the Hamachi VPN client. This consists of two recipes; install.rb
(which downloads and installs the appropriate package and dependencies) and connect.rb
(which authenticates with Hamachi and joins the appropriate network). The default.rb includes these two recipes.
I’ve found that this style results in much tidier recipes.
]]>It’s a lot more text than I’d prefer in a presentation, but this was for a small group of developers and was more of a face to face conversation with examples on the slides to back up the points
It’s mainly a series of thoughts that I should have shared on my blog or twitter; hopefully this will go some way to helping get the ideas out there
]]>
Training is usually fairly low cost, but it usually only provides an overview of what something can do for your team. Training can be a useful morale boost, but it very rarely becomes immediately applicable to your business domain. Acquiring a new skill requires practice in a real environment. This loosely corresponds to moving someone onto the Dreyfus skills ladder or moving from Unconscious Incompetence to Conscious Incompetence in the four stage model.
Mentoring allows your team to try out new skills under the guidance of a skilled practitioner. When the team member does something inconsistent with current practices, the mentor will intervene, explaining why they are intervening, any likely problems from the original solution and demonstrate an alternative solution, explaining why they think this may be more appropriate. After the discussion, the pair may decide to continue with the original solution and see if it works, or go with the alternative. This loosely corresponds to moving the team member to Competent on the Dreyfus model or to Conscious Competence in the four stage model.
Coaching is a more hands-off approach. The team will continue to work in their normal style, while the coach observes. Using Socratic questioning, the coach will generally guide the team members to explore new avenues of thought, to discover problems that they are likely to encounter and to work in a way that minimises the likelihood of any unknown issues encountered becoming an insurmountable block. Coaching offers the highest value, as it gives the team a toolset for modifying their thinking on an ongoing basis. It corresponds loosely to moving into the advanced stages of the Dreyfus model (Proficient / Expert) or towards Unconscious Competence in the four stage model.
]]>My definition1 of agile is being flexible to adapt an existing process.
That is, if your existing process looks like waterfall, you’re still agile if you introspect, retrospect and experiment to improve your process. If at the end, your process looks like waterfall, then as long as you have introspected, retrospected and experimented and found that this approach gives the best results, then your process is agile.
[1] Although this might not fit with other definitions. Your mileage may vary
]]>The same people who will have heard about my dislike of checked exceptions will probably also know about my dislike of returning null. I was mulling over a legacy code base that I may be taking over in the future and one of the first things that I would like to do is to replace all null
returns with something meaningful.
Normally, I would remove null
s by searching for the offending return statement, fixing it to do something meaningful (and if I don’t know what meaningful means in this place, throw an exception), then find usages of that method in the workspace and remove any (now defunct) null checks.
Enter the checked exception as a refactoring tool!
public Result someMethod() {
Result result = someMethodIDontControl();
if(null == result) {return null;} // Actually, this is really crap because in reality, I'd just return result, but bear with me!
return result;
}
becomes
public Result someMethod() throws IUsedToReturnNullPleaseFixMe {
Result result = someMethodIDontControl();
if(null == result) {throw new IUsedToReturnNullPleaseFixMe();} // This is temporary. The right thing _might_ be an exception, but we'll work that out later
return result;
}
Now we can lean on the compiler to find all the places that call this method. We can strip out any null checks (that are now unnecessary), look to see if there is something meaningful that we should be doing, and then add throws IUsedToReturnNullPleaseFixMe
to the method we’ve just fixed. When we’ve propagated our exception to the top level, we’re done. What I would do at this point is probably delete the exception class, fix all the resulting compile errors by removing the throws clauses, until finally the last compilation error is the original throw new IUsedToReturnNullPleaseFixMe();
which I can now replace with something meaningful (e.g. throw a meaningful exception, return a meaningful NullResult, convert to a collection and return emptySet() etc)