Showing posts with label value. Show all posts
Showing posts with label value. Show all posts

Monday, November 7, 2016

Listen to and Address the Concerns

If there is resistance to change, there may be good reasons for it. The way things are currently done have reasons embedded in them, even if those reasons are not immediately discernible.

When proposing a new way forward, the best thing I've found to do is to ask what the concerns will be with the new approach. At that point, a discussion can be had.

In the case of our proposed automation of testing deployments, the DBA's concern was around the state of the databases. Presently, changes in the Development environment can come from anyone. But by deploying to test manually, the DBA can see what's happening in that space. That way there are no surprises in Acceptance.

So if we are going to automate, that's the concern we need to address. If the DBA would be happy to get involved during the development - either writing the scripts or code reviewing the written scripts - then the concern is assuaged.

It would have been problematic to go ahead without getting the relevant stakeholders on board. It's far better to have them as part of the decision and the process. So to do that, listen to them.

Friday, November 4, 2016

Faster Horses

"If I had asked people what they wanted, they would have said faster horses." - Henry Ford


Collaboration is a tricky business. On the one hand, we need to deliver what the customer wants. On the other, the customer may not know what they want until they see it.

As agile developers, we are meant to deliver value to the customer. Sometimes that's going to be by doing what they want. At other times, it's going to be anticipating it.

The lean value of seeing the whole is vital to adopt. If the development team understand the domain, it gives them the opportunity to see things the customer doesn't. That it turn leads to a higher value product.

This is why collaboration is so important. It allows early and frequent feedback on what features are being delivered. This takes away the surprise element, as well as giving the opportunity for collaboration.

Development over time involves a deep immersion in a problem space. Ideas will spring up as the problem space is explored, and a good agile team should be ready to respond when this happens.

Wednesday, November 2, 2016

Bad Unit Tests are Worse than no Unit Tests

Unit tests represent our best intentions as developers. They are non-functional code that take time and effort to write and maintain. But what they give us is confidence in the quality of the code, and confidence that modifying code won't break existing functionality.

Poorly written unit tests can make developers forget their best intentions. If unit tests are poorly written, involve heavy mocking, or are tightly coupled with the implementation, unit tests become an impediment.

Because effort has to go into understanding those tests, and the tests are divorced from their original context, it's understandable developers will choose to sacrifice the test rather than the time for maintaining it.

Because of the role unit tests play, it's 5 best to avoid this situation. This means spending time writing good unit tests and testable code.

Good unit tests are decoupled from the solution. They are functional without being prescriptive as to the details. It's not about making sure every line of code is covered, but making sure the code does what is expected.

To achieve good unit tests, it requires writing testable code. Unit tests shouldn't be an afterthought, but part of the development. If heavy mocking is required, that's a sign the code needs refactoring. If it's hard to see how unit tests could be made to test the code, that's another sign.

Unit tests are like any other aspect of a codebase. At all times, we are writing to be understood long after we have left the project. This is just as true for code where other developers come in cold, or even ourselves once we have context switched away from the problem at hand.

Tuesday, November 1, 2016

Pilot Technical Ideas in Sprints

Every fortnight, all the technical people in our section meet for a forum - our chance to bring up any technical issues or things we've learnt that might be of interest to others. This has mixed results, but occasionally it throws up a good idea that the team can pursue.

The general problem with ideas is how easily they can be argued for or against. Of they were implemented, on the other hand, their merit is demonstrable.

Therein lies the difficulty for a scrum team. There's always things that could be potentially of value, but they have to go up against that time being used for something else. The forum becomes an exercise in implicit permission - we put the idea forward for quality control.

If the idea has tacit merit and implicit consent, then it's something that can be put forward as part of the development. Since sprints are about providing business value, the idea should in some way contribute to business value.

One example floating around at the moment is moving to a microservice architecture. We have our reasons for doing this, but it will still take time to set up and deliver. But doing it as part of a particular user story means we can realise that change and assess its merits. It serves the business, as well as allowing for the developers to try out better ways of delivery.

Monday, October 31, 2016

Having One Big Target

I've been in sprints where there are lots of little things to be done, as well as sprints where there's just one thing that has to happen. My experience is having one big target is much better than lots of little targets.

The reason, I think, is that one big target lacks the context switching that going from target to target. It allows all people to focus on one problem and gradually work to that.

A big target is not an ill-defined target. The same rules apply as apply in all scrum - it should be coherent enough that it can be worked on. Anything less and a big target has a chance of failure.

A big target should still be broken down to small targets. But the package of targets together provides a context to the work. A package of disparate targets has their own context, with the developers needing to adopt that mindset to begin work. Smaller tasks for a greater whole do not have that problem.

Thursday, October 27, 2016

The Utility of a WIP Limit

One of the advantages of using a Kanban board for tracking scrum is that it identify bottlenecks in the process. The Kanban board has an interesting way to stop this - putting a limit on the amount of tickets that can be in a column at any given time.

Putting a WIP limit prevents too much work piling up. The team ought to be doing what it can to keep the flow going smoothly. It helps eliminate bottlenecks by preventing issues from piling up.

It also serves as a reminder to the team of collective commitment. That we are all in it together, and blockers affect everyone. Tickets stuck in analysis, development, or testing all have the same outcome - that feature doesn't get out. And given business value determines ranking order, the tickets in WIP are more valuable than tickets that are on the backlog.

Wednesday, October 26, 2016

Whatever Tools for the Job

When I was a child, I was amazed at just how many tools were in my grandfather's workshop. I didn't even know what most of the tools did, let one why there would be so many.

My toolkit is virtual rather than physical. Like the craftsman, knowing which tool is right for the job and how to use it effectively is vital.

One recent task I had to do was to query our database and get some intelligible information from it. To do this, I used a combination of SQL Developer and Excel, taking advantage of features in both to perform the task. A DBA may have been able to solve it purely in SQL (just as I'd easily be able to solve it with a targeted Java function), but the combination of tools worked for me. I used SQL Developer and Excel for what each was good at doing.

Knowing multiple ways to solve a problem gives flexibility when issues arise. Sometimes a spreadsheet or even Notepad are the right tools for the job in the right circumstances.

Tuesday, October 25, 2016

The Nature of Agile Testing

"The focus of agile development is producing high-quality software in a time frame that maximizes its value to the business. This is the job of the whole team, not just testers or designated quality assurance professionals. Everyone on an agile team gets “test-infected.” Tests, from the unit level on up, drive the coding, help the team learn how the application should work, and let us know when we’re “done” with a task or story. An agile team must possess all the skills needed to produce quality code that delivers the features required by the organization. While this might mean including specialists on the team, such as expert testers, it doesn’t limit particular tasks to particular team members. Any task might be completed by any team member, or a pair of team members. This means that the team takes responsibility for all kinds of testing tasks, such as automating tests and manual exploratory testing. It also means that the whole team thinks constantly about designing code for testability." [Crispin, L. and Gregory, J., Agile Testing, p.15]

Friday, October 21, 2016

Dude's Law: Value = Why / How

The one of the consequences of agile development is the focus on a minimum viable product. The product owner sets the work by business value, so the user stories with the highest value are always worked on first.

The business need for a user story (or the amount of work done on a user story) does depend on the ability for the development team to deliver that story. A really complex piece of work might be the best thing from the business perspective, but is it more important than multiple smaller tickets? This is where Dude's Law comes in.
Dude's Law: Value = Why / How

If something takes a lot of effort, that's effort that could be expended on something else. So if a user story is going to take a lot of effort, it's value ought to be weighed up against what alternatives could be done instead.

The inverse holds for where the how is minimal. Changes that are trivial to implement can high value even if they are not priorities from a business perspective. But a user story that's difficult to implement and of low business importance holds very little value.

Applying Dude's Law gives a way to quantify what tasks ought to be achieved in a sprint. Like everything, the code should be written such that if the project were to be shut down tomorrow, as much business value as possible should have been added until that point.

Wednesday, October 19, 2016

The Value of Values

The most attractive thing about any agile methodology is that the processes are am embodiment of values. What makes agile agile is the ability to change those processes if and when doing is what's best for the project.

Scrum, XP, and Lean all have their own ways of doing things - but the adoption of those practices doesn't embody agility.

For example, we are using the scrum methodology. This means designated sprints, daily stand-ups, planning, and retrospectives. But these aren't what makes us agile. It's the Scrum values - commitment, openness, courage, respect, and focus - that makes us agile.

The values that the different agile methodologies hold are also able to be utilised without adoption of the practices. The idea of seeing the whole is a value of lean, but it's just as useful a value to hold to while doing scrum.

The advantage of values is being able to respond and change to difficult situations without falling back on the process. Values are our metric by which change is guided and assessed. They are the why of the processes that allow us to know what those processes are for.

Processes without the values can be followed and confer the same advantages as a team who have internalised the values. But knowing the processes without the values makes it harder to realise those advantages when the processes become burdensome or sub-optimal. An agile team has the ability to better utilise the processes than one who follow the processes without the values guiding them.

Monday, October 17, 2016

Programmatic vs Functional Testing

From a testing perspective, it makes no difference how a programmatic solution is implemented if the functionality remains the same. What matters is how the system behaves, and not what goes into that behaviour.

Functional testing ought to treat the system as a black box. This decouples the testing suite from the solution, allowing testers to focus on the quality of the software rather than getting bogged down in the details of how the software works.

This also gives the programmers the freedom to refactor the solution without  causing extra rework on the testing suite.

The question, always, is what value does it provide? The cost of testing the programmatic details not only has the time expense of the testing, but the additional cost of not focusing that effort elsewhere.

Thursday, October 13, 2016

Identifying and Eliminating Bottlenecks

"Don't be irreplaceable, if you can't be replaced, you can't be promoted." (from Dilbert's Laws of Work)

The easiest way to identify a bottleneck is to see what happens when time is a factor. If someone (or something) is critical to an operation, then things don't happen. That is obviously a less-than-ideal way to find where a bottleneck is.

Bottlenecks usually present themselves long before a crisis, but aren't seen as critical at the time. They are usually things that only occasionally matter, so general availability is usually enough.

Unusual situations aren't unavoidable situations. Taking steps to eliminate the bottleneck is sensible risk management. It is much better than the alternatives, such as cancelling leave or letting deadlines slip.

For those bottlenecks that are part of everyday development, they should be mitigated and eliminated as quickly as possible. In our team, only a few people had the ability to do deploys. This was liveable until those people went on leave. So we implemented automated deploys from Jenkins so that would never be a problem again.

Wednesday, October 12, 2016

Purposes of Unit Testing

  1. As a development process
    Test-driven development is a useful skill to learn. It encourages a clean design, as writing unit tests for messy design is both painful to write and painful to maintain. It also gives a target to code against, by setting what what the function ought to achieve before the function is even written.

  2. Proving the code behaves correctly
    Writing unit tests is the simplest way to show that code does what it is meant to do. Unit tests allow easy checking of boundary conditions, to ensure that the function behaves as expected.

  3. Demonstrating robustness
    In complex systems, well-written unit tests demonstrate that functions behave as expected. As more features are added, or as code is reused, unit tests demonstrate that these changes do not affect the existing functionality. Conversely, if unit tests easily brake when code changes, it's a good indicator of fragility.

  4. Testing
    Some tests algorithms are better for than humans. When testing a function involves a large amount of data, unit tests are best equipped for this job. This is also true for time-dependent functions, or testing algorithms.

  5. Refactoring
    Unit tests provide the assurance needed that refactoring the codebase hasn't accidentally changed functionality. Without unit tests, refactoring is fraught with risk.

Tuesday, October 11, 2016

Chickens and Pigs

A Pig and a Chicken are walking down the road.
The Chicken says: "Hey Pig, I was thinking we should open a restaurant!"
Pig replies: "Hm, maybe, what would we call it?"
The Chicken responds: "How about 'ham-n-eggs'?"
The Pig thinks for a moment and says: "No thanks. I'd be committed, but you'd only be involved."
Most people who are involved in a project are not committed. They are chickens. And while they make decisions that affect the project, they are not committed in the same way as the development team are.

The development team are the ones who are responsible for what is delivered. They are pigs. Their actions directly affect the project.

A chicken making decisions on behalf of the pigs can adversely affect the team's ability to do their job. As the chicken has no skin in the game, their decisions are divorced from the consequences.

A pig who acts like a chicken is also problematic. If they are not committed to delivery, their involvement detracts from the team's collective ability to deliver.

Thursday, October 6, 2016

When Algorithms Test

Code needs to be tested. Sometimes that testing is best done by an algorithm.

We recently had a user story that involved removing particular characters from the application number string. The purpose was to address a readability issues - at a glance certain characters and numbers are indistinguishable, so removing the offending characters from the string they were generated from. A simple enough coding exercise.

This card, however, sat in the testing column for a long while. It didn't need to, as we had built a unit test that did what a regular tester would do - throw lots of data at the generation and see whether those offending characters were present.

An automated test, in this case, could do what a human could not: quickly generate and accurately assess the functionality. It's checked 1000 times every time the code is compiled - overkill as far as what's needed to be tested, but that overkill is computationally negligible.

Writing the unit test first (TDD) gives the developer the target to aim for, as well as creating the before and after test artefacts. At the very least, the unit tests results could supplement the functional spot-checking that would constitute normal testing for such a story.

Writing code that verifies functionality is not simply for helping developers to write better code, but can be the best tool at the disposal of the testers for doing testing. It's leveraging technology at tasks it excels, which is what we ought to be using technology for.

Wednesday, October 5, 2016

Book Recommendation: The Nature of Software Development

Development has more than enough to keep anyone occupied on immediate concerns. But it's worth standing back in order to reflect on what it is we are doing.

The Nature of Software Development by Ron Jeffries can best be seen as an expansion on the agile manifesto. Like the manifesto, it's high level but gets right to the point. Like the manifesto, it's concise but profound. And like the manifesto, the aim is to identify what makes for successlooks like.

What we are doing when building software is trying to add value. The word can mean different things in different contexts, but in this case it is a strength rather than a weakness.

We build software because the software will serve a purpose. We should focus on delivering that which serves that purpose, and not waste time on features that are superfluous to that.

We should develop such that there will be value if the project winds up tomorrow. The code should always be ready to deploy. We should fix problems as we go along because that makes development quicker in the long run.

There's much more to the book than I'll cover here. It's a short book, and conversational in tone, and that fits with the message the cook conveys. Deliver what adds value, and don't waste time with filler that doesn't. This book is very valuable.

Tuesday, October 4, 2016

90% of Development is People

When I started out in software development, my biggest concern was my lack of technical ability. Each annual review I flagged technical proficiency as an area of improvement.

After about 5 years and a few projects, I was put on an assignment with absurd deadlines on a different technology stack. This forced me to talk to people more about what I was doing. This was a gestalt moment for me, as it forced me to see software development in a new light.

Raw technical proficiency has its place, and some jobs require it - 3D engine programmers, for example. But for the enterprise work I do, soft skills matter.

The ability to negotiate matters because ideas are seldom unambiguous. It also matters in navigating what can be achieved in the face of unrealistic expectations.

The ability to foster trust matters because it's essential for team cohesion and fostering working relations.

Being able to effectively communicate matters because if we can't express ourselves to others, then we can't get our ideas across.

Being able to listen matters because others need to be able to get their ideas across to us.

And being able to put all that together matters because effective collaboration requires all those skills. A developer who can collaborate is in a far better position than one where those skills are lacking.

Monday, October 3, 2016

Shuhari: first learn, then detach, and finally transcend

From Wikipedia:
  • shu (守) "protect", "obey" — traditional wisdom — learning fundamentals, techniques, heuristics, proverbs
  • ha (破) "detach", "digress" — breaking with tradition — detachment from the illusions of self
  • ri (離) "leave", "separate" — transcendence — there are no techniques or proverbs, all moves are natural, becoming one with spirit alone without clinging to forms; transcending the physical
When we learn something new, the accumulated wisdom of those who came before is the best place to start. We follow what they say because they know what they are talking about. This is shu.

As we progress, we are able to identify where the rules work for us and where they don't. We are in a position to know the difference between what works and what doesn't, so breaking the rules gives us valuable feedback. This is ha.

Finally we are in a position where the rules no longer matter. We have developed through experience practices that serve us well, as well as learnt many bad practices to avoid. This is ri.

Friday, September 30, 2016

Kinds of Technical Debt

I think there are three main ways technical debt accumulates. They are:
  1. Debt by negligence
    This is the everyday accumulation of technical debt in a project. It's the little things that can really add up over time. Examples of this include...
    • Leaving code in giant indecipherable methods.
    • Not giving variables meaningful names.
    • Bloating an existing class.
    • Leaving in commented out code.
    • Not giving meaningful commit messages.
    • Failing to write or update unit tests.
    All of these are entirely avoidable if a programming team is taking care with what they do. Unless the code is finalised, and the system works so well that no maintenance is ever needed, these practices will hurt the project later on.

  2. Debt by constraints
    The best of intentions and due diligence among the developers won't matter if there's too much being asked of them. Examples of this include...
    • The amount of work cannot be achieved in the time allotted.
    • The developers with the wrong skill-set are assigned to the project.
    • Interference in the process from management.
    • The technology stack is less than optimal for the solution.
    • The requirements repeatedly shift.
    These debts are often the most easy to recognise, but the most lamented by developers. It can be an excuse for why a system ends up a fragile kludge, but not an excuse for throwing away good practices.

  3. Debt by investment
    There is the very rare occasion that taking on technical debt is the wise decision. Examples of this include...
    • Responding to an urgent deadline.
    • Getting a prototype up and running quickly.
    In these cases, the technical debt should be acknowledged and paid down as soon as possible.

Not all technical debt is bad, and some kinds of technical debt are more or less benign in the scheme of things, but it's worth recognising what factors lead to technical debt, so that the decision to address it can be a informed and deliberate one.

Sometimes we should know better, sometimes we can't do anything about it, and sometimes it's worth it.

Monday, September 26, 2016

Following the Boy Scout Rule

"Always leave the campground cleaner than you found it."

In all my years as a software developer, the only times I've ever gotten to start from scratch is when I've worked on personal projects. And even then, starting from scratch is a last resort.

My experience of being a programmer is working in someone else's architecture. I get to expand it out, fix it up, and sometimes refactor it away. And each time I end up having the same question - why is it built that way? And each time there's the same answer - it's because the code needed to be delivered quickly.

It feels at times that all we can do as programmers is try not to make things worse. One thing I've done is tried to fit in with the existing way of doing things. That way the code is consistent for those who maintain it in the future. But it doesn't solve the problem, merely prevents it from getting any worse.

The answer is meant to be refactoring, though it's really not an answer for fragile code. It's a sad irony that the code in most need of refactoring is the code least able to be refactored...

Any complex system is going to seem impenetrable at first glance, but there are ways to improve it. A system doesn't need to be overhauled to be fixed, and something as simple as tidying up the code that's being worked on is enough to make things better.

For this project, we have pretty abysmal unit testing. So one rule we've set for ourselves is to put unit tests in wherever we find ourselves enhancing the code. Coverage is still woeful, but it is less woeful than it was a month ago. Another thing is to make sure no commit has commented-out code.

Code doesn't get to a messy state by a single act, nor can it be fixed in one. The complex mess that is the average codebase (at least average from my experience) is the way it is because of a long path to that state. Making things better is a similarly long path, but thankfully one that be addressed as part of enhancing a system. Fragility is quantitative, not qualitative.