Security audit/Penetration Test

Last year, my employer paid for a “security audit” for our software, and any “issue” on their report was then a high priority to fix.

I think the majority of the issues they stated were incredibly unlikely to happen, or there would be an easier means of acquiring such information. One of them was that UDP messages, which are only sent on the user’s local network – had an unencrypted username. But if the attacker was already inside the user’s building, it would probably be much easier just to look at the user’s screen rather than plugging into their network and running a packet-sniffer.

Problem 1:

Shortly after we released some “security fixes”, we had a few bugs reported, one of which was:

“Users unable to reset their own passwords using the self-service password reset process”

So the security improvement created a Security major incident. Brilliant.

Problem 2:

A colleague was explaining another problem which I only had a vague understanding of. But it was to do with the version of a protocol being sent in the header of a message. It is classed as a security flaw because an attacker can look up known security flaws for that version and try to exploit the system that way. I suppose they can still guess what the version is, and try different “attack vectors”; but I suppose the less information you give them, then the more hassle it is. As my colleague explained it, a change had been made to remove the version, and tested on a specific version of SQL server, but we have multiple versions on our live infrastructure. When it came to demoing it with a client, they discovered a particular feature was broken on a different SQL Server version. A little awkward, but at least it didn’t go live.

Potential Problem 3:

When it comes to authentication failures, if you tell the user that the login attempt has failed due to the username being wrong, or the password being wrong – you are making it easier for malicious users to attempt to gain access to someone’s account. So if an attacker is guessing usernames and normally sees “Invalid username”, and eventually gets an “invalid password” message, then the attacker knows the account exists and now just needs to get the password.

There was one API call that returned an error code along with the message “Invalid username”. So as advised by the security audit, the developer changed the message to “Invalid username or password”.

On the code review, I pointed out that the developer also needs to change the Error Code too, and they replied saying the security audit stated that the message was the problem. They definitely hadn’t thought about the actual problem. If Error Code 40 is “Invalid username” and Error Code 41 is “Invalid password”, and you change both texts to say “Invalid username or password”, then it’s not really any more secure is it? since we are still returning 40 when the username is wrong, and 41 when the password is wrong. What we need to do is make 40 and 41 obsolete, and make a new Error Code for “Invalid username or password”. However, can we actually do that? When you have third parties using your API, if they have written code which relies on certain return values – then you break their software when you change yours. So we would need to inform everyone that the change is coming, then release this change.

UDP and ChatGPT

A senior developer questioned why we were encrypting elements of the UDP message. The developer struggled to explain and then incorrectly used ChatGPT. It was obvious by the increase in technicality and vocabulary in his response.

George
Out of interest, why are you encrypting this?

Karthick
According to the system audit query, MAC address and Sending user display name and the location name should be encrypted.

George
But Mac Address is sent in plaintext as part of UDP - I can see it in your screenshot above

Karthick
It is encrypted at Controller before sending.

George
Yeah I know you encrypt it in the payload, that was my question, why are you encrypting something that is in plaintext elsewhere on the network traffic?

Karthick
In most cases, the visibility of the sender's IP address is not a concern. IP addresses are public and essential for routing data across networks. While it's possible to use techniques like VPNs or proxies to obscure your real IP address from the recipient of the data, these techniques are not directly related to the encryption of the UDP packet payload.

George
Did you ask ChatGPT for that?
Also, I'm talking about MAC Addresses, not IP addresses.
I don't really care if you encrypt it or not, I was curious what decision led to you encrypting a MAC address.

Karthick
ChatGPT gave a good answer 😃
I cannot see MAC address of Wireshark UDP packet trace done in my laptop.

Govind
From the Pen test, it is reported that the
"Disclosing MAC Addresses and display names of users provides a wealth of information to a potential attacker"
via panic alerts.
That's the reason we are encrypting the Mac address.
And I believe the Mac address showing on the Wireshark, is the system Mac address(the interceptor machine) on which the Wireshark tool is running.

George
All you had to say was "Pen testers" and I would have been happy 😄

How To Confuse Women

How to confuse women

  • Step 1 centre the text in a cell
  • Step 2 watch the confusion

Alright, it’s a somewhat clickbaity title, but I did cause a lot of confusion to one person with one simple feature, and she still didn’t understand when I felt I had perfectly explained it.

I had made a grid which shows a person’s name, alongside a list of items they have ordered, in alphabetical order; as per the requirements.

Later on, we would add alternating row colours to make different people’s orders more distinctive. In the example I came up with, there were only 2 orders on a page, and I had left the row selection highlight on, so it actually looked like we did have alternating colours.

The examples from the UX team only had a few items per person, so it wasn’t clear how they had aligned the text. I left it centred which looked a bit weird for large orders, which is the example I came up with.

PersonItems
Lisaphone
 CD
 hat
 lamp
Jamesphone
 shorts
 t-shirt
 towel
I don’t see how I can accurately illustrate this with WordPress. Imagine Lisa’s row is fully highlighted

 Just to show my progress on this new project, I posted a screenshot to generate a bit of hype 😉

Olivia was confused about why it wasn’t in alphabetical order – but it is in alphabetical order!

Olivia: why is “phone” at the top?
 
Me: Ulrika's designs or my screenshot? Mine is alphabetical. Phone is for a different Person. We still need to add the alternating colours, and maybe don't centre the name to make it clearer
 
Olivia: this one <sends screenshot of top row>
 
Me: Different Person
  
Olivia: I'm confused. Lisa's name is the same row as Phone
 
Me: There's 2 People there. Just that the second person has loads of items, and because we have centred the Person name, it's halfway down the row. We can use alternate row colours as Ulrika’s design, and we can stop centering the name to make it clear.

I message Tim:

Me: I can't believe the confusion that has arisen even though I have explained what it is.
 
Tim: I got your back

<Back in the main chat>

Tim: Phone is for Lisa there
 
Tim: Everything else is for James
 
Tim: Which is when the alphabetical order kicks in.
 
Olivia: Thank you Tim, That was seriously messing with my mind. The name needs to be at the start of the list of items.

<Back to private message with Tim>

Me: I cannot understand why my explanation wasn't good enough. Is it because I am a developer nerd and cannot communicate with people?
 
Tim <jestingly>: the trick is to keep your answers on one line. Colours and shapes help too.
 

I’m so baffled. Why couldn’t they understand what I wrote? I wrote a perfect explanation then Tim just put his explanation in short messages, and he was thanked for his explanation. It’s like I don’t exist!

16 weeks work

Some teams post fortnightly updates on what they have done on our internal social media platform Microsoft’s Yammer (Now named Viva Engage). No matter what they post, managers seem to respond with positive comments.

So here is an example. On team stated they had completed:

3 user stories. 1 dev investigation. Improved code coverage.

Then attached was there code analysis report which stated:

  • 0 Bugs
  • 0 Code smells
  • 100% coverage on 1 new lines to cover
  • 0% duplications on 8 new lines

I never know how to make sense of these stats. The duplications mention 8 new lines, but yet the code coverage mentions 1 new line. It can’t mean it is still to cover when it states they have 100% coverage.

Their video demo stated it was “Sprint 8” which means it’s after 16 weeks of work. They logged into their application and there are 2 buttons (not functional).

My Work

I’ve been working on a game in Unity and have also reached the 16 week mark. I have only been working on it sporadically. Early on, I might have worked a few hours and many days per week, sometimes working several hours at a weekend. Other weeks, I have just worked on it for 3 hours or so in one afternoon only.

I have written loads of code for the AI state machine. Your units can automatically move in a formation, break away in certain conditions. Then the defending group of units have their own behaviours, and work together in their own way. Some behaviour is configurable so I have the logic and UI for the player to change it. There’s controls for the cameras, game speed, pausing, save and reloading. A few options for volume and a few graphical effects. There’s some miscellaneous aesthetics such as animations, particle effects.

I am a single developer working fewer hours, and I have to play-test it myself. Compared to a team with a few developers, a few testers and different managers assigned – all working a 9-5 day, 5 days a week; and all they have is a menu and a title banner.

Hackathon Progress

Another comparison is to compare the progress of developers during a “hackathon”, or “game jam”.  Developers can often put together a prototype, or a fairly fun game within a few days…

Developers during hackathon: We built an entire application in just 3 days. Developers after hackathon: Adding that icon is going to take 3 weeks.

Mark Dalgleish

Conclusion

Recently, I’ve been thinking about this a lot. I think if you start with no code, then any code you write has a much bigger impact. You also don’t have to work out how it works alongside other code.

So the more code there is already, then the longer it takes to write. So if the Hackathons are productive, then you can write something fast. Same situation with my Unity game, and since I am working on it myself, then I have no one slowing me down.

The other reason why working on my own is great is that I can set the process. Due to the 90/10 rule, I think it is best just to get it 90% done, then move on. If you change your mind of how something works, it isn’t as big of a time waste. If it turns out to be good, then you improve it later, alongside other features when you are changing code in that area.

So going back to this original team who did 16 weeks work and got nowhere – even though it’s a new software product, and should be able to code fast – I think they are slowed down by their insistence that everything has to be perfect and has all the extras like Unit Tests. So they could get a feature 90% complete quickly, but then they are told to spend several days perfecting it for that last 10% of quality. Then they are messing around with non-functional stuff like the Deployment Pipelines and miscellaneous processes. When you are months away from releasing, I don’t see the point in dedicating so much time to how you are going to deploy it, so I have been 100% focussed on features and gameplay.

I think this could illustrate how process can severely slow you down, and striving for perfection can also lead to inefficiencies. I think my idea of “90% quality is good enough” could be a winning approach, then you can always perfect the features if you are ahead of schedule. If I keep working on my game, I will worry about how to release it when it is close to a releasable state (ie how to get your game listed on Steam).

Failing in different ways

I occasionally meet up with my old university mates. One friend works for a contracting company. He is a really good developer on a juicy £100k wage which is crazy, and it shows how much money companies waste on software on short contracts. Often they may only have small, permanent development teams, then hire some temporary staff for extra capacity, or they might just fully outsource their software requests entirely.

Since he works on short contracts, often 3-6 months, (sometimes up to a year), he has experience seeing how many companies operate.

I love having discussions with him because he is incredibly knowledgeable and always keeps up with the latest jargon. He knows all the Cloud and Web-development jargon, popular software tools, and Agile process.

He came out with this statement:

“It’s reassuring that you get to work with different companies doing different things, but they are all terrible. You are often asked to help – not because it’s going well; but because it’s going wrong”

What he was saying is that companies have different philosophies when it comes to software. It could be Cloud only, on-prem only, strict Agile development, different levels of automation etc, but whatever they do, it doesn’t quite work, and they will make baffling decisions.

So when I write about the baffling decisions where I work, it’s just that we are failing in a different way to other companies.

Angry Unicorn

I was getting a 503 error when trying to use Git. After searching for internet for solutions, I came across this “unicorns have taken over Error – 503“.  I wondered what that was all about? Was it one of those stupid error pages some companies do as a joke?

After a bit more searching, I came across another one, Title: “Intermittent angry unicorn”, and it’s clearer what they are on about 

“I’ve been subject to the angry unicorn for over a week now.”

That angry unicorn sure does look fierce.

Commit Messages

As a developer, you need to “commit” your work into source control. When you do this, you need to provide a message that describes the change. A bug fix or enhancement can consist of a few commits. When you use a source control like Git, you can even “rewrite” the “history” by using squash/rebase commands.

When I am writing code for my job, I often put a bit of thought into the wording to make it clear and professional. If it is for a personal side-project, I sometimes write meaningful messages, but sometimes I may group together multiple fixes, then come up with something generic like “Bug fixes”, or might commit more experimental work-in-progress under a name like “attempt” or “x feature part 1”.

It’s quite frustrating though to see colleagues write generic messages like “bug fix” which doesn’t describe what it is fixing, or how it is fixing it. Seeing messages littered with spelling mistakes is also annoying and unprofessional.

Examples include:

  • “EventNotificationBugFix After Resolving James’ Comment”
  • “bug resolved”
  • “Dev test changes from tester” (literally what does that mean?)
  • Updated the findCorrectCodeSp to findCurrectCode.
  • Taken off completly the fix Amanda done for the fix for 25477 and fixed. Included the fix for 8017 as well
  • Fix for SQLCrop issues (should be SQL Cop, our Code Analysis)
  • Fioxed further typos (ironically creating more typos when fixing typos)
  • fixed the failed unit testes (testes rather than tests. Brilliant)
  • “Post Christ’ comments re coding standards” (it’s the second coming of Christ to teach us coding standards! They meant to write Chris.)

There was a guy who worked in our short-lived Scotland office who sounded like an absolute nutcase and I have never seen someone not take their job seriously like this:

  • instructions unclear, got dick stuck in tfs 
  • what a waste of eyes
  • but fuck wasps
  • be nice to bees
  • what if there were landmines in dinosaur times

A colleague recently showed me this website https://whatthecommit.com/. I don’t know if they are based on real messages, but it shows you a new message every time you refresh. Most are pretty basic along the lines of “does this work”, but there’s some more outlandish ones if you persevere and refresh many times.

One of my team members recently submitted a change that was labelled “Crash when cancelling out of the dialog”. That describes the bug that he fixed, rather than what he fixed. Another team member provided the following good advice:

The change looks good, but your commit message isn’t describing the change. Could you just reword it so that it completes the sentence “When applied, this commit will…” please. Another way of looking at it is that every commit should read like an instruction in a to-do list. I’d use something like “Return empty collection if user cancels out of the dialog”.

Senior Developer

A stricter idea of commit messages is described here: https://www.conventionalcommits.org/en/v1.0.0/

One of our Principal Developers loves linking people to this guide https://cbea.ms/git-commit/. One interesting idea is to “Use the imperative mood in the subject line”, whereas most people would write in the past tense.

Having a clear history of file changes helps you when it comes to finding which change caused an issue, and also gives you a better understanding why it changed.

Errors logging errors

Today, I saw some code that looked like the classic “I can’t recreate this bug, so I’ll write some code to log extra information, and I’ll hope this somehow helps me diagnose the issue”.

They had a list of data, and the ID in this list should be unique, but it was in there twice due to a bug. So it would look like something like this (ID =1 is in there twice):

private List<Code> _codes = new List<Code>()
			{
				new Code
				{
					IsSelectable = true,
					ID = 1
				},
				new Code
				{
					IsSelectable = true,
					ID = 1
				},
				new Code
				{
					IsSelectable = false,
					ID = 2
				},
				new Code
				{
					IsSelectable = true,
					ID = 3
				}
			}; 

Then their method contained this code to validate the data:

		private void EnsureValid(int idToFind)
		{
			try
			{
				_codes.Single(s => s.ID == idToFind);
			}
			catch (InvalidOperationException)
			{
				Dictionary<string, object> customData = new Dictionary<string, object>
					{
						{ "ID", _codes.ToDictionary(x=>x.ID) }
					};

                LogToErrorDB(customData);
			}
		}

The Single will throw an exception due to there being more than one matching element (Single will succeed when there is a Single match). In the catch block, they then convert the code list to a dictionary and will log this in the error database. However, a dictionary requires the keys in the dictionary to be unique. Since there’s duplicate IDs, this will throw an exception again, this time with:

“System.ArgumentException: ‘An item with the same key has already been added.'”

Error thrown in the catch block

So you get an error whilst trying to log your error. The extra information they intended to log is never logged.

I’ve seen this mistake happen a few times before, and usually you can test it by artificially creating the data condition. Then they would realise their error logging doesn’t work.

Computers cannot handle floating point maths

I’ve been writing a game using Unity, and I’ve just realised how rare it is to use floating point (decimal) numbers in my day job as a software developer. I remember my Computing teacher back in College stating how computers are rubbish at calculating decimal numbers, but I never really understood. Calculators work just fine. They may only have several decimal places but that is usually more decimal places than you need.

In game development, decimal numbers are frequently used for sizes and positions in a 3D space and therefore calculations with these objects involve lots of decimal maths.

After writing some logic to position my characters on the map, I tried writing a unit test. Unit testing this method could be beneficial when I add extra features later.

I wanted to compare a Vector which is composed of 3 floating point numbers. Since I already had written the logic and was happy with the character’s positioning, I just grabbed the output of the method and specified it as the expected output, but my test failed!

Expected: (-34.28, 0.00, 20.63)
But was:  (-34.28, 0.00, 20.63)

so then I inspected the Vectors more closely

"(-34.28, 0.00, 20.63)"
	magnitude: 40.00208
	normalized: "(-0.86, 0.00, 0.52)"
	sqrMagnitude: 1600.166
	x: -34.275
	y: 0
	z: 20.625
 
new Vector3(-34.28f, 0.00f, 20.63f)
"(-34.28, 0.00, 20.63)"
	magnitude: 40.00894
	normalized: "(-0.86, 0.00, 0.52)"
	sqrMagnitude: 1600.715
	x: -34.28
	y: 0
	z: 20.63

I think the numbers it shows you is a text representation which involves rounding the numbers to 2 decimal places. But if you look at the actual X, one is -34.275 and the other is -34.28. So there’s a 0.005 difference. A similar problem with Z.

What also threw me, is when I looked at the documentation, https://docs.unity3d.com/ScriptReference/Vector3.Equals.html  I saw this:

“Due to floating point inaccuracies, this might return false for vectors which are essentially (but not exactly) equal. Use the == operator to test two vectors for approximate equality.”

I was originally using Assert.Equals(expected, actual) so I switched to Assert.True(expected == actual) but it still wasn’t working.

I looked at the Unity source code and they are providing their own == operator for vectors that does some “square magnitude” calculation then compares if it is less than a certain number – a margin of error. 

this is Unity’s version

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Vector3 lhs, Vector3 rhs)
{
   float num = lhs.x - rhs.x;
   float num2 = lhs.y - rhs.y;
   float num3 = lhs.z - rhs.z;
   float num4 = num * num + num2 * num2 + num3 * num3;
   return num4 < 9.99999944E-11f;
}

So I did something similar and increased the number. I came up with this, using Unity’s provided square magnitude function, but wasn’t sure if it made mathematical sense: It worked for my scenarios though

private static void AssertAreApproximatelyEqualDueToFloatingPointImprecision(Vector3 expected, Vector3 actual)
{
   var difference = Vector3.SqrMagnitude(actual - expected);
   Assert.IsTrue(difference <= 5.0E-04);

/*
eg
0.0004996415
<=
0.00050
*/
}

Looking back at this, I probably over complicated it. I suppose I should just change the expected values to have more decimal places because it’s the rounding to 2 decimal places that will be the actual problem in this case. In other cases with more decimal points, you will encounter issues due to the way computers do handle large decimal numbers which the Unity docs are alluding to.

In other situations, you also need some leeway in your calculations. If you want to move a character to a certain position, you may find that they could be 0.1 away from their destination, then on the next frame, they move their usual distance based on their movement speed – and then overshoot it. So you end up needing to write code like “if distanceRemaining < 0.2f then stop

So floating point numbers, especially when it comes to game development, really does add extra complications to think about.

Performance Tales: Tasks

Recently, a team was created in order to tackle major issues, often proactively. Some errors are logged without the user noticing anything, so by monitoring the logs, the team can diagnose and fix these “silent” errors. The other thing they are looking out for is performance problems. Some performance problems aren’t noticed when it’s more of a minor increase, inconsistent, or slowly gets worse over time. I would think some users don’t bother reporting slowness because it’s harder to quantify than the obvious crash.

However, one user had been seeing a recent drop in performance by not dealing with their tasks, but it had got to the point where they could no longer log in, as it took longer than 30 seconds to retrieve their tasks on login – so it timed-out (as in an error was meant to be thrown when the time to retrieve their tasks took 30 seconds).

“At the time of logging this bug, the user currently has 136,854 tasks in Tasks Management. The Program performance will start to be negatively affected after 4,000 tasks. I have extended the timeout of sql call for TasksManagement.GetUserTaskCountSummary to 60 seconds as this caused a login failure.”

Walter (Developer)

“let’s be honest, the program performance will start to be negatively affected after 1 task”

Mike (jestingly)

I think this is acceptable as a quick fix to allow the user to login again, but is it really acceptable for the login process to take more than 30 seconds? I’d imagine it would take around 40 seconds for this user.

That’s the problem with this team, they just look for quick wins, even if it isn’t the right solution long-term, and might even move the problem elsewhere.

What’s better than waiting 30 seconds? waiting 60 seconds? or threading it off to delay the loading? or Mark’s idea: no timeout.

What if the time taken still exceeds 60 seconds, assuming some other user has a large volume of data? Can you set the timeout as infinity?.

Mark


we had a customer with a very large count and it only ran for around 32/33 seconds and their counts were unusually large. We are going to send out communications for customers to keep these low by means of maintenance. The 60 seconds just allows an extra safety net if we get in this situation again. I don’t want to extend the timeout to be too long for this reason as it will unlikely (if ever) be needed to be longer than 60 seconds.

Walter


Why not a try catch / retry attempt for this? It should be a non-essential call to logging in, if it fails, you can catch, log, and show an error message. Should we not look at optimising this so that you can login quicker?
Maybe run this on a background thread too?

Lee


I discussed this with Johnny and making changes to this Stored Procedure could result in worse performance for smaller datasets and advised against making changes to it. We’re going to tackle this by means of communications to sites. I thought the simplest and safest approach is just to extend the timeout slightly so that the practice does not suffer a system down as a result of it – the timeout is only breached by a second or two.
Once the user logs in, they are displayed their task counts, so I think it might be deemed essential (rather than showing them a loading wheel until the data is returned). Currently, if we did this, when loading up Tasks Management it would just crash with an error.

Walter


It would still crash on logging in if it takes over 60 seconds.
Why not make it non-critical to logging in?

  • Log in
  • Status bar “Loading…”
  • Completes – OK.
  • Fails – Show error and retry link.
Lee


This was the worst site on the estate and was taking roughly 32 seconds. To take over 60 seconds the task count would probably be unheard of.
Each time I ran that stored procedure manually, the results were the same so I don’t think a retry is going to work here.
Even by changing to make it non critical to logging in, Tasks Management will still be busted when you try to load it. The timeout is on the SQL side so that is the area we need to resolve really.

Walter

However, Johnny did advise against alternative solutions such as:
1. fine tuning the stored proc
2. adding indexes
3. Remove tasks counts completely for some types of tasks

My View:

Walter seemed to have put more thought into it than I originally thought, but I still thought he was overlooking Lee’s suggestion. Yes, it would need more work to actually work (display loading text on the Tasks Count Bar, then loading screen when launching the Tasks Management page), but it would significantly speed up logging in. If this user could log in 32 seconds quicker, then what would the average user see?

If the other parts of the log-in process also take some time, then that’s a long time they are waiting in total. If taskcounts are the bulk of the time, then we can make it super fast if we take it out. I would have thought users would expect times of 5 seconds or less (might not be possible, but that’s the scale we need to aim for). Walter is talking like users are more than happy to wait 30 seconds or more just to get to the home page. A long wait is better than not being able to log-in at all, but surely it’s generally unacceptable to be more than several seconds in total. It’s one of the reasons why users have grown more discontent over time.

When doing some testing of smaller counts, for example 10k – the results are returned in a few seconds (2-3). This organisation had around 120k Appointments Tasks across all users plus all of their other tasks which resulted in a production duration of 32 seconds. The more they manage their tasks the quicker workflow will be, that’s always been the message we’ve tried to get across.

Walter

Performance Review 2023

Last year, we felt slightly aggrieved that our employer made out they would match inflation with our pay rises, but then disguised it with: a one-off profit share, pension payments, and optional benefits. Our wage only increased by 2% but inflation was currently around 7% and predicted to rise further. Better than nothing though, so can’t really complain.

With inflation being 10%, we wondered what we would get this year. Then came the communication that stated that they understand inflation, and remarked that we are still highly profitable so can cover the costs:

“Further to our communication at the end of 2022, I can now update you on our remuneration approach for 2023. We know and understand that employees are continuing to experience cost pressures and we remain committed to ensuring that the overall pay budget for this year reflects the continued external inflationary environment we are in. Whilst this has been possible due to the ongoing success of the business, it will require us to again manage our costs in 2023 carefully.”

HR Director

However, then they reminded us that they gave us: 

  1. an extra £200 one-off payment
  2. Increased leave for parents
  3. the option to work bank holidays and take a different day off instead.
  4. they will give us a one-off profit share just like last year

So with them clutching at straws for things they have done, you know that means they weren’t giving us 10%. Maybe we could get 5% as a compromise then?

“The exact amount of any increase to an individual’s salary and timing will be agreed locally, as normal, and will be dependent on a number of factors including performance. I believe these measures reflect our responsibility to be aware of the external inflationary environment, our immense gratitude for your efforts over the past year and our desire to become an employer of choice.”

HR Director

What did I get?

0%

immense gratitude for your efforts over the past year” 🤨

I’ve mentioned in previous blogs that judging performance is very subjective and often bent to fit a narrative, and I got completely screwed. So let’s get into it:

The Review

“You had an average year in 2022, working on only a couple of projects, one where you worked as an individual contributor then moved onto a pair project”

Well, that seems to imply just being on 2 projects in a year was a bad thing, but that’s not really my fault is it? Since I single-handedly delivered one project, then was in a team of 2, surely that should show I can handle responsibility and pressure?

“You were good in many technical aspects but were not able to step up to the plate as a leader in the team.”

I was in a team of 2 as a Senior Developer, and I got really good feedback from that team member. What more do you want?

“You were given an opportunity to lead on defining our interview process. I expected you to lead on this but have not shown much interest in it. Ultimately someone else led it, creating the interview pack, redefining interview questions and leading live interviews, which I think is a missed opportunity to shine.”

I blogged about this process. It was a mess, but at least I tried my best to direct it. We created an interview process for Graduate Developers from Indian universities who were using Python, but set them C# and Object-oriented questions…then asked questions on Software Testing which they also don’t do. I was pretty clear we needed to focus on the people we were targeting (Python and Web programming) and not on what the job was (C# Developer); (or even better, change the people we were targeting – but that was already decided upon). I got outvoted by the other Seniors. I felt I couldn’t lead in the interviews because I didn’t believe in the questions.

“I can see that you might not see Unit testing as a productive way forward, and the target set might not be accurate”

In recent times, managers have been demanding we achieve 80% test coverage and I have highlighted how poor many tests are that people write, and the 80% is a random target. It’s not improving the quality of code at all. Due to the fact I wrote little (but high-quality tests) I got criticised and talked about between senior management. I raised in my review that I believe managers now see my output as low quality, so I will need to repair my reputation.

I also raised that I was annoyed at the frequency of team member changes. My projects had Testers switched in and out, we changed Product Owners, Software Architect, and there was talk of more changes that didn’t happen. Colin then stated “I never raised my concerns at the time”, but I definitely did.

Some of the comments received from your colleagues:

“I think that he has been a good technical lead. His knowledge is excellent, and this has been shown in how he has been able to help me with any technical problems. He has constantly been available, has a great attendance record, and will defer annual leave for the good of the project. His code review comments are always clear, concise, and helpful. He is always available to help with Testing as well.”

“He has a good insight into what he thought was and was not possible”

“He needs to make sure that just because an issue is raised he doesn’t jump on it right away as there is a priority order for things”

“He’s reliable and just gets on with the work”

“Can be a bit quiet on calls at times but whenever I specifically call him out in calls, he would answer questions”

“At weekly meetings there wasn’t enough substance in his updates. He doesn’t come across as a leader to me or perhaps he just did not want to be at those meetings.”

I definitely got good feedback from people but then the positive ones were ignored in the discussion. I had good arguments against some of the negative points as well. I think I only picked up non-prioritised work when I had finished the work that was. What do you want me to do? Just sit there idle? I often knew it was issues related to recent work so it was obviously gonna be the highest priority, and as Team Lead, I think I can make that call myself. 

I’m always annoyed when people criticise me for being quiet on calls. If enough people are saying the things I am thinking, then I don’t need to speak. If no one has raised the issue I am thinking of, then I will provide it. Then, if people specifically ask what I think, then I will say, even if I am repeating what others have said. That final feedback was about a meeting similar to a Scrum of Scrums where many teams get together. But the meeting was mainly for Colin and he rarely attended. So I had the attitude of quickly going through my points then moving on. I thought the wording was harsh – they have no idea what it is like to work with me directly.

I have no idea how they can justify giving me nothing. That’s like a 10% pay-cut with today’s economy.

Colin isn’t my manager anymore, so let’s hope my new manager will actually put things right.