Tuesday, May 17, 2022

Why a bug fix should "always" include new tests

Ok, maybe not always, but please don't start by assuming you're the exception.

(Note that exceptions should come with an adequate, documented explanation.)

So, imagine the scenario: You find something wrong in the code base, so you fix it.

Simple enough and almost certainly a good thing. 

But, consider the bigger goal that we don't just want a codebase with fewer bugs in it we also want a codebase that is easy to maintain, so that future bugs or changes (there will be some) are also easy (and quick) to address.

By adding or changing code without adding tests, we risk making future changes harder/slower.

Going back to the bug you fixed. How was it discovered? I'm going to assume it wasn't because of a failing test.

It was probably found by someone using the code/app/service/whatever or looking at the code. Either way, a manual process.

And how was the change tested? Again, I'm guessing manually.

So what happens when someone has to change something near or related to that code again in the future?

They'll have to test it manually again. But, also, they need to work out (or remember) how to test it manually and work out what all the scenarios they need to test are. Then they have to do that testing in its entirety and without human error. This is unlikely to be fast, thorough, or accurate.

But, also, what if the place where the error in the code was found wasn't the only place that error had been made? Have you really, manually reviewed the entire codebase to look for such an error? How do you know that you really checked *everywhere*? Was that a good use of your time? Additionally, how will you make sure that any future changes to the code don't reintroduce the same bug? Either here or in another part of the codebase? Are you really going to add that to the list of manual checks that are made as part of every code review? I suspect not.

Suddenly, taking the effort to write some automated tests doesn't seem like such a waste of time. Doing so can often be faster than manually retesting something while working on it. Also, having something that checks your code for bad practices, inconsistencies, and anti-patterns is much faster than manually reviewing all but the smallest codebases.

But, what if you don't know how to write tests? Or you don't know how to write a good test for this specific scenario? Well, you find out. Ignorance isn't an excuse.
If working on a codebase as part of a team, ask them. Your whole team wants to work together to create better software and that includes having a codebase that is easy and better for them all to work with.

Maybe I'll write more on getting started with testing or testing difficult things in the future. Don't worry, though; there are a lot of resources about this already on the internet (& elsewhere).

<RantOver />

Saturday, May 07, 2022

Why some things never get better

So, imagine you're dealing with a technical problem. 

There's no specific tooling to help with your scenario.

You can muddle through but everything feels harder than you'd like. 

There are a few simple tools or features that would make this much easier. They'd handle the need to do complicated things manually and avoid errors that are easily made when doing things manually.

But, this thing you thought was going to be easy has turned out to be harder and more time-consuming than you had planned for.

You're now frustrated and behind. 

You just need to get this done and move onto the next thing.

You can't justify the time to work on tooling as well as solving the problem immediately in front of you.

The whole thing has become so frustrating that you just want to get it fixed so you can move onto the next task and not have to think about it again.

You certainly don't want to spend more time thinking deeply about the issue. As would be needed if building a tool to help with it.

So you move on to the next thing.

Maybe, you think, you'll come back to this once the initial pain has passed and work on the tooling that will be useful for yourself in the future and for other people too.

But you're busy.

Other things have a higher priority. Plus, you can't fully remember the pain you felt previously. Maybe it wasn't that bad. Maybe someone else will have made something to help when you have to work on something similar in the future.

And so you don't create that tool.

Sometimes things only get better when you take it upon yourself to deal with extra pain so that others don't have to.

Sadly, I'm not able to handle as much of that extra pain or as frequently as I'd like. :(


Thursday, April 14, 2022

There are two types of developers

There are two types of developers:

  • Those who test their code before checking it in.
  • Those who check in code and rely on automated checks as part of a PR to do the testing.

(and possibly others, but beyond this discussion.)

I'm not going to argue that one is wrong and one is right. 

What I do think is important to remember is that if you have a team that contains a mixture of the two types they (you?) need to be aware of how they are likely to think about each other and there is the possibility of conflict because of this.

Those who test before committing their changes think of themselves as being thorough. They may think that those who don't do the same are not as concerned about the quality of the code and the product it is part of. They may also think that others don't think testing is important or is something that other people can deal with.

People who rely on automated checks to do all the work, may think that those who don't do the same are not being efficient with their time. In fact, they may think that those who do run all the tests before committing their work are wasting their time, and ultimately providing less value to the team as they spend time running tests rather than writing code.

The takeaway here is to know who in your team fits into the two types. Where you have people with different ideas on this topic, acknowledge, accept, and appreciate the differences. Having everyone in a team think the same way isn't a good thing. Appreciate differences. Recognize that different doesn't mean wrong. Instead, focus on how everyone contributes and brings unique value.

Tuesday, March 15, 2022

How you should be using (and naming) resources in XAML

... because a lot of people get it wrong!

We'll get to XAML shortly, but let's start by looking at some C# code:

It seems like a reasonable method, with an appropriate name. Doesn't it?
The name of the function clearly explains what the code does. That's a good thing. Right?

Imagine that the above was created to add a tax to a price. (This is a simplified example where tax is always the same and you can ignore the complexities of tax in the real world.) Now, is the function well named?

Think about where this method might be called from.
Will it always be evident to someone looking at the code why 20% is added to a price?
What if there were other reasons in the codebase to add 20% to a value. What's to stop them from using this function in those places too?

I asked if the above method was well named because it describes what the code does? Actually, this is a lousy way to name something.

The name should indicate the intent behind the code and suggest why it does what it does. We don't need the name to tell us what the code does. We want it to tell us what it is for. This means the name doesn't need to change when the code changes, and it clearly indicates where and why it should be used.

If we have the AddTwentyPercent method in our codebase and it is used for something other than calculating tax, what happens when the percentage for sales tax changes?

If we only change the contents of the function, we end up with something whose name does not describe what it does. Not only does it not describe it, but it also does something different. Something that could easily be misunderstood and end up with code that doesn't do what is expected or wanted. Code that is hard to reason about ("I know it says add twenty percent, but I need to remember that it actually adds 22%") and code that is harder to maintain because anyone unfamiliar with this "special case" could think it does what the name suggests.

If the tax rate changed, we could respond to this by creating a new function called--for example--'AddTwentyTwoPercent' and changing the calls to the old method related to adding the tax amount to call the new function. But how would we know which of the places that used the original function were to do with calculating tax? We'd have to go through and check them all.
We wanted to make a change to the percentage used to calculate tax. This should mean changing a single value in one place. However, we're now having to potentially review lots of code in various parts of a codebase. It should be a simple change, but a poorly named function has made this task much more complicated, time-consuming, and therefore also expensive.

Instead, what if the function had initially been named 'AddTaxToPrice'?

In that case, it would be clear what it does and where/why to use it. It should also raise a red flag if it was used for something else that happened to need to add an amount to a number that coincided with the tax percentage at that time.
If we had a function with the 'AddTaxToPrice' name, we could confidently change the contents of the function without needing to worry about where it was used or whether the name needed to be changed.
We'd have encapsulated the logic in a single place, with only a single reason to change, and minimized the chance for confusion about what the code does.

Now let's think about XAML.

Consider the following:

This might seem like a reasonable name for a resource. You may have even seen this in code presented as an example of "best practice." I actually think this is a terrible way to name a defined resource and consider it an anti-pattern. (i.e., an example of something you should NOT do.)

There are issues with this that are comparable with the C# function discussed above in the following negative ways.

  1. The name matches what the code does.
  2. The name does not indicate where or why it should be used.
  3. The code (thickness) could easily be used in very different places and for other purposes.
  4. If one of the places where this style was used needed to be changed, we'd have all the same problems as with the C# function. 

Imagine this thickness is used as the margin for Grids containing the contents of most pages in an app.
Now imagine you want to make a change to the app's design, so you have a large margin on the right-hand side of each page and add a smaller margin to the bottom of the content on each page. What do you do?

  • If you change the value of the existing resource but not the name, you get something with a name that doesn't match what it does. This leads to potential confusion for anyone (likely including yourself) reading the code in the future.
  • You could create a new resource and change all references to the old name to the new one. But, this means reviewing all uses of the original resource and only updating the appropriate ones. This could be a lot of work.

Imagine instead that a resource with the name 'StandardPageContentsMargin' had been created.

  • The exact details of this could be changed without the need to rename anything.
  • The resource's details could be changed without worrying about unexpected side effects.
  • It would be obviously wrong if someone tried to use the resource for something else. (Such as another type of control or place within the UI.)
  • You wouldn't waste time in an unnecessarily complicated and hard-to-maintain codebase.

In software development, how you name things matters. Yes, even in XAML.

Give resources names that indicate what they are for and where they should be used.

This will give you XAML code that is easier to write, review, understand, and change.

Yes, this might mean you end up creating multiple resources with the same contents/value but different names. No, the current tooling does not do a lot to help with creating similar resources. But that doesn't mean you shouldn't do it.

But, the "best practice" examples do the bad thing? - Yes, and we (I) shall (will) change them!

Sunday, March 13, 2022

Some notes for people giving technical talks

At a point last year (that I'm not going to identify) I got very frustrated with the way many people were giving technical talks. 

This is a list I put together at that time with some important things for anyone giving a technical talk to remember.

It's not about the speaker. We don't need to hear their biography or life story.

Tell a story. Or, at the very least, give the impression that you have a structure and it's not an arbitrary collection of things in an arbitrary order.

The talk is not an abstract thing. Don't talk about the presentation you're giving as an external thing. Especially not as something you have no control or influence over. It's YOU giving a talk. The talk doesn't exist separately from you.  

Don't give a talk anyone can give. Let others do that. Give the talk that only you can do.

No excuses: rehearse, rehearse, rehearse & get timings right. If you run out of time it shows you weren't prepared and therefore are happy to waste everyone's time and not give them what you promised.

If online - look at the camera. If you've chosen to have a camera on you, look at it. We don't want to see you looking above, below, or beside the camera. We really don't want to see the side of your head. 

If in-person - look at the audience. Not at the screen. Not at your laptop. Not at the floor. Not at the ceiling.

Put key names and terms on the screen (not just logos.) The audience might not recognize a logo or a term you mention. If they want to look up more about it later, it really helps if they know how to spell it. 

Share the resources. Don't say you will and then not do it. And make sure you share them everywhere the talk is made available. If you don't know then ask the organizers where it will be.

Have short versions for all URLs. Don't put a long URL on the screen and hope that someone in the audience will be able to read or accurately copy it.

Have a really clear title that matches the talk. Don't mislead an audience to attend by letting them think a talk is about one thing when it's actually about another. This includes using broad terms when you're actually going to be talking about something very focused. 

Do something specific to the audience/situation. No one wants the same thing repeated verbatim somewhere else.

whining over ;)