Friday, 27 June 2025

Solving problems a step at a time

Problem solving is fundamental to all the work we do, but it’s not a skill that’s taught or talked about explicitly all that much. This can be a major barrier for people in their day to day work, and also in their career development. I want to address that a little by talking through some classes of problem, and problem solving techniques and strategies.


Formal problem solving

The term “problem solving” has two distinct uses in IT. When we’re talking from a computer science point of view, we consider “problem solving” to be a question of identifying an algorithm to solve a given problem. There is a huge amount of material from both mathematics and computer science about this side of problem solving.

HINT - if this is the kind of problem you have, AI/Google/Design Patterns will provide you with a good answer. “go get a predefined answer from the GoF book” is a heuristic, which we’ll talk about in a minute.

The most important thing to know about an algorithmic problem is the size or complexity of your problem, and hence how long it might take to solve.

Size and Complexity of problems are a factor of the number of possible permutations - if you need to perform an operation on every one of 10 elements, that won’t take long. Every one of 10**100 will take… quite a bit longer.

There’s a famous problem in computer science called the ‘Travelling Salesman Problem’:

Given a list of cities and the distances between each pair of cities, what is the shortest possible route that visits each city exactly once and returns to the origin city?

In simplistic terms The Travelling Salesman Problem can’t be solved without (figuratively at least) trying every permutation - there are no computational shortcuts. It’s classified as ‘NP-Hard’, and we see many variants of it in e.g. iterating over sets.

So when choosing how to implement program logic, always think about the size of your data sets and whether your chosen approach will work with the amount of data you’re likely to see, especially with nested loops.

Heuristics

In problem solving terms, a heuristic is a ‘near enough’ approach. Most of the time it works, but it’s not guaranteed to work. Design patterns are a kind of heuristic - they’re a one-size solution to various common problems. You might need to tweak the detail of a design pattern for your individual use case, but the broad approach is probably right. Similarly, “switch it off and on again” is a heuristic for a lot of problems where finding and fixing the true cause is hard or impossible to find and not really necessary to overcome the immediate problem.

That’s as much as I’m going to say about formal problem solving because it’s not really what we’re here for. It’s useful to have a bit of background knowledge of it as we move into troubleshooting..


Troubleshooting

The ‘other’ kind of problem solving is sometimes known as trouble shooting. This is approaching a novel real world problem needing to find a resolution. If you google ‘trouble shooting’ you’ll find a number of variants of:

  1. Gather Information

  2. Describe the problem

  3. Identify probable cause

  4. Create a plan

  5. Test the plan

  6. Analyse the result

  7. Document the process.

All of these are much easier to say than to do. Gather which information? Identify the cause how? They’re good sensible steps but they assume too much.

So, things that you can do to identify and solve a novel problem:

Heuristics

We talked about heuristics in the previous section, but if anything they’re more applicable here. Have you seen this kind of problem or something similar before? What worked on that occasion? Watch out! It can be really easy to convince yourself that you’re seeing exactly the same problem - be on guard against heuristics pushing you in a particular direction. It’s really easy to think that it “must” be the same problem you saw once before, and that can trap you in a blind alley. Very often experience of similar symptoms can be an indicator and may enable you to find a quick solution, just remember to keep checking whether you’re spending too much time on a single approach.

Break it down

The absolute number one strategy for solving problems. Most of the time the problem is difficult to solve because there are too many variables. So… eliminate some. Simplify the situation by isolating the place where the problem occurs. Break the failing process down into pieces and test each one in turn until you find where the problem lies.

It’s often productive to eliminate parts of the system from each end until you converge on the problematic section.

Draw it out

It’s useful to draw the system you’re working on as a diagram. This is especially useful for seeing where the boundaries are so you can break the problem down into smaller chunks.

The truth is out there

One of the most fundamental problem solving tools is the “truth table”. This is just a table that details the state of your problem as variables change. For example:

Program runs when


So you can see from the truth table that the only circumstances when the program runs is when the computer is switched on, node is installed, and the computer is not on fire…

Read around the problem

The more information you have about the problem domain, the more likely it is that you’ll understand what’s going on. It’s really easy to solve problems in something you understand really well, but much harder with something you have less knowledge of.

Watch out! You can spend days digging through documentation and getting nowhere. Don’t make this your first step - learn something about the symptoms before you start researching.

Two heads are better than one

Find someone to talk through the problem with. It doesn’t necessarily have to be someone more experienced, and you’re not necessarily asking them to come up with a solution. But simply expressing the problem in words will often force you to think about it in a systematic way and lead you to the solution.
See also Rubber Ducking

Minimal Test Case

This is the big hitter of problem solving. It’s the same approach as Break it down from the opposite direction - build the most minimal model you can of the problem that still displays the same behaviour. This is an approach often used for bug reports with public APIs etc: creating the most minimal case you can will often tell you exactly where the problem lies. Hint: write it using a test framework if you can.

While it’s primarily a software technique, nothing prevents you from creating minimal test cases in other classes of problem. 

Breadth of knowledge

This is Read around the problem but pre-emptively. If you have a broad range of knowledge of tech, very often things you’ve learned in other contexts will help you to solve the problem. The number one topic of background knowledge that will help you is networks. Understanding how applications talk to servers - the network protocols, infrastructure and addressing standards they use is the most valuable non-dev tech skill you can have.

Number two is Testing. Understanding test techniques and frameworks will help you to build minimal test cases and break your problem down.

Practice makes perfect

Just solving problems is good practice for solving other problems. There’s nothing quite like experience to help you get better at it. Even just solving logic puzzles can help you develop problem solving skills.

AI

Problem solving is something AI is really quite bad at. It’s great for finding possibly related information, but you’ll need to review and compare those cases with your own example. Think of it as a tool for “reading round the problem” or “rubber ducking” rather than a problem solving approach in it’s own right.

Staying calm

Very often problems crop up under difficult circumstances. We’re often called on to solve problems under time pressure, or with direct impact on end users, or more often both. There can be pressure from clients to find a solution, and when a problem is high impact sometimes senior stakeholders will make their presence felt.
Stay calm. Rushing to fix will cloud your judgement and often lead to mistakes that can make the whole situation worse. Sometimes much worse. Writing down what you need to do next can help, work slowly through things that could go wrong, and if possible get someone else to check you as you go along. If there’s someone who can keep the stakeholders at arms length while you work, get them involved too.

Take a break

The biggest danger in troubleshooting is getting yourself stuck in a blind alley. You can spend too much time pursuing one particular approach and convincing yourself it “has” to be a particular cause. Then once you finally get a solution you’ll beat yourself up for not realising sooner. Keep stepping away from the problem every once in a while to get some perspective. Maybe ask someone. If you’re really really stuck, go for a walk - getting some space and relaxing a little will often help.

Putting it all together

The trick to effective problem solving is to use the right combination of techniques. In some cases it may be that the best way to solve the problem is to create a minimal test case, but a heuristic approach might shortcut that and get us to a solution quickly. A typical problem might involve:

  • Use your experience to try out a few possible solutions (heuristics), but don’t spend too long on this approach.

  • Break down the problem to try to isolate where it’s happening.

  • Talk the problem through with someone.

  • They might have heuristics to try, so try those.

  • Break the problem down further, try to isolate the exact cause and maybe create a minimal test case.

  • Do some reading based on your minimal test case.

  • Step away and take a break, then come back fresh

  • Evaluate your progress and see if you need to change tack

You don’t necessarily need to do all these steps or in this order but these will be the kinds of steps that lead you where you need to go.

Above all, don’t panic! If you can’t fix it, you can always find someone to help.


Next Steps

Systems thinking

I’ve used the term “system” quite a few times in this article, to mean a set of elements functioning together. “Systems thinking” is the approach to problems that looks at how components combine and interface. It’s a great step towards more advanced problem solving techniques.

Thursday, 4 November 2021

Should I adjust story points when work is carried over to the next sprint? NO.

 Why adjusting story points in carried-over stories is bad practice:


1) the backlog is a historical record of the work done, and the estimates that were made. Adjusting the story points down makes it look on the record as if the team had underestimated the story

2) Velocity is a representation of how much work the team get through on average. By adjusting the story points you are effectively making work disappear. Velocity is an approximate figure, one should never look at velocity within a single sprint as meaningful, it’s the average velocity over a number of sprints that gives an indicator of how much work to bring in.

3) Story points are a tool for the team to facilitate estimation, nothing more.

By taking points out of a story you are reducing the apparent average velocity of the team and making the reporting incorrect over time. It may make the burndown chart look better in an individual sprint, but the long term effects on reporting are harmful. The sprint burndown chart is no business of anyone outside the team anyway.

Monday, 21 December 2020

The Agile Testing Paradox - reconciling manual testing with agile methodology

There's one difficult question that keeps coming up in scrum teams, and it never seems to go away. How do you complete all the PBIs in a sprint without having devs idle while the last bit of testing is done?

Scrum doesn't have any concept of a tester being separate from a dev - there is no separate tester role. This is partly to keep the framework simple, but also partly because (like a lot of software development thinking from the early 21st Century) it has roots in the open source movement where there are no strictly defined roles (beyond arguably the PO). That's a topic for another day, for the moment I'm interested in inefficient sprints, bored devs and frustrated testers.

The problem looks like this:


At the beginning of the sprint, the testers have nothing to do. At the end of the sprint, the devs have nothing to do.


There are dozens of suggested solutions to this out there, and they mostly talk about doing lots of little things to improve the situation. Testers can be preparing test cases at the beginning of the sprint, devs can be doing non-testable infrastructure work at the end. There are a couple of good posts dealing with this here:




That second one caught my eye: 'Manual testing in scrum is hard, but not impossible'. That's a massive alarm bell. Development processes shouldn't be hard, that just discourages people and stops development being fun. If a process is hard, people won't do it, and they certainly won't do it consistently in the future. Eliminate obstacles, don't build a staircase over them.

One of the commonest things that's advocated to address this problem is to make your PBIs smaller. While that's worthwhile anyway, and it can help a bit, it still doesn't fix the problem. Even a PBI that takes 3 hours to develop and an hour to test still leaves slack time at each end, and requires a lot of extra effort on the part of the team to break down & refine**.

There are a couple of simple ways you can reconcile manual testing with scrum without making it painful, I'm going to talk about two of them:

Simultaneous Testing

In theory a PBI follows a linear path like this:


In practice it usually looks a lot more like this:



Code is written, committed, tested and bugs are found. Once that cycle is complete it's merged, and quite frequently more bugs are found (usually when it gets migrated into another environment).

Each of those transitions from 'Write code' through to 'test' takes time. Tickets move around the Jira board,  people look for something ready to work on, and very often a tester won't actually start work on a PBI until it's formally moved into a 'testing' column on the sprint backlog. What might work better is to have the tester picking up in progress work. We talk about 'commit early and often' - what's to stop a tester reading the commit message, working out what can be tinkered with and starting to test it? Yes, it's not finished, but bugs can still be found, and if we're going to have that cycle back and forth between the dev and the tester anyway, why not do it without the overhead.

This approach means stopping thinking about PBIs as 'done, then tested' and making the process more iterative and collaborative. But that's exactly what agile is all about - having that 'dev, then test' approach looks a lot like mini waterfall.

Test the increment

Testing a PBI against requirements and marking it as 'OK' in sprint has one massive problem - you're still changing the code. We all work hard to make code modular and loosely coupled, but the nature of sprint goals, epics and business requirements means that we're generally working in the same approximate area of code throughout the sprint. So you complete a PBI, the tester signs it off, and 5 minutes later someone commits a change that breaks it. The tester then tests the functionality they've changed, and a regression set that may not test your change, and a broken increment comes out of the end of the sprint.



Testing the increment means separating formal testing from the development process and making it a QA process instead. Normally you're going to want to reflect that in the organisational structure, which helps to make the testers independent again. You can still have strong relationships between testers and devs - that "is it supposed to do this?" conversation still needs to happen.

But if the code isn't formally tested, how do we know it's right? Good automated testing skills are part of a devs toolkit, it's as important as writing the code.

Testing the change is the developers job. The testers job is validating the product.

The big drawback that gets raised to 'testing the increment' is that it slows down fixing of bugs, because the bug doesn't get tested until the sprint after it's fixed. While that's kind of true, sometimes, that increment is also stable so the risk of other bugs being introduced is less, and nothing stops you sidestepping the system for an emergency fix. In any case, very often you find bugs well after a change has been merged anyway.

Conclusion

Testing the increment is my preferred approach - I think there are still massive inefficiencies in the simultaneous testing method, and it's probably not enough on it's own to fix the problem. Testing the increment is a significant change in approach, but it separates the workflows and gives you more confidence that the increment is OK.

So if you're running into this problem with slack time in sprints and testing is getting pushed into the last couple of days, it might be worth experimenting with one of these approaches to see if that makes your process smoother.




** there's also a tension between breaking things down into the smallest components you can, and what actually counts as a user story. It's pretty hard to say 'as a user, I want the small piece of prep work that combined with six other things will enable me to....'.


Friday, 18 December 2020

Error Patterns - mistakes so common they become a pattern

What's wrong with this pseudo code?

"We need to get all entries for a given date, or today if the date isn't specified"

@controller

EntriesDto getEntries(Date searchDate=Date.now()){}

I made this mistake a couple of times before it properly sank in, and I just ran into it again. If you're still looking at it thinking "nope, can't see a problem", it's the assumption that the consumer and the api are in the same locale. This will work a lot of the time, but around midnight on certain days in certain months the result could be a day earlier than you expect, as daylight saving switches over.

Another daylight saving error I've run into more than once is:

"if we consistently use UTC we don't need to worry about daylight saving".

It's better, but you still do need to think about it. Because although you might be using UTC consistently you can be certain your end user isn't. Somewhere around there will have to be some conversion. I usually try to do that conversion at the view, because obviously, but where you're using some variant of Date.now() in end user client side code (e.g. browser) you're going to run into problems, because the client machine will have a locale setting convenient for the user.

I couldn't see that this class of error has a name, so I'm referring to them as 'Error Patterns', code errors that happen repeatedly in a consistent way.


Saturday, 13 May 2017

Getting into the software development business

A couple of weeks back I spent the day at the Leeds Digital Job Fair. I've been doing a lot of recruitment for the last few months, and been fortunate enough to find a few good developers to join our dev teams.

Hardly a month goes by when I don't get asked "( I | a friend | a colleague ) wants to move into software development from (some totally unrelated field), how should ( I | they ) go about it?". This post aims to consolidate my answers to that question.

Everything that follows is my own opinion. But bear in mind, I (and other devs like me) am the one who decides whether you get an interview or not based on your training & experience.

First of all, be realistic. Yes, there are jobs out there paying big money for good developers. They require experience - lots of experience. You really aren't going to get a 50k GBP job (2017 Northern England rates) based on no experience and a boot camp course.

Speaking of boot camps, there are lots of companies out there doing introductory software development courses of very varied cost and quality. I saw one charging 6k for a syllabus that made no sense to me, and another at half that price that was much more coherent. RESIST THE SALESPEOPLE! Make an informed decision - I'm guessing if you want to get into dev then you're maybe in a lower paid job, so you can't afford to throw money away.

Here's my list of most important pointers:

1. If you regard learning new things as a chore, forget it altogether. You cannot function as a developer without learning new things all the time. If you don't enjoy that, you will hate it.

2. Experience is everything, and you don't have any. So get some: write websites for yourself, friends, clubs, local charities. Look at getting involved in open source projects, maybe do some documentation for them if your coding isn't good enough to contribute code.

3. Don't try and learn everything at once, pick a coherent direction and follow it. I've seen courses promising to teach 'full stack'. IMO learning to be a full stack developer takes time and experience.

Coherent directions might be:
  • Java
  • Javascript, Node.js, Catalyst
  • PHP
  • Python
  • C# and Visual Studio
  • some other language and context
(Every developer needs to know some HTML/CSS, but unless you're a web designer rather than a developer, those skills alone will not be enough.)

4. If you're going to shell out a load of cash on a training course, choose carefully. Ask for advice, assess whether the syllabus looks coherent or will just give you a smattering of widely different topics.

5. There is a lot more to it than just being able to write code. Any jobbing developer has a working knowledge of the following
  • Libraries and frameworks (jQuery, Catalyst, Spring, Hibernate etc etc etc, depends on what they're working on and in what language)
  • Unit testing (and writing code that's easy to test)
  • Agile methodologies (e.g. scrum
  • Algorithms
  • Continuous integration and build tools (Jenkins, maven, teamcity..)

If you can talk sensibly about these things in an interview, I'm going to take you more seriously whether you have commercial experience or not. You can get experience of them by downloading and experimenting with open source code.

6. LEARN AN IDE! It doesn't matter much which one, choose whatever is in widespread use for your language/platform. The important thing is to learn about:
  • the debugger - most languages have one, they allow you to pause the code and see what's happening in real time. You won't realise how important that is until you've done it.
  • code completion - the IDE will give you hints about what to type next, this can save you a lot of time
  • code navigation - moving around a complex project with hundreds of source files is painfully slow without an IDE, and instantaneous with.
  • build tools - the IDE normally has build and run tools built in, this will save you time and also help you to learn the build tools.

OK, so all that was probably a bit intense and daunting. Here's the lighter side:  I've been working in the computer industry now for about 25 years, 15 as a developer. I'm learning new things every day, and having an enormous amount of fun at it. A lot of software development is about financial systems, or ecommerce sites, but software permeates every aspect of life. I've been lucky enough to work in ethically valuable fields for many years, but even before that I contributed to open source projects, including software to make the lives of severely disabled people easier. Writing code can be great fun, and it can be a worthwhile thing to do.




Good luck :)

Friday, 1 July 2016

Key programming books

A top 5 of programming or related topics books I've found most useful:

Pragmatic Programmer
The Mythical Man Month
Perl  Testing, a developers notebook
UML in 24 hours
The Design of Everyday Things


I'll blog details of each one later, in particular 'The Design of Everyday Things' which isn't an obvious 'programming' related book.

Monday, 13 June 2016

Dangerous design flaw in wordpress

Wordpress insists on storing fully qualified URLs all over the place. Especially in the database. This means that if you restore a backup of a wordpress installation onto another machine (a test/dev machine for example), you can unexpectedly end up being switched to the live site at any moment.

Add to this the fact that as previously complained about, the whole thing is stored in the database, so you are logging into a dev machine with the same user account as live, and the potential for catastrophe is huge.