February 4, 2018

Learn TDD with Codemanship

Don't Bake In Yesterday's Business Model With Unmaintainable Code

I'm running a little poll on the Codemanship Twitter account asking whether code craft skills should be something every professional developer should have.




I've always seen these skills as foundational for a career as a developer. Once we've learned to write code that kind of works, the next step in our learning should be to develop the skills needed to write reliable and maintainable code. The responses so far suggest that about 95% of us agree (more than 70% of us strongly).

Some enlightened employers recognise the need for these skills, and address the lack of them when taking on new graduates. Those new hires are the lucky ones, though. Most employers offer no training in unit testing, TDD, refactoring, Continuous Integration or design principles at all. They also often have nobody more experienced who could mentor developers in those things. It's still sadly very much the case that many software developers go through their careers without ever being exposed to code craft.

This translates into a majority of code being less reliable and less maintainable, which has a knock-on effect in the wider economy caused by the dramatically higher cost of changing that code. It's not the actual £ cost that has the impact, of course. It's the "drag factor" that hard-to-change code has on the pace of innovation. Bosses routinely cite IT as being a major factor in impeding progress. I'm sure we can all think of businesses that were held back by their inability to change their software and their systems.

For all our talk of "business agility", only a small percentage of organisations come anywhere close. It's not because they haven't bought into the idea of being agile. The management magazines are now full of chatter about agility. No shortage of companies that aspire to be more responsive to change. They just can't respond fast enough when things change. The code that helped them scale up their operations simultaneously bakes in a status quo, making it much harder to evolve the way they do business. Software giveth, and software taketh away. I see many businesses now achieving ever greater efficiencies at doing things the way they needed to be done 5, 10 or 20 years ago, but unable to adapt to the way things are today and might be tomorrow.

I see this is finance, in retail, in media, in telecoms, in law, in all manner of private sector organisations. And I see it in the public sector, too. "IT delays" is increasingly the reason why government policies are massively delayed or fail to be rolled out altogether. It's a pincer movement: we can't do X at the scale we need to without code, and we can't change the code to do X+1 for a rapidly changing business landscape.

I've always maintained that code craft is a business imperative. I might even go as far as to say a societal imperative, as software seeps into every nook and cranny of our lives. If we don't address issues like how easy to change our code is, we risk baking in the past, relying on inflexible and unreliable systems that are as anachronistic to the way things need to be in the future as our tired old and no-longer-fit-for-purpose systems of governance. An even bigger risk is that other countries will steal a march on us, in much the same way that more agile tech start-ups can steam ahead of established market players simply because they're not dragging millions of lines of legacy code behind them.

While the fashion today is for "digital transformations", encoding all our core operations in software, we must be mindful that legacy code = legacy business model.

So what is your company doing to improve their code craft?






January 9, 2018

Learn TDD with Codemanship

Test Granularity Matters. Ask Any Accountant.

It's that time of year when I have to make sure my company's accounts are all up to date and tickety-boo, and I got a useful reminder about why the granularity of our tests really matters.

In my spreadsheet for bank payments and receipts, I have a formula for calculating what the closing balance at the end of the financial year is. Today, I realised that calculated balance was about £1200 short. Evidently, I had either entered one or more payments incorrectly, or one or more receipts.

I had to go back through all the bank statements for the year double-checking every line item against the spreadsheet.

Now, if I'd had a formula for the balance at the end of every line item, I could simply have checked the closing balances on each statement to see where they diverged.

I've experienced similar pain when relying on tests that check logic at too high a level (e.g., system tests or API tests). When a test fails, I have to go rummage through the call stack to figure out where it went wrong - the equivalent of reading all my bank statements looking for the line item that doesn't match. Much time is spent in the debugger: a red flag.

I strongly encourage teams to rely more on small, focused tests that - ideally - have only reason to fail, and to write those tests as close to the module that's doing that piece of work as they can. So when a test fails it's easy to deduce that "the problem is this, and the problem is here".


January 7, 2018

Learn TDD with Codemanship

Do Your Automated Tests Give You Confidence In Your Code?

I ran a little poll on the @codemanship Twitter account asking:




The responses suggest many developers don't put a lot of faith in their automated tests for detecting bugs. The aim of test automation is to dramatically lower the cost and execution time of regression testing our code so that we're alerted to new bugs sooner rather than later.

The ultimate goal is to have high confidence at any point in time that the software works, and is therefore fit for release. This is a foundational requirement of Continuous Delivery - software should always be shippable.


Examining many test suites, as I do every year, I think I have some insight into this problem. Firstly, most teams that have automated tests don't have particularly good test suites. Much of the code isn't reached by them. Many of the tests ask loose questions, leaving big gaps in their assertions that you could drive a bus-load of bugs through.

Teams quickly learn, after the first few releases, that just because their tests are passing, that doesn't mean the code is working. But there seems to be little appetite for beefing up their tests suites to plug the leaks that bugs are pouring in through.

Very few teams test their tests to see how effective they are at catching bugs. Even fewer teams target more exhaustive testing at "load-bearing" code, or even have any awareness of which parts of the code present the highest risk.

Happy Path thinking still dominates the developer mindset. Most of us don't think like testers. We want to show that our code works, not that it doesn't in certain edge cases. So our tests tend to skip over the edge cases.

In code reviews - for those teams that do them on any regular basis - test assurance tends not to be one of the things reviewers look for. At best, line coverage is checked. If the coverage report shows the new or changed code is executed in a test, that's spiffy for most dev teams. And, to be fair, most teams don't even check for that. You'd be shocked at how many teams are genuinely surprised to learn how low their coverage is. "But we do TDD...!" Evidently not much of the time.

Teams that practice TDD fairly rigorously tend to have test suites they can put more faith in. But, even as a TDD trainer and mentor with two decades of experience doing it, I regularly feel the need to take testing further after my design is complete.

I'm a big fan of guided inspection, reading the code carefully, looking for test cases I may have missed. I'm also big on parameterised testing, because it can buy you potentially massive amounts of test coverage with surprisingly little extra test code.

And, believe it or not, to some extent you can also automate exploratory testing. One example is the simple Java prototype for generating combinations of inputs for use in JUnit tests that I threw together last year. Another example is tools that can randomly generate input data, like Haskell's QuickCheck (and it's many language-specific ports, like JCheck).

I also find simple test analysis techniques like truth tables and decision tables, state transition and program flow models very useful for discovering edge cases I might have missed. Think you're thinking like a tester? Read the first few chapters of Robert Binder's Testing Object Oriented Systems and think again.

So, if you're one of the 58% who said they don't have high confidence in their automated tests, it may be time to take your automated testing to the next level.





January 4, 2018

Learn TDD with Codemanship

The Impact of Fast-Running Unit Tests Can Be Profound

The most common issue I find that holds dev teams back is the testing bottleneck. How long it takes to check that your software still works before rolling it out is a major factor in how often you can do releases.

Consider a rudimentary "maturity model" for checking that our code is fit for release: it's a spectrum of maturity, with the lowest level (let's call it Level 0) being that we don't test it at all and just release it for the users to "test" in the field, and the highest level being testing continuously to try to ensure bugs don't make it into the next 10 minutes, let alone into a production release (call that Level 5).

And there are all levels in between 0 and 5. You might be manually testing before a big release. You might be manually testing iteratively, every couple of weeks. You might be running automated GUI tests overnight. You might have a suite of, say, Cucumber tests that take an hour to run. And so on. Or we might have a mix of 50/50 GUI and unit tests. Or a bunch of "unit" tests that hit databases, making them integration tests. And so on.

There are 3 axes for our maturity model:

x. How effective our tests are at detecting bugs

y. How quickly they run

z. How often we run them

These factors all interrelate. Catching more bugs often means running more tests, which takes longer. And the longer the tests take to run, the less often we're likely to run them.

Together, they answer the question: how long before a bug is likely to be detected?

Teams have to climb the maturity model if they want to release more reliable code more often and reap the business benefits of Continuous Delivery.

They not only have to improve at writing fast-running automated tests, which is a non-trivial skillset that takes years to master, but also at test analysis and design, so the tests they write are asking more of the right questions. (Yes, it's not all about automation.)

Slow-running tests (manual or automated) is a very common bottleneck I find in dev teams, who wrestle with the much higher cost of removing bugs resulting from catching them much later. I've watched teams go round and round in circles trying to stabilise their product to make it acceptable for a major release, sometimes for many months and at a cost of millions. Such costs are typically dwarfed by the knock-on opportunity cost to the business waiting for critical updates to their software and systems.

I also come into contact with a lot of teams who've been writing automated tests for years, but have remained at a fairly low level of testing maturity. Their tests run slow (hours). Their tests miss a bunch of stuff. While these teams don't suffer from prolonged "stabilisation phases" before releases, they still feel like they're wading through treacle to get working code out of the door. High productivity at the birth of a new code base quickly drops to a trickle of new features and a great deal of bug fixing.

The aim for teams striving for sustainable Continuous Delivery is to be able to re-test their code every single time a change is made. Make one change. Run the tests. Fix the one thing you broke if you broke it. Then on to the next baby step.

This means that your tests must run in seconds, not hours, or days, or weeks. And you need high confidence that if you broke the code, a test would show that.

The effect of tightening up test execution can be profound for dev teams, and for the businesses relying on them. I've witnessed some miracles in my time where organisations that were on their knees trying to evolve their legacy systems eventually managed to stand up and walk, even run, as their testing cycles accelerated.

So, for a developer, writing effective fast-running automated tests is a key skill. It's something we should learn early, and continue to improve on throughout our careers.

If you or your team needs to work on your unit testing chops, I've designed a jam-packed 1-day training workshop that'll kickstart things. And this month, bookings are half-price.





December 31, 2017

Learn TDD with Codemanship

New Year's Resolutions - Making High-Integrity Code & Automated Code Inspections Mainstream

What's your software development New Year's Resolution for 2018?

Through Codemanship, I'm going to be giving two things a big push, starting tomorrow:

1. Techniques for producing high-integrity code

This has been my pet topic for the best part of 20 years. Ever since I started contracting, I've been shocked at just how unreliable the majority of software we create is. Especially because I know from practical experience that the techniques we can apply to produce software that almost never fails are actually quite straightforward and can be applied economically if you know what you're doing.

I've been banging the drum for quality by design ever since, but - to my immense frustration - it never seems to catch on. Techniques like Design By Contract, data-driven and property-based testing, and even good old-fashioned guided inspections, are perfectly within reach of the average dev team. No need for Z specifications, proofs of correctness, or any of that hifalutin malarkey in the majority of cases. You'd be amazed what's possible using the tools you already know, like your xUnit framework.

But still, two decades later, most teams see basic unit testing as "advanced". New tools and technologies spread like wildfire through our community, but good practices catch on at a glacial pace.

As we rely on software more and more, software needs to become more reliable. Our practices have lagged far behind the exponentially increasing potential for harm. We need to up our game.

So, in 2018 I'm going to be doing a lot of promoting of these techniques, as well as raising awareness of their value in engineering load-bearing code that can be relied on.

2. Continuous code inspections

The more code I see (hundreds of code bases ever year), the more convinced I become that the practical route to the most maintainable code is automating code inspections. Regular code reviews are too little, too late, and suffer the economic drawbacks of all after-the-fact manual ad hoc testing. Pair programming is better, but it's a very human activity. It misses too much, because pairs are trying to focus on too many things simultaneously. Like code reviews, it's too subjective, too ad hoc, too hit-and-miss.

For years now, I've been in the habit of automating key code quality checks so all of the code can be checked all of the time. The economic argument for this is clear: code inspection is just another kind of testing. It's unit testing for code quality bugs. If testing is infrequent and arbitrary, many bugs will slip through the net. Later code reviews may pick them up, but the longer maintainability issues persist, the more it costs to a. live with them until they are fixed (because they make the code harder to change), and b. fix them.

Dev teams that do continuous automated inspection tend to produce much cleaner code, and they do it with little to no extra effort. This is for the exact same reasons that dev teams that do continuous automated functional testing tend to produce much more reliable code than teams that test manually, and take little to no extra time and effort to achieve that. Many teams even save time and money.

To be honest, automating code inspections involves a non-trivial learning curve. Devs have to reason about code and express their views on design in a way many of us aren't used to. It's its own problem domain, and the skills and experience required to do it well are currently in short supply. But the tools are readily available, should teams choose to try it.

So, a significant investment has to be made to get automated code inspections up and running. But the potential for reuse of code quality checks is massive. There's just one teeny obstacle: we have to agree on what constitutes a code quality bug, within the team, between teams, and across dev communities. Right now, I have some big issues with what the developers of some code analysis tools suggest is "good code". So I switch off their off-the-peg rules and write my own checks. But, even then, it pays off quite quickly.

Anyhoo, those are the two things I'm going to be focusing on in 2018. Wish me luck!


December 7, 2017

Learn TDD with Codemanship

"This would never have happened if we'd written it in Haskell" - Bah Humbug!

Spurred on by a spate of social media activity of the "We replaced a system written in X with one written in Y, and it was way better" kind, I just wanted to throw my hat into the ring on this topic.

As someone with practical insights into high-integrity software development, I can confidently attest that this is bunk of the highest order. There is no programming language that assures reliability.

Sure, there are languages with built-in features that can help, but you actually have to do stuff to make sure your code works 99.999999999% of the time. Y'know? Like testing and wotnot.

For example, you can inflict all kinds of damage in C, thanks to direct manipulation of memory, but you don't have to abuse those features of the language. A Bugatti Veyron has a top speed of 254 mph, but you don't have to drive it at 254 mph.

"We would never have had that crash if we'd been driving a Volvo" really means "We'd never have had that crash if we'd been driving slower".

If you want to avoid dangling pointers in a C program, you can. It just takes a bit of know-how and a bit of discipline. Don't blame the language for any shortcomings you might have in either. The difference the language makes is small compared to the difference you make.


ADDENDUM: Just to clarify, I'm not saying better languages and tools don't help. What I'm saying is that the difference they make can be very small compared to other factors. How do I know this? Well, I've been programming for 35 years and have worked in a dozen or more languages on real projects. So there's that. But also, I've worked with a lot of teams, and noticed how the same team using different tools gets similar results, while different teams using identical tools can get strikingly different results. So I conclude that the team makes the bigger difference, by orders of magnitude. So I choose to focus more on teams and how they work than on the tools, by orders of magnitude. And it's not as if tools and technology don't get enough focus within the industry :)



October 31, 2017

Learn TDD with Codemanship

Safer Duck Typing: Could We Have Our Cake & Eat It?

I've been thinking a lot lately about how we might reconcile the flexibility of duck typing, like in Python and Ruby, with the safety of static type checking like we have in Java and C#.

For many, the swappable-by-default you get with duck typing is a boon for an evolving domain model. And for me... well, there's a reason why people invented static type checking, and I would prefer not to go back to the bad old days of having to keep that model in my head.

Is there a "having our cake and eating it" arrangement possible here? I think there just might be.

In programming, "type safety" means there's a low risk of trying to invoke methods that the target object doesn't support. Static type systems like in Java enforce this as part of the design. All objects have a type, and that type describes what methods they support. Part of the "drag" of programming in Java is having to qualify this for every single object we want to use. Want to pass an object as a parameter in a method call? You'll need to specify what type that object is. So it's not possible to invoke a method that an object doesn't support - well, not easily, anyway.

It seems to me that, in languages like Python, we have that information in our code. We just need to apply it somehow.



In this example, two methods are invoked on a parameter of the calculate_net_salary() function. Whatever is passed in as that parameter value must implement those two methods with the exact signatures. But the Python compiler doesn't see that. If I passed in an instance of a class that didn't implement those methods, it would be perfectly happy.

Scala introduced a concept called structural typing, where we can specify with function parameters what methods any object passed in as that parameter value must support. e.g.,


def quacker(duck: {def quack(value: String): String}) {
println (duck.quack("Quack"))
}


I like how the required interface is defined by the client - I think this is how it ought to be. But I hate that I need to define this at all. It's duplicated information, and extra work that we have to remember to do. It, too, requires me to carry the model in my head. And when these contracts change, it's more code we have to change.

As far as I can see, the information's already in the function's implementation. We could examine the body of a function or method and build a table of the methods it calls. Then we trace back the source of the target instance. (This may require a bit of fancy shooting, but it's doable, surely?)

In my calculate_net_salary() I can trace the target of the invocations of income_tax() and national_insurance() to the parameter tax_calc. Following that back up the call stack to code that invokes calculate_net_salary(), I see that the class of the target instance is TaxCalculator.



Now I can examine this class to see if it does indeed support those methods.

This is something I've been saying all along about duck typing: the type is there, it's just implied.

I think what's needed is a belt-and-braces prototype to see if this could work in practice. If it really could work, then I - personally - would find something like this very useful. Would you? Do you know of something that already does this that my Googling has overlooked?





October 24, 2017

Learn TDD with Codemanship

Don't Want to TDD? Don't TDD. Just Be Honest About Your Reasons


A growing body of evidence strongly suggests that Test-Driven Development produces code that is - on average - more reliable (less bugs per KLOC) and more maintainable (simpler, less duplication, more modular, and far faster and cheaper to re-test). And it can do this with little or no extra effort.

Hooray for our side!

But, of course, I'm always at pains to be clear that TDD is not compulsory. If you don't want to do it, then don't do it.

But if not TDD, then what else are you doing to ensure your code is reliable and maintainable? Perhaps you're writing automated tests after you've written the code, for example. Perhaps you're writing assertions inside the code and using a tool like QuickCheck to drive test cases. Perhaps you're doing Design by Contract. Perhaps you're using a model checker. What matters is the end result. TDD is optional.

You'll have to forgive my skepticism when people tell me they choose not to do TDD, though. Usually - it transpires upon seeing the resulting software - what they really mean is "we choose not to write reliable and maintainable code" and "we choose not to worry about the release after this one." The world is full of legacy production code that wasn't intended to last, much of it decades old.

So, by all means, do it some other way if that's what floats your boat. But be honest with yourself about your reasons. Eventually, whatever your stated justification, your code will tell the real story.






August 11, 2017

Learn TDD with Codemanship

Update: Code Craft "Driving Test" FxCop Rules



I've been continuing work on a tool to automatically analyse .NET code submitted for the Code Craft "Driving Test".

Despite tying myself in knots for the first week trying to build a whole code analysis and reporting framework - when will I ever learn?! - I'm making good progress with Plan B this week.

Plan B is to go with the Visual Studio code analysis infrastructure (basically, FxCop). It's been more than a decade since I wrote FxCop rules, and it's been an uphill battle wrapping my head around it again (along with all the changes they've made since 2006).

But I now have 8 code quality rules that are kind of sort of working. Some work well. Some need more thought.

1. Methods can't be longer than 10 LOC

2. Methods can't have > 2 branches

3. Identifiers must be <= 20 characters. (Plan is to exempt test fixture/method names. TO-DO.)

4. Classes can't have > 8 methods (so max class size is 80 LOC)

5. Methods can't use more than one feature of another class. (My very basic interpretation of "Feature Envy". Again, TO-DO to improve that. Again, test code may be exempt.)

6. Boolean parameters are not allowed

7. Methods can't have > 3 parameters

8. Methods can't instantiate project types, unless they are factory or builder methods that return an abstract type. (The beginning of my Dependency Inversion "pincer movement". 2 more rules to come preventing invocation of static project methods, and methods that aren't virtual or abstract. Again, factories and builders will be exempt, as well as test code.)

What's been really fun about the last couple of weeks has been eating my own dog food. As each new rule emerges, I've been applying it frequently to my own code. I'm a great believer in the power of Continuous Inspection, and this has been a timely reminder of just how powerful it can be.

Red-Green-INSPECT-Refactor


After passing every test, and performing every refactoring, I run a code analysis that will eventually systematically check all my code for 15 or so issues. I fix any problems it raises there and then. I don't commit or push code that fails code analysis.



In Continuous Inspection, this is the equivalent of all my tests being green. Of course, as with functional tests, the resulting code quality may only be as good as the code quality tests. And I'm refining them with more and more examples, and applying them to real code to see what designs they encourage. So far, not so shabby.

And for those inevitable occasions when blindly obeying the design rules would make our code worse, the tool will have a mechanism for opting out of a rule. (Probably a custom attribute that you can apply to classes and fields and methods etc, specifying which rule you're breaking and - most importantly - documenting why. Again, a TO-DO.) In the Driving Test, I'm thinking candidates will get 3 such "hall passes".

If you want to see the work so far, and try it out for yourself, the source code's at https://github.com/jasongorman/CodeCraft.FxCop

And I've made a handful more tickets available for the trial Code Craft "Driving Test" for C# developers on Sept 16th. It's free this time, in exchange for your adventerous and forgiving participation in this business experiment :)

Powered by Eventbrite






August 9, 2017

Learn TDD with Codemanship

Clean Code isn't a Programming Luxury. It's a Business Necessity

I'm not going to call out the tweeter, to spare their blushes, but today I saw one of those regular tweets denigrating the business value of "clean code".

This is an all-too-common sentiment I see being expressed at all levels in our industry. Clean Code is a luxury. A nice-to-have. It's just prima donna programmers making their code pretty. Etc etc.

Nothing could be further from the truth. Just from direct personal experience, I've seen several major businesses brought to their knees by their inability to adapt and evolve their software.

There was the financial services company who struggled for nearly a year to produce a stable release of the new features their sales people desperately needed.

There was the mobile software giant who was burning $100 million a year just fixing bugs while the competition was racing ahead.

There was the online recruitment behemoth who rewrote their entire platform multiple times from scratch because the cost of changing it became too great. Every. Single. Time.

I see time and time again businesses being held back by delays to software releases. In an information economy - which is what we now find ourselves in (up to our necks) - the ability to change software and systems is a fundamental factor in a business's ability to compete.

Far from being a luxury, Clean Code - code that's easy to change - is a basic necessity. It is to the Information Age what coal was to the Industrial Age.

No FTSE500 CEO these days can hatch a plan to change their business that doesn't involve someone somewhere changing software. And the lack of responsiveness from IT is routinely cited as a major limiting factor on how their business performs.

Code craft is not about making our code pretty. It's about delivering value today without blocking more value tomorrow. It's that simple.