Can AI Make Computer Games?

Jabrils created a game using various AI tools. Although he says it was 100% created by an AI, it required him to type in different prompts until he got something that worked, and needed to use different AI’s in order to get the code, images, and sound. So it still needs human input as a “director”.

I fooled an expert gamedev with a game made ENTIRELY by AI

He got David Jaffe, who worked on the likes of Twisted Metal and God of War, to harshly critique it, oblivious to the fact it wasn’t Jabril’s own game.

He initially struggles to work out what the aim of the game is, which highlights the fact that – even though it is a working game – it doesn’t have the extra polish such as a tutorial, button prompts, or subtle visual hints. Although, maybe it could have added them had Jabrils specifically asked for those features.

“I have no clue what I’m doing in this game. If I wasn’t recording this video with you – I would be done”

David Jaffe

“I also don’t know what my goal is. I assume it’s to land but you don’t really have the space marked very well.”

David Jaffe

Since David believes that Jabrils made it, he remarks on how you think your own game is obvious how to play it, but that’s why getting someone independent to play test your game is so valuable. It’s similar to any type of software development really; you can be so focussed on coding, that you don’t see the bigger picture and the various ways someone can interact with it

After he is told it was made by an AI, he becomes more positive. 

“I think it is brilliant. Looking at it from that perspective, that is how games are going to get made more and more, right. The fact that you could do that, and say ‘make me a game that does X, Y and Z’ is amazing…I love it. I love that you made this. It’s terrible, but it’s kind of like criticising a one-year-old who took his first steps.” 

David Jaffe

It’s going to be interesting how AI develops, and I do wonder how long it will be before human interaction will be reduced, and also if AI can “understand” game design to actually incorporate more user-friendly features.

Bug: Identification number mismatch

Recently, a developer had fixed a bug with title similar to “Tax Number is not populating in Save Registration dialog”

The original code looked like this:

public CarIdentification CarIdentification1
{
   get { return _carIdentification1; }
}
 
public CarIdentification CarIdentification2
{
   get { return _carIdentification2; }
}

if (!string.IsNullOrEmpty(transaction.TaxNumber))
{
   _carIdentification1.Value = transaction.TaxNumber;
}
 
if (!string.IsNullOrEmpty(transaction.RegistrationNumber))
{
   _carIdentification1.Value = transaction.RegistrationNumber;
}
 
if (!string.IsNullOrEmpty(transaction.NewRegistrationNumber))
{
   _carIdentification1.Value = transaction.NewRegistrationNumber;
}
 
if (!string.IsNullOrEmpty(transaction.NewTaxNumber))
{
   _carIdentification2.Value = transaction.NewTaxNumber;
}

So a quick glance at the code and you see that 3 of the 4 statements are using “_carIdentification1” then the last one sets _carIdentification2. So without putting much thought into this, I would expect one of the first 3 should actually be using _carIdentification2. But what does 1 or 2 actually mean? Are they representing TaxNumber and RegistrationNumber, or is it representing Old and New?

If it is the former, I think _carIdentification2 would represent TaxNumber so the first one was wrong.

If the latter, then I think _carIdentification2 would represent New so the third one is wrong.

I do know that the concept of TaxNumber was added into the system later on, so most likely it would be: “_carIdentification2 would represent TaxNumber”

However, the developer, Govind had changed it to the following:

public CarIdentification CarIdentification1
{
get { return _taxNumber; }
}
 
public CarIdentification CarIdentification2
{
get { return _registrationNumber; }
}
if (!string.IsNullOrEmpty(transaction.TaxNumber))
{
   _taxNumber.Value = transaction.TaxNumber;
}
 
if (!string.IsNullOrEmpty(transaction.RegistrationNumber))
{
   _registrationNumber.Value = transaction.RegistrationNumber;
}
 
if (!string.IsNullOrEmpty(transaction.NewRegistrationNumber))
{
   _registrationNumber.Value = transaction.NewRegistrationNumber;
}
 
if (!string.IsNullOrEmpty(transaction.NewTaxNumber))
{
   _taxNumber.Value = transaction.NewTaxNumber;
}

So they have named the fields _taxNumber and _registrationNumber which is much clearer. Notice though that they have deemed carIdentification1 to be _taxNumber which means they are saying the second, third, and fourth statements were wrong!

An additional thought: if a “transaction” comes into the system, what fields do you expect populated? if RegistrationNumber and NewRegistrationNumber are populated, then _registrationNumber will initially be set to RegistrationNumber, then instantly changed to NewRegistrationNumber! So I’d say this logic needs to be if/else so it only sets _registrationNumber once and _taxNumber once.

I point this out to the developer, but I find a large number of Indian developers just seem to respond with a sequence of meaningless words and you have no idea what they are thinking.

Me:

if NewTaxNumber and TaxNumber are specified, won't it just use NewTaxNumber?


Govind:

taxNumber identifier has to updated with new taxNumber value for transactions


Me:

if it is intentionally written this way, it should be if/else

and if it wasn't intended that way, then there is a bug here, similar to the one you are fixing

They ignored me and checked it in. I don’t know if just the original code was mad, or if this new code is mad too. Let’s hope it doesn’t cause more problems when it goes live.

90/10 rule of project management

The biggest thing that annoys me about software development is how projects really drag out near the end. It feels like you get so much done at the start, then progress really grinds to a halt. So early on, you think you are way ahead of schedule, then all of a sudden you feel like you are behind. Even when you get an extension, no matter how little is left, it seems to drag to take the allotted time.  

z 
z 
z 
•••naaHM -3HL NI S90Q 
sv saaaonanaa saas 
LN3W39VNVW MOH 
xnogv V Ll 
moua-uwoo SLI aod -3%V11VAV 
-3WlL -3HL OL 71äOM 
anox aNvaxa nox •svq v 
-3711 -3MHag saaaonanaa MONÄ I 
asnvoag 7SVL SIHL aaxogawlL 1 
anox aaqvrqvw v '-3QNO 
MVI S,NOSN17äVd

I do think I am terrible for dragging tasks out. It’s easy to look at the time and think “ah it is 3pm, may as well keep testing this rather than moving onto the next task”.

As well as Parkinson’s Law, I was reading that there is what is known as the “90/10 rule of project management”. This is where the first 90% is completed in 10% of the time, but the last 10% takes 90% of the time. So it seems it’s not just me that thinks this is a phenomenon.

So let’s think why this is: 

Putting off the unknown until the end

To maintain progress, it is much more tempting to pick up the work with the clearest requirements, and leave the uncertain ones to the end. Even when there is a Product Owner prioritising the work, they are often swayed by the Developer’s opinion. Also, there can be potential work you uncover when looking at what the code currently does and you think “I’ll investigate that later”. When you eventually get around to it, it turns out to be a “can of worms”. 

Last-minute changes:

No matter how much you plan, there will usually be some last-minute changes since the customer can change their mind. With “scope-creep”, that last batch of work has become larger. In a similar fashion, you could be implementing a feature but then discover there’s other features that need changing to be compatible – so over time, more requirements are discovered. 

“Resources”:

Over time, other projects or bug fixes suddenly increase in priority and you can find yourself with (at least temporarily) fewer team members. I also find that people may delay their annual leave during the time when they feel most excited about the project, then when it starts to drag, they then take it. Managers can also think “ah, that project is nearly finished, we can take a developer away and put them on a new project”.

Lines of code

If you imagine starting a new project from scratch, and think of a fairly straightforward feature like a dialog with several text boxes. You can quickly code the UI and the server code to save the data to the database. But then when you come to test it, you realise that resizing the dialog doesn’t scale. So you make a few tweaks. What about users that only use the keyboard? So you add the tab order, some accelerator keys etc. What about invalid data entry? So you add some extra checks and appropriate error messages. Ok, what about automated tests, so you do some refactoring and add some tests. The manual testers find a bug that a certain scenario doesn’t work. So with this example, it is easy to understand that the dialog can be 90% complete really quickly, but that extra 10% to perfect it took a long time, and maybe some delays occurred communicating  back and forth with the Testers and Product Owner in order to finalise the work.

But we can take this explanation further.

A few weeks later, you need to add a feature that interacts with this code. You might need to re-familiarise yourself with the code, re-reading several files, and your changes need to not break any existing feature. Now imagine this kind of sequence happening over many months. The codebase increases in size and complexity, and the constant refactoring might mean that files you remember with a certain name have now drastically changed, moved or been deleted. Development is far slower now for most features, and even bug fixes could involve stepping through more lines of code in order to diagnose and fix. So I’d say productivity drops proportional to the size of the codebase.

Learning Unity

Several years ago, I tried learning Unity (games development) but it took a long time to pick up the basics. I’ve been meaning to give it another go, and when Code Monkey (a Youtuber I did subscribe to) announced he was making a 10 hour free course, I thought it’s the perfect time to jump in.

Following along, rewatching and experimenting with what I was learning took ages. I ended up dedicating many weekends and a couple of hours each day to complete it.

It’s a basic Overcooked-style game. If you want to make it, you do need to sign-up to Code Monkey’s website https://unitycodemonkey.com/kitchenchaoscourse.php to download the assets (graphics and a bit of audio).

If you want to play it, you can get it on Steam for free. https://store.steampowered.com/app/2275820/Kitchen_Chaos__Learn_Game_Development/

A few days ago, Code Monkey released part 2 of his free course! This time he adds multiplayer. I haven’t watched that one, but have added it to my Watch List.

I have: many Youtube videos; websites; books from Humble Bundle to go through, so I’ll keep at it.

Example of a bad project led by a Principal Developer

Intro

One problem we often talk about at work, is that software projects are sent to be Code Reviewed a month before release, and they often get torn apart. This is because many people at the company don’t seem to like doing code reviews, or aren’t good at critiquing code.

As the project goes along, each check-in requires review but the review is done within the team. When the project is complete, and needs to be merged into the Release branch, the review is done by people outside the team (by people of higher skill, or by people who review under more scrutiny).

It’s still strange when the project is led by a senior, but is then torn apart at the final Code Review stage. Or in this case, that I am covering today – Gerald, a Principal Developer; someone who you would consider an “expert”. 114 comments were left on this particular project.

Some comments were coding standard violations (but given the Principal has several years experience working here, it was hard to believe he overlooked them), general bad formatting, code comments left in code, loads of mutable classes (bad design, but often very easy to fix), then a few classes spamming the error log (we have a separate problem which another development team are trying to fix – about monitoring storage too high, mainly down to excessive/unnecessary logging)

Problems

Excessive Logging
Me
Is this creating 6 log entries per call?

Gerald 
Yes , maybe even 7, but that's if the config value is set to debug. We have turned off by default

Sean
How do you change the logging level? Do you need a new release to change it? What is your plan for changing it?

Me
shouldn't it just create 1 row with all the information in?

A single entry would be good, I point out it is excessively adding 6 rows per call, and he is like “no! you are wrong, it is worse than that!”

In another part of the code, Sean flags up the same problem. Weirdly, he then agrees it is a very bad thing to do, and his tone sounds like it is an obvious thing. Wasn’t he leading the team? why didn’t he notice the problem during the months he was working on it?

Sean 
Won't this write a lot of entries to the Error Logs?
We are actively trying to stop that

Gerald 
the audit logger can be turned off.
I agree here though we could not write to monitoring if there's no records

Sean 
There's an ongoing project to stop that amount of unnecessary, unused and ignored things to the error logs.

Gerald 
Agreed. especially from the client. because that clogs up networks - a lot worse than this.
Does the code work?
//Would this work? Or how do we get the organisation ID?

He left this code comment in the code he sent to review. If the comment is doubting that it works, what confidence do I have? Instead of writing any words, I send a simple emoji. 👀

Gerald 
Not sure what this comment means, could you please elaborate

Sean 
Might be the fact that there's a question in the code asking if it works or not.
What a cliff-hanger.... Well does it? 😄

Gerald 
I'll remove the comment. Thanks for clarifying Sean.

Gerald 
Removed the comment. I think the team was not aware that we can get the organisationid from the usercontext.

Why did it need clarifying? Did he even read the line I commented on? why do we need to explain that a comment like that shouldn’t be in code we send to production?

YAGNI

There’s a software development principal known as YAGNI: You Ain’t Gonna Need It. It’s about only writing features you know you need. If you write features that aren’t used, any code changes you make need to support this feature. It’s a maintainability problem. There were actually a few instances of this in his project, although it was a case of maintaining obsolete code.

Changing obsolete code just in case it is used, but yet it wasn’t tested because it wasn’t used…

Sean 
This looks like dead code...

Gerald 
Yes on the off chance it was used, we now redirect to the new stored procedure

Sean 
How did you test it?

Gerald 
We spoke to the other team and they said it wasn't used, so no testing required. I am sure.

Sean 
So you leave it in case it is used, but don't test it because it isn't?

Gerald 
Yes sort of. In case this was ever resurrected the change was there for them to use

Sean 
It won't be
Not knowing which server runs his code

I also found it odd that he thought some of the code was run on the Scheduler, when in fact the Scheduler never has much logic; its role is to send “jobs” to the Application Servers to process them. Therefore, the code his team wrote is executed on the application server…

Sean
There must be a better way than making a Remoting Call to get this information!

Gerald
We're stuck here. The enablement is on the Application Server. The scheduler service is running this, and we don't want to make direct DB calls.

Sean
No it isn't. This code is running on an Application Server
I was playing around with it
case when (BeforeXml is null and datalength(BeforeXml) = 5)

This code is always false. It cannot be null (empty) and also be 5 characters.


Gerald : Good spot I will make this change now. I was playing around with it

The Major Incident

After the project went out, the release got “Red Flagged” which means we have to produce an urgent fix, and the release is halted from the rollout.

“Please can we red flag the current release. Unfortunately the database Schema Patch 8037 altering the Audit table filled up TempDB (60gb+) resulting in the database server Failing over.”

The change he made seemed very rushed. From the Principal Developer’s own words, he said that managers were demanding the change as quickly as possible. He should know better from his experience. Which is better: a delayed but correct fix, or a rushed broken one which would cause yet another red flag?

His new, rushed fix was inefficient, mainly from not understanding LINQ-to-SQL. There were also some database changes which the logic was wrong, and there was a typo in the SQL script which would have caused it to fail.

If it doesn’t work, it’s not gonna get past testing, and won’t release on time anyway, so what is the point rushing it?

Sean: This can't be very efficient…

Gerald: Might need an index on that, but it's linq to sql - a mind of its own. i can try profiling this, but seems pressured to get this in

Sean:
And if you slow down the saving of new records, you will find even more pressure to get a fix out
Also, Linq-SQL doen't have a mind of its own…

Additionally, a tester had a look at his changes and pointed out yet another error in his new database patch. If Gerald had run his changes through the database tool we have, it would have flagged the error. Absolutely embarrassing. But that’s what you get for rushing.

4 Year Special: Derek

It’s been 4 years since I started writing this blog! how time flies.

The original inspiration for the blog was to tell stories about my incompetent colleague Derek. However, he left shortly after I started writing – so I didn’t end up writing many blogs about him.

After going through some old chat logs I found, I have dug up some extra stories, code snippets, and quotes.

“There’s a lot of duplication here, surprisingly. Functionally it is probably quite a big bag of spanners”

Derek

Hypocrite

When I first started working with Derek, I was telling my manager about the things he was doing and saying. My manager asked me how he is getting on to see if I had more stories to tell.

Matt:
How is Derek getting on?

Me 10:36:
on holiday, but he has spent a week or so sorting out some buttons. He has assigned two items to himself. 

So he complained that the User Stories were too big, so we have split them up a bit more. Yet he then assigns 2.

He hasn't sorted out all my comments I made on his last fix.

After Derek was making excuses that he wasn’t productive due to the size of our planned work, we split it into smaller chunks for his benefit. He then picks up multiple chunks in addition to also needing to rework his previous work. It seems we didn’t need to split the work up at all.

Redefining a boolean

bool hasSelectedReports = SelectedReports.Count != 1; 
bool noReportSelected = SelectedReports.Count == 0;

A boolean or “bool” for short represents true or false. Since there are two states, if you created a variable called “hasSelectedReports” you can invert it using the ! (not) operator, so saying !hasSelectedReports reads as “has no selected reports”. Derek decided to create a variable for the inverse, but then he got the logic wrong: If Count is 0, both hasSelectedReports and noReportSelected are true!

“I’m working from home today. Sorry I haven’t emailed sooner, I had some problems initially remoting in as my computer at work had a dicky fit.”

Derek

Pointless Conversion and check

return !String.IsNullOrEmpty(ConceptId.ToString()) ? ConceptId.ToString() : null;

ConceptId is defined as a long ,which is a number. It can represent any whole number between -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. It cannot be null/empty. By default it will be 0. Here, Derek converts the number to text (string) so he can take advantage of the IsNullOrEmpty method. If it is somehow null, we will return null… apart from if ConceptId was somehow null, calling ToString on it would crash.

If he really did want the text presentation of the number, this code should simply be

return ConceptId.ToString();

Pointless Conversion and check: part 2

if (!String.IsNullOrEmpty(conceptId.ToString()))
{
   	_conceptIdInt64 = Convert.ToInt64(conceptId);
}

Again, Derek decides to convert the number to a string so he can check it isn’t null. It is always true, so then goes into the code block. He then converts the long to an Int64. A long IS an Int64. It’s just an alias for it. So the code is completely pointless, other than assigning a simple variable.

“I may have taken too much artistic licence”

Derek

If at first you don’t succeed, try again

public Entity GetEntityFromConceptId(long conceptId)
{
  	return 
  	  	(EntityFinder.TryGetEntityFromId(conceptId)) != null 
  	  	? 
  	  	EntityFinder.TryGetEntityFromId(conceptId) 
  	  	: 
  	  	null;
}

When methods are named “Try”, it means that it might not be successful and can return “null”. In this case, TryGetEntityFromId returns null if you pass in a conceptId that doesn’t exist. So you should check for null, and do something different, maybe display an error message to the user. Although Derek decides to simply try again. Why would it work the second time?

(frustrated tone) I’ve spent 5 days on the same work item

Derek after 13 days trying to implement a simple feature. For the previous 3 days, during the daily stand-up meetings, he was saying he is “nearly finished and it’s pretty much ready to check in”

Conclusion

As you can tell from these stories, Derek made some bizarre choices and generally seemed deluded. There were times where I thought he had to be trolling, because there is no way you would write so much redundant code. I understand you can have bad days and have the occasional moments of madness, but it was a daily occurrence with Derek. For more stories about Derek, click the Derek tag.

Bug Bash

It’s been a while since we organised a “Bug Bash”. The general idea is to focus on fixing software bugs and clearing the seemingly ever-growing list. Sometimes managers have organised this as an optional thing over a weekend, or sometimes opted for a work week.

The problem I have with this idea is that with a strict deadline, you are encouraging people to rush. If you want to follow the usual process of a developer really understanding the bug (reading the bug report carefully, recreating the issue, analysing the code, coming up with a solution, testing it manually, maybe writing some unit tests for it), then going through the code review and testing process – then you are being really hopeful that it can be done in such a strict time-frame.

I find another developer will always have some opinion on your code, so you make a change, have to retest it and then get them to review it again. Then when coming to patch it on the test environment, you then might get problems with the build server or the test environment.

So the only bugs that are really appropriate for a Bug Bash are ones that are easily recreatable, quick to fix, and low impact. All the true high priority issues will have been addressed more urgently and put into the normal release process anyway.

What you have to bear in mind, is any change has some kind of risk that you might introduce another problem, and this increases when you try and rush the change out; which is what the Bug Bash inherently prioritises.

I was looking for an example of how managers sold the idea, and I found one that actually seemed a bit more thought out:

 
Next week we are to down tools on project work and spend the week stabilising our product.
 
Service have provided a list of 300+ issues they would like us to work through. In addition, Paul has been reviewing the Error Logs to identify the most frequently reported errors and is creating items for these.
 
The domain experts are currently reviewing the list and identifying the issues they feel can be fixed next week. These will be placed into the Stabilisation list.
 
The priority order for working these items is set by a temporary field ‘Bug Fix Priority’. 1 is the highest priority.
 
Each developer should select the next bug at the top of the list that is not currently being worked, change the state to Assigned, and Owner to themselves.

All Priority 1s must be completed first. If there are no defects you are comfortable fixing, please speak to me before moving on.
 
Each bug fixed must have supporting unit test(s) before being sent for code review.
 
At no point should a developer have more than 3 items they are involved with, this being 1 bug being worked on, 1 being code reviewed and 1 with the tester.  If you’re waiting for a code review - go chase it. If you're waiting for a test to complete – go help out.
 
It is important to note the emphasis on this release is QUALITY.
 
With this in mind, the attached spreadsheet has been produced that maps a developer to someone who will review their code and DB changes. Where possible we have also mapped each developer to a test resource. The developer and tester jointly own the end to end process for each bug.
 
A kick off meeting will be held at 10am on Monday in Room 1 for all to attend.
 
Code Reviewers will hold daily stand-ups with their development and test resources which will then feed into a management review at 4 pm.
 
 
Darren
Development Manager

So, they have allocated a full week, tried to analyse the bugs to see if they are suitable to fix quickly, and they have emphasised it is about quality. However, they seem fairly strict on the order the bugs are addressed, so you may end up with developers being forced to pick up items in areas they don’t specialise in.

There was a follow-up email stating that there were issues with the build server which caused them to lose time.

All,
 
The plan is to finish coding tomorrow to allow test to complete on Friday.
 
With this in mind and as a result of build issues experienced yesterday we’re considering the possibility of overtime tomorrow evening to make up lost time.
Can you please indicate using the voting buttons by 12pm tomorrow whether you’d be available for overtime tomorrow evening.

We'll be ordering Pizza and a Beer too, to keep us fuelled 😉 It would be very much appreciated if you could stick around. Every bug fixed is giving our end users a better customer experience!
 
Thanks,
 
Darren

When Bug Bashs have occurred over the weekend, I think Developers and Testers have started at the same time, but they wouldn’t have had anything to test until mid-day at least – due to development time, code review time, then build and patch process. So the Testers will just be earning money for chilling out and eating pizza.

I found an instant messaging conversation with a colleague about a different Bug Bash:

Daniel 11:37:
one of the bugs on the list to be fixed in the bug bash was logged by me 5 years ago
so very urgent then

Me 11:38:
the bug bash isn't supposed to be for urgent issues

Overtime requests will only be approved for time spent on defects that are Fixed, Tested, PO Approved and Closed(Done)
 
So you could do some complex work, not get it done, and therefore not get paid

Daniel 11:42:
yeah I read that today
who's going to go for that
it's completely the wrong way to fix bugs

So this bug bash seemed to be for clearing down all the bugs that have just been ignored for years. The problem with old bugs like that is that you could spend time trying to recreate them, and find they are now obsolete due to other code changes, or obsolete features. The managers also decided they didn’t want to pay people for incomplete items, so you cold spend ages working on something and not get paid.

  • You could close the bug as obsolete – it’s not fixed so you don’t get paid
  • You could spend ages recreating it, coming up with a fix, but there’s not enough time for the rest of the process to actually complete it.
  • You could come up with a fix, but there’s a small bug found by the tester. You could persuade them to keep quiet so you both get paid.
  • You could come up with a fix, but build issues cause it to not get tested.

I think that every-so-often, you do need to analyse the list of bugs you have, and try and clear it down; either by fixing them, proving they are obsolete, or maybe just marking them as never intending to fix. A dedicated period of time is required but I would have thought a 2 week period is required at minimum in order to not cut corners.

YAGNI / This Code Could be Useful In The Future

I remember the days of being a junior software developer where you write code because “it might be useful at some point in the future”. The thing is, this means you end up writing way more code than is necessary, and could lead to overcomplicated designs.

There is a concept called YAGNI: “You Ain’t Gonna Need It”

Swizec sums this up well here with a strong hint of sarcasm…

And that brings us to the other YAGNI: Building stuff you think you’ll need before you need it.

You think of a wonderful abstraction. A wonderful little feature that’s gonna help oh so much in the future.

You build it.

Months pass. You tweak the code here and there. Nobody’s using it, but you have to maintain otherwise it’s gonna break. Whenever you implement a feature, you have to think about how it impacts this code you’ve got.

It’s slowing you down. Making you think. And you aren’t even using it.

But one day! One glorious day, your PM gives you a task. A task from the gods. You are about to use this code you predicted 6 months ago!

You are a god of prediction! You knew it all along!

https://swizec.com/blog/dry-is-a-footgun-remember-to-yagni/

A simple example I came across recently was this:

public static bool IsModalDialogOpen()
{
  Boolean isModalDialogOpen = Application.AnyModalDialogOpen;
  if (isModalDialogOpen)
  {
     throw new DialogException("A dialog is already open");
  }
  return isModalDialogOpen;
}

So they have written a method that checks if a dialog is already open. If there is, then an exception is thrown (depending on their error handling, it would either crash, or display some kind of error to the user), otherwise it returns false. Since this is new code, the only places that called this method was in his new code. However, he never checked the return value of the method. Since it is defined as a Boolean/bool then it could only return true or false, but his logic only ever returned false… and all the calling code never used the value. Our exchange went like this:

Me: Why do we have a return type for this method when the return value is not used above?
Developer: If any one in future want to know the value it will be useful because of that I have added.
Me: https://rules.sonarsource.com/csharp/RSPEC-3241
       Also: it will never return true
Developer: OK, removed the return type.
Me: It needs an appropriate method name now

So at first he says it will be useful in future – which is definitely false – YANGI definitely applied in this situation. Then when he agreed that the boolean value wasn’t useful, he left the method name as IsModalDialogOpen which implies it should return a boolean. In the end, we were left with this:

public static void ThrowExceptionIfModalDialogOpen()
{
   if (Application.AnyModalDialogOpen)
   {
     throw new DialogException("A dialog is already open");
   }
}

In another recent change, there was this humorous exchange between two Senior Developers, George and Paul:

George
This looks like dead code...

Paul
Yes on the off chance it was used, we now redirect to the new stored procedure

George
How did you test it?

Paul
We spoke to the Data guys and they said it wasnt used, so no testing required. I am sure.

George
So you leave it in case it is used, but don't test it because it isn't?

Paul
Yes sort of. In case this was ever ressurrected the change was there for them to use

George
It won't be

So Paul had been migrating a database “into the Cloud”, and so went through all the features where that old database was used. He found some old code which he believed to be obsolete, but made the change there anyway. George then flags it up, and Paul says he changed it just in case it was actually used, even though other developers also agreed it wasn’t used. He didn’t test it because it wasn’t used, but the code is there if someone decides it should be used, but it might not actually work because he never tested it.

You could make a variation on that Swizec quote at the start of the blog. It’s extra code that you have to maintain and slows you down, but the day that code is finally used; Paul has saved people time! (Apart from all the developers who will end up looking at the obsolete code in the meantime).

Coding Tales #1

I haven’t written many blogs talking about code for a while, but my notes are stacking up; so time to post some blogs discussing code! I’ll try to explain them the best I can for the non-programmers, or those that find C# hard to understand.

There was one bug fix where the developer took several attempts to fix it. Taking several attempts to fix a bug illustrates that you either – don’t have a good understanding of:

  • the requirements,
  • or the codebase that you are changing.

If you make a change and it introduces a bug, then you make another change and it introduces another – instead of playing “whack-a-mole”, it’s worth considering if you are actually writing the correct fix. From my experience, you can often just take a step back, ask for help, and come up with a much simpler, and less risky fix.

In one of their changes, I saw evidence that it was possible that they didn’t understand what they were changing, or taking care in their work.

case ParentRecordRelationship.Grouped:
//when a record is grouped, the associated text is NOT altered - so this method should not be called
   throw new ArgumentException(string.Concat("Invalid parent record relationship supplied: ", parentRecordRelationship));

So we have a comment, explaining that the existing requirement is that the “associated text” is not modified, so it is completely invalid to call this particular method which would change the associated text (other code not shown). Therefore, we throw an exception which would cause the system to show an error to the user.

The developer changed the code to this:

case ParentRecordRelationship.Grouped:
    newAssociatedTextValue = CreateAssociatedTextValue(string.Format(_groupedWithFormatText, parentrecordOriginalTerm));
     break;
//when a record is grouped, the associated text is NOT altered - so this method should not be called
//throw new ArgumentException(string.Concat("Invalid parent record relationship supplied: ", parentRecordRelationship));  

So now he has allowed the text to be updated in this situation. Unless that really is a change in requirements, then this is the wrong thing to do. Also, instead of deleting the code that throws an exception, he has just “commented” it out (which is why it now shows in green), and also left in the actual comment saying that this scenario is invalid; which now adds to the confusion when the next developer reads it.

To me, that shows that the developer is uncertain it is the right thing to do, otherwise you would remove the comment and the code. Just “commenting” the old implementation out basically acts as a reminder that you might want to restore it. (You could easily just look at the history of the file to see the old code anyway, it isn’t like it is lost if you actually delete it in the first place.)

He also added to the confusion with this change

//take the 1st 12 characters of the format text
itemValueStartsWith = _combinedWithFormatText.Substring(0, 12);

it is now

//take the 1st 12 characters of the format text                      
itemValueStartsWith = _combinedWithFormatText.Substring(0, 9);

This is a good example of why writing comments for simple code is bad. The comment explains a requirement that it should take 12 characters, but you can see that it takes 9.

To me, this shows a lack of care, and lack of attention to detail – which are basic traits that I think are important for good software developers.

T-Shaped Engineer

Recently, I came across a new jargon term, the T-Shaped Engineer. I think the general idea is that you used to have a “specialist” or a “generalist”. Now the perception is that it is good to have a compromise between them.

A generalist is like the adage, “A jack of all trades, but a master of none”. You learn new technologies but not achieve a deeper understanding – since mastering anything requires you to dedicate massive amounts of time to the craft. When challenging work needs to be done, engineers with deeper knowledge are needed; aka the specialist.

Specialists devote their time to a narrow set of technologies. They probably don’t learn the newest technology unless it falls into their specialist domain.

Work was often prioritised based on what resources were available. If a feature required more developers with a certain skill-set, and they weren’t available, then the development had to be postponed. If the company hires more developers with the required skill, when priorities shift, you can end up with spare/unassigned developers. This was a hard balancing act for the Product Managers. Sometimes, the developers could end up being asked to take tasks they wouldn’t normally do.

This has led to a new kind of engineer – the “T-Shaped” engineer. This describes a person whose knowledge distribution looks like the letter T. The horizontal line represents a broad knowledge in multiple areas, and the vertical one represents a specialisation of a topic.

From I-Shaped to T-Shaped – Why DevOps Professionals Need to be Multi-Skilled

Theoretically, having a full team of T-Shaped engineers with their own specialisation means that work can be prioritised. Whilst they may have a broad general knowledge, managers need to remember they can’t perform exceptionally everywhere. The concept isn’t a silver-bullet.

If “Pi-shaped” and “comb-shaped” developers exist, then you would think those would be the developers to hire. I suppose if you do find them, then they will be rare and demand large wages.

References:

What are T Shaped People? Youtube video

https://alexkondov.com/the-t-shaped-engineer/

https://www.devopsinstitute.com/from-i-shaped-to-t-shaped-why-devops-professionals-need-to-be-multi-skilled/