June 25, 2015
Mocks vs. Stubs - It Has Nothing To Do With The ImplementationAn area of confusion I see quite often is on the difference between mocking and stubbing.
I think this confusion arises from the frameworks we use to create mock objects, which can also be used to create stubs.
In practice, the difference is very straightforward.
If we want to test some logic that requires data that - for whatever reason - comes via a collaborator, we use a stub. Put simply, a stub returns test data.
If we want to test that an interaction with a collaborator happens the way we expect it should, we use a mock. Mock objects test interactions.
Take a look at these example tests, just to illustrate the difference more starkly:
The first test uses Mockito to create an object that returns test data, so I can test that the total cost of a trade is calculated correctly using the stock price my StockPricer stub returns.
The second test uses a hand-rolled object to test how many times the Trade object calls GetPrice() on the mock StockPricer.
Whether or not we used a mock objects framework has no bearing on whether the test double is a mock or a stub. The kind of test we're writing decides that.
If we want our test to fail because external data suppled by a collaborator was used incorrectly, it's a stub.
If we want our test to fail because a method was not invoked (correctly) on a collaborator, it's a mock.
(And, yes, back in the days before mock objects ,we'd have called MockStockPricer a "spy".)
June 20, 2015
If We're In Such High-Demand and Short Supply, Why Has Developer Pay Been Falling?Thoughts turn again to the push by government, employers and other interested parties to get more people "coding", and on the mythical shortage of professional programmers that has driven much of it over the last few years.
Being a scientific sort of a cat, I'm always interested to see what evidence exists to support any position - whether it be the "let's get everybody coding" lobby's, or mine that (while I'm all in favour of everybody trying it) there is no such skills shortage that needs urgently addressing.
In a free and properly functioning market, we'd expect any resource that is in short supply to go up in value. When demand outstrips supply - especially by as much as the lobbyists claim - we get a "seller's market" where suppliers can name their price to a larger extent.
This should mean that we see the salaries and contract rates of professional software developers going up in real terms. Checking out the advertised salary trends on itjobswatch.co.uk we see a markedly different picture, though; developer earnings have been going down, and for many years.
For example, jobs advertised looking for a "Developer" had a rough average salary of about £38,000 per year 10 years ago. Today, it's hovering around the £42,000 mark, with the occasional blip as the latest new and shiny thing drives a temporary increase in the average before the market readjusts again - presumably after more people have had a chance to get the new and shiny thing on their CV.
Adjusting for inflation, the 2005 equivalent of £42,000 is about £30,000. That is to say, in real terms, average developer salaries have actually fallen by about 25%.
Add in the misery of house prices rises and the cost of travel rising way above the rate of inflation, and this paints a picture of today's developer being much worse off than she was in 2005.
If developer pay had kept pace with inflation, the average today would be £60,000 p.a. And that trend is repeated across regions, across programming languages and across most industries. C# developer pay has been falling. Java developer pay has been falling. London developer pay has been falling, Manchester developer pay has been falling. Pay for devs working in banks has been falling,. Pay for devs working in retail has been falling. The upper-quartile pay has been falling, The lower quartile pay has been falling.
And when we look at contractor pay, it's even more depressing. Many very experienced developers report charging the same rates today as they did as much as 20 years ago. My own experience, and that of my peers, has been that rates never recovered after the first dotcom bubble went pop in 2001, and they've been flatlining ever since - not even creeping up below the rate of inflation.
Now, how does this square with a seller's market?
In short: it doesn't.
June 19, 2015
A 'Software Developer' Knows Enough To Deliver Working Software Alone, And In TeamsA long discussion on a telephone conference this morning ensued about what a "software developer" is.
This relates to education and apprenticeships. They're an SME contemplating running an apprenticeship scheme, and - having roundly rejected all the officially government-snactioned schemes out there as being 'too business IT orientated' and just a bit too general and handwavy for their needs - they're naturally asking the question: what should a software developer know how to do?
We harked back to Scott Ambler's idea of developers as "generalising specialists". Perhaps, we argued, a software developer is someone who is capable of doing all of it - managing the work, gathering requirements, designing and architecting solutions (including a basically good enough user experience), implementing code that satisfies the requirements and is reliable and maintainable and scalable and fungible and edible etc enough for the customer's needs, testing it thoroughly enough to make sure of that, releasing or deploying it into the working environment, and maintaining it over many future releases - to a basic level of competence.
In short, a "software developer" might be someone who would be capable, just working by themselves and directly with the customer, of delivering working software that has value to that customer.
Having said that, we also recognised that working in teams brought its own set of concerns and challenges, and requires more skills than does working alone. And so, we also speculated that a "software developer" is someone who not only can deliver working software alone, but they can also successfully deliver working software as part of a team.
This is actually giving us a good steer on what the basics might need to cover. You wouldn't, for example, be able to get away with skipping build automation in your apprenticeships, because that's a necessary part of delivering working software, and by this definition, something every software developer should know how to do.
Nor would we be able to get away with skipping Continuous Integration in their practical education, because that is a necessary part of working in teams on the same piece of software.
And so on.
The long and the short of it is that a "software developer" needs to know the basics of all of the key development disciplines - including how to manage it - to satisfy our definition. They would not, for example, be clueless about software architecture, because there may be no architect to tell them what to do. They would not be able to rely on testers, because they may be the only tester - aside from the customer, of course. They would not be able to count on the services of someone from IT operations to build and configure machines, networks and all that malarkey, because they may be the only technical person involved.
And so on and so on.
Now, I'm not suggesting that every developer has to be a world-class expert on all of the disciplines. A strong command of programming, with a practical appreciation of how to do the others - practical enough to do a basically good job yourself - would suffice.
And, yes, that was our third and final idea: a software developer is first and foremost a programmer, and that's simply because - if working software is the desired end result - then all roads lead to code.
The thinking continues...
June 9, 2015
Focus On What The Users Care About, Not What The System Cares AboutJust time before my morning conference call to draw your attention to a very interesting blog post that was tweeted earlier about how a "delay" in bus services reported by Transport for London (TfL) was not really a delay from the passenger's perspective, highlighting the dangers of designing services - in this case, passenger information systems - from the system perspective and not the user's.
I think this is a classic example of a system focus taking precedent over a user focus. The gist of it was that TfL were reporting "delays" of up to 40 minutes on bus services, but when the blogger caught a bus during that time period, he sailed through the streets of London and arrived without any delay at his destination.
As he describes it:
"From TfL’s point of view, bus x is supposed to go past point y at time z. If it gets to z late, it has been delayed.2 Quite rightly, TfL care about specific buses and the overall service. But from my point of view, if I get to point y at time z, I am happy – and will be blissfully ignorant of the fact that I am on bus q which should have got to y half an hour earlier"
It might serve as a timely reminder that we should make a bigger effort to distinguish between features we think our system should have and things our users care about, and be driven by the latter, not the former.
May 27, 2015
Intensive TDD Workshop, London, Sat July 18thJust a quick hoorah to announce the next great-value weekend TDD workshop, which will be in South Wimbledon on Saturday July 25th. (Corrected from July 18th in previous version of this post, BTW.)
You can find out more and grab your extremely reasonably-priced ticket here.
Thank you @jasongorman for an amazing TDD workshop. I enjoyed the CRC design part a lot. See you on May!!— Vicenç García-Altés (@vgaltes) March 14, 2015
On the train reading TDD By Example after running through the Fibonacci Kata. Inspired by @jasongorman's excellent TDD Workshop today.— Neil McLaughlin (@neilbmclaughlin) March 14, 2015
@jasongorman Thanks for the great TDD course! See you in May for Advanced Unit Testing— Manuel Rivero (@trikitrok) March 15, 2015
@jasongorman really enjoyed the intensive TDD workshop!. Learnt a lot, thanks. Any chance we could get the slides?— Valde (@jvalde) April 13, 2015
@jasongorman Awesome intensive TDD day. Really useful and learnt plenty. Thanks, Jason!— Gary McLean Hall (@garymcleanhall) April 11, 2015
May 26, 2015
Ditch The Backlog and Start Iterating!Goals.
The old ways have a habit of sneaking back in through the back door. And so it is with Agile Software Development that, despite all our protestations about being iterative and open to feedback and change, The Big PlanTM found its way back cunningly disguised as the backlog.
The reality is that most Agile teams are not iterating their designs in rapid feedback cycles, but instead are incrementally working their way through a plan for a solution that was cooked up by what we used to call "requirements analysts" - generally speaking, people who talk to the customer to find out what they want and draw up a specification - right at the start.
The backlog on many teams doesn't change much. And this is because the goal of each small frequent delivery is not to try out the software and see how it can be made better in the next delivery, but to test each delivery to check that it conforms to The Big PlanTM.
The box-ticking exercise of user acceptance testing usually just asks "is that what we agreed?" The software isn't tested for real, by real users, working on real problems to ask "is that what we really need?"
And so it is that many Agile teams still get that skip-ful of feedback when the "iterated" solution finds its way into the real world. To all intents and purposes, that's a Big Bang release. Y'know, the kind we thought we'd stopped doing.
Better to get that kind of feedback throughout. Better also to shift focus from The Big PlanTM to actual end user goals, not a list of system features that someone believed would meet those goals (if they ever thought to ask what those goals were.)
Imagine we're working for an airline. We turn up for work and are presented with a backlog of feature requests for an online check-in facility. Dutifully, we work our way through this backlog, agreeing acceptance tests with our customer and ticking them off one by one. Eventually, the system goes live. At which point we discover that, because all of the flights we operate are long-haul, and therefore almost all our passengers need to check in baggage for the hold, we've had almost zero impact on the time it takes to check-in.
What we could have been doing, instead of working our way through The Big PlanTM, is working our way towards reducing check-in times. If that was the original goal, then that's what we should have been iterating towards.
This is actually a founding principle of Agile, before it was called "Agile". Tom Gilb's ideas about evolutionary project management, dating back to the late 1980s, clearly highlight the need to focus on goals, not plans. Each iteration needs to bring us closer to the goal, and we need to test and measurre progress not by software delivered against plan - I mean, damn, there was a major clue right there! - but by progress towards reaching our goals.
Instead of putting all our faith in the online check-in solution that was presented to us, we could have been focusing on those baggage check-in queues and streamlining them. The solution might not even involve software. In which case we swallow our pride and acknowledge we don't have the answer, instead of wasting a big chunk of time and money pretending we do.
This requires a different relationship with the customer, where developers like us are just one part of a cross-discipline team tasked with solving problems that may or may nor involve software. We should be incentivised to write software that really achieves something, and to be prepared to change direction when we learn that we're on the wrong track.
The first step in that journey is to ditch the backlog. Put a match to The Big PlanTM.
Instead of plans, have goals; a handful of headline requirements that really are requirements - to reduce check-in times, to detect and treat heart disease sooner, to save 1p on the cost of manufacturing a widget, to get 20% more children in Africa through school, or whatever the goal is that someone thinks is valuable enough to invest the kind of money software costs to create and maintain in. We ain't done until the goal's been achieved at least to some extent, or until we've abandoned the goal.
That requires developers to play an integral part in a wider - and probably longer-term - game. We are not actors who turn up and say the lines someone else wrote on a set someone else built. We write our lines and build our sets and then act them out to an audience whose feedback should determine what happens next in the story.
May 13, 2015
Working Backwards From Test Assertions
The second of six special screencasts to celebrate 6 years since Codemanship was formed.
April 25, 2015
Non-Functional Tests Can Help Avoid Over-Engineering (And Under-Engineering)Building on the topic of how we tackle non-functional requirements like code quality, I'm reminded of those times where my team has evolved an architecture that developers taking over from us didn't understand the reasons or rationale for.
More than once, I've seen software and systems scrapped and new teams start again from scratch because they felt the existing solution was "over-engineered".
Then, months later, someone on the new team reports back to me that, over time, their design has had to necessarily evolve into something similar to what they scrapped.
In these situations it can be tricky: a lot of software really is over-engineered and a simpler solution would be possible (and desirable in the long term).
But how do we tell? How can we know that the design is the simplest thing that a team could have done?
For that, I think, we need to look at how we'd know that software was functionally over-complicated and see if we can project any lessons we leearn on to non-functional complexity.
A good indicator of whether code is really needed is to remove it and see if any acceptannce tests fail. You'd be surprised how many features and branches in code find their way in there without the customer asking for them. This is especially true when teams don't practice test-driven development. Developers make stuff up.
Surely the same goes for the non-functional stuff? If I could simplify the design, and my non-functional tests still pass, then it's probable that the current design is over-engineered. But in order to do that, we'd need a set of explicit non-functional tests. And most teams don't have those. Which is why designs can so easily get over-engineered.
Just a thought.
Continuous Inspection ScreencastIt's been quite a while since I did a screencast. Here's a new one about Continuous Inspection, which is a thing. (Oh yes.)
April 23, 2015
The Big Giant Object Oriented Analysis & Design Blog PostHaving been thwarted in my plan to speak at CraftConf on Budapest this week, I find myself with the luxury of time to blog about a topic that comes up again and again.
Object oriented analysis and design (OOA/D) is not a trendy subject these days. Arguably, it had it's heyday in the late 1990's, when UML dinosaurs ruled the Earth. But the fact remains that most software being written today is, at least to some extent, object oriented. And it's therefore necessary and wise to be able to organise our code effectively in an object oriented way. (Read my old, old paper about OOA/D to give yourself the historical context on this.)
Developers, on the whole, seem to really struggle getting from functional requirements (expressed, for example, as acceptance tests; the 21st century equivalent of Use Case scenarios) to a basis for an object oriented design that will satisfy that requirement.
There's a simple thought process to it; so simple that I see a lot of developers struggling mainly to take the leap of faith that it really can be that simple.
The thought process can be best outlined with a series of questions:
1. Who will be using this software, and what will they be using it to do?
2. How will they interact with the software in order to do what they want?
3. What are the outcomes of each user interaction?
4. What knowledge is involved in doing this work?
5. Which objects have the knowledge necessary to do each piece of the work?
6. How will these objects co-ordinate the work between themselves?
In Extreme Programming, we answer the first question with User Stories like the one below.
A video library member wants to donate a DVD to the library. That is who is using the software, and what they will be using it to do.
In XP, we take a test-driven approach to design. So when we sit down with the customer (in this case, the video library member) to flesh out this requirement - remember that a user story isn't a requirements specification, it's just a placeholder to have a conversation about the requirements - we capture their needs explicitly as acceptance tests, like this one:
Given a copy of a DVD title that isn’t in the library,
When a member donates their copy, specifying the name of the DVD title
Then that title is added to the library
AND their copy is registered against that title so that other members can borrow it,
AND an email alert is sent to members who specified an interest in matching titles,
AND the new title is added to the list of new titles for the next member newsletter
AND the member is awarded priority points
This acceptance test, expressed in the trendy Top Of The Pops-style "given...when...then..." format, reveals information about how the user interacts with the software, contained in the when clause. This is the action that the user performs that triggers the software to do the work.
The then clause is the starting point for our OO design. It clearly sets out all of the individual outcomes of performing that action. Outcomes are important. They describe the effect the user action has on the data in the system. In short, they describe what the user can expect to get when they perform that action. From this point on, we'll refer to these outcomes as the work that the software does.
The "ANDs" in this example are significant. They help us to identify 5 unique outcomes - 5 individual pieces of work that the software needs to do in order to pass this test. And whatever design we come up with, first and foremost, it must pass this test. In other words, the first test of a good OO design is that it works.
The essence of OO design is assigning the work we want the software to do to the objects that are best-placed to do that work. By "best-placed", I mean that the object has most, if not all, of the knowledge required to do that work.
Knowledge, in software terms, is data. Let's say we want to calculate a person's age in years; what do we need to know in order to do that calculation? We need to know their date of birth, and we need to know what today's date is, so we can calculate how much time has elapsed since they were born. Who knows a person's date of birth?
Now, this is where a lot of developers come unstuck. We seem to have an in-built tendency to separate agency from data. This leads to a style of design where objects that know stuff (data objects) are acted upon by objects that do stuff (services, command, managers etc etc). In order to do stuff, objects have to get the necessary knowledge from the objects that know stuff.
So we can end up with lots of low-level coupling between the doing objects and the knowing objects, and this drags us into deep waters when it comes to accommodating change later because of the "ripple effect" that tighter coupling amplifies, where a tiny change to one part of the code can rippled out through the dependencies and become a major re-write.
A key goal of good OO design is to minimise coupling between modules, and we achieve this by - as much as possible - encapsulating both the knowledge and the work in the same place, like this:
This is sometimes referred to as the "Tell, Don't Ask") style of OO design, because - instead of asking for an object's data in order to do some work, we tell the object that has that data to do the work itself. The end result is fewer, higher-level couplings between objects, and smaller ripples when we make changes.
If we're aiming for a loosely coupled design - and we are - then the next step in the OO design process, where we assign responsibility for each piece of work, requires us to put the work where the knowledge is. For that, we need to map out in our heads or on paper what this knowledge is.
Now, I'm very much a test-driven sort of dude, and as such I find that design thinking works best when we work from concrete examples. The acceptance test above isn't concrete enough for my tastes. There are still too many questions: which member, what DVD title, who has registered an interest in matching titles, and so on?
To make an acceptance test executable, we must add concrete examples - i.e., test data. So our hand-wavy test script from above becomes:
Given a copy of The Abyss, which isn’t in the library,
When Joe Peters donates his copy, specifying the name of the title, that it was directed by James Cameron and released in 1989
Then The Abyss is added to the library
AND his copy is registered against that title so that other members can borrow it,
AND an email alert with the subject “New DVD title” is sent to Bill Smith and Jane Jones, who specified an interest in titles matching “the abyss”(non-case-sensitive), stating “Dear
, Just to let you know that another member has recently donated a copy of The Abyss (dir: James Cameron, 1989) to the library, and it is now available to borrow.”
AND The Abyss is added to the list of new titles for the next member newsletter
AND Joe Peters receives 10 priority points for making a donation
Now it's all starting to come into focus. From this, if I feel I need to - and earlier in development, when my domain knowledge is just beginning to build, I find it more useful - I can draw a knowledge map based on this example.
It's by no means scientific or exhaustive. It just lays out the objects I think are involved, and what these objects know about. The library, for example, knows about members and titles. (If you're UML literate, you'd might think this is an object diagram... and you'd be right.)
So, now we know what work needs to be done, and we know what objects might be involved and what these objects know. The next step is to put the work where the knowledge is.
This is actually quite a mechanical exercise; we have all the information we need. My tip -as on old pro - is to start with the outcomes, not the objects. Remember: first and foremost, our design must pass the acceptance test.
So, take the first piece of work that needs to be done:
The Abyss is added to the library
...and look for the object we believe has the knowledge to do this. The library knows about titles, so maybe the library should have responsibility for adding this title to itself.
Work through the outcomes one at a time, and assign responsibility for that work to the object that has the knowledge to do it.
Class Responsibility Collaboration cards are a neat and simple way of modeling this information. Write the name of type of object doing the work at the top, and on the left-hand side list what is responsible for knowing and what it is responsible for doing.
(HINT: you shouldn't end up with more CRC cards than outcomes. An outcome may indeed involve a subsystem of objects, but better to hide that detail behind a clean interface like Email Alert, and drill down into it later.)
Now we have a design that tells us what objects are involved, and which objects are doing which piece of work. We're almost there. There's only one piece of the OO jigsaw left; we need to decide how these objects collaborate with each other in order to co-ordinate the work. Objects, by themselves, don't do anything unless they're told to. The work is co-ordinated by objects telling each other to do their bit.
If the work happens in the order it's listed in the test, then that pretty much takes care of the collaborations. We start with the library adding the new title to itself. That's our entry point: someone - e.g., a GUI controller, or web service, or unit test - tells the library to add the title.
Once that piece of work is done, we move on to the next piece of work: registering a default copy to that title for members to borrow. Who does that? The title does it. We're thinking here about the thread of control - fans of sequence diagrams will know exactly what this is - where, like a baton in a relay race, control is passed from one object ("worker") to the next by sending a message. The library tells the new title to register a copy against itself. And on to the next piece of work, until all the work's been done, and we've passed the acceptance test.
Again, this is a largely mechanical exercise, with a pinch of good judgement thrown in, based on our understanding of how best to manage dependencies in software. For example, we may choose to avoid circular dependencies that might otherwise naturally fall out of the order in which the work is done. In this case, we don't have Title tell Library to add the title to the list of "new titles" - library's second piece of work - because that would set up a circular dependency between those two objects that we'd like to avoid. Instead, we allow control to be returned by default to the caller, library after title has done it's work.
On a CRC card, we capture information about collaborations on the right-hand side.
Note that Member has no collaborators. This means that Member doesn't tell any other objects to do any work. This is how we can tell it's at the bottom of the call stack. Library, on the other hand, has no objects that tell it to do anything, which places it at the top of the call stack: Library is the outermost object; our entry point for this scenario.
Note also that I've got a question mark on the collaborators side of the Email Alert object. This is because I believe there may be a whole can of worms hiding behind its inscrutable interface - potentially a whole subsystem dedicated to sending emails. I have decided to defer thinking about how that will work. For now, it's enough to know that Title tells Email Alert to send itself. We can fake it 'til we make it.
So, in essence, we now have an object oriented design that we believe will pass the acceptance test.
The next step would be to implement it in code.
Again, being a test-driven sort of cat, I would seek to implement it - and drive out all the low-level/code-level detail - in a test-driven way.
There are different ways we can skin this particular rabbit. We could start at the bottom of the call stack and test-driven an implementation of Member to check that it does indeed award itself priority points when we tell it to. Once we got Member working as desired, we could move up the call stack to Title, and test-driven an implementation of that using our real Member, and a fake Email Alert as a placeholder. Then, when we get Title working, we could finish up by wiring it all together and test-driving an implementation of Library with our real Title, our real Member, and our fake Email Alert. Then we could go away and get to work on designing and implementing the email subsystem.
Or we could work top-down (or "outside-in", as some prefer it), by test-driving an implementation of Library using mock objects for its collaborators Title and Member, wiring them together by writing tests that will fail if Library doesn't tell those collaborators to do their bit. Once we get Library working, we them move down the stack and test-driven implementations of Title and Member, again with the placeholder (e.g., a mock) for Email Alert so we can defer that part until we know what's involved.
A CRC card implies two different kinds of test:
1. Tests that fail because work was not done correctly
2. Tests that fail because an object didn't tell a collaborator to do its part
I tend to find that, in implementing OO designs end-to-end, both kinds of tests come in handy. The important thing to remember is whether the test you're writing is about the work, or about the collaborations. Tests should only have one reason to fail, so that when they do, it's easier to pinpoint what went wrong, so they should never be about both.
Also, sometimes, the test for the work can be implied by an interaction test when parameter values we expect to be passed to a mock object have been calculated by the caller. Tread very carefully here, though. Implicit in this can be two reasons for the test to fail: because the interaction was incorrect (or missing), or because the parameter value was incorrectly calculated. Just as it can be wise not to mix actions with queries, it can also be wise not to mix the types of tests.
Finally, and to reiterate for emphasis, the final arbiter of whether your design works is whether or not it passes the acceptance test. So as you implement it, keep going back to that test. You're not done until it passes.
And there you have it: a test-driven, Agile approach to object oriented analysis and design. Just like in the 90's. Only with less boxes and arrows.