Blog

Advice for business people working with software developers (understanding what developers actually mean)

As a veteran software developer who understands both how software developers think and operate, as well as the positioning of business folk, I often seen the following situations arise and the disconnect that never seems to be addressed.

This article is written for business folks who work with software developers.

 

When a software developer says something is “easy”.

Software development is not easy. Ever!

It is a complex, complicated, time consuming process. This is the truth.
Any developer who disagrees with it is either a savant genius (doubtful), lying (not very likely), doesn’t yet have enough experience to understand (likely), or hasn’t “stepped out of their shoes” to properly think about it (most likely).

So when a developer says something is “easy”, what they really mean is:

Based on what you’ve told me, it sounds like I need to do something I’ve previously done, or it’s something I’ve learnt about, which I’m confident I can do without a much extra learning or mental effort.
And I’m just going to ignore for now anything that can trip me up in the process.

A couple of things to know about the “common software developer” and the software development process:

  • Developers are optimistic. Personally I think it’s part of the nature that makes them a developer. It’s a “can do” and “anything is solvable” attitude that drives them to find solutions and innovate.
  • There many of unpredictable things that can, and quite often do, go wrong. Such as:
    • A single character typo that takes half a day or a good night’s sleep to find.
    • A software dependency changes and breaks everything.
    • What seemed like a simple approach doesn’t work.
    • Implementing it is more complex than first thought.
      There are many, many more variables and conditions that need to be considered than were evident in the initial brief.
    • After building the thing it doesn’t work as expected. Or performance is nothing like expected.

And we also have to keep in mind if the person saying “it’s easy” is also the person who has to do the actual work.
Are you asking an architect with 20 years in the industry (and who may also be out of touch with the actual tooling and development process) while a developer just out of university is the one tasked with implementation?
Conversely, are you asking junior developer without experience yet?

Finally, many developers don’t like to say “no”, disappoint a boss/senior, or appear to not know what they are doing.
Many developers also fear for the security of their jobs, and by extension saying something is “not easy” can show weakness in their ability.

It is my belief that “it’s easy” is one of the primary reasons software development projects fail, in part because the question of “how hard is it?” is also the foundation for my next point.

 

When a software developer gives you a time estimate.

The golden rule of software development estimation is:

Multiple by 2.5

This is not in any way a joke or exaggeration.

Software developers are optimistic, shit at estimates (see the discussion above) and, my personal belief, we very quickly learn to estimate based on what we learn the business “wants to hear” vs what we really know to be true (let’s face it, most of the time the business is going to be pushing for an externally driven deadline regardless).

I’ve been estimating for 20 years and I still regularly get it wrong. Estimation is hard. There are so many unknowns and unpredictable external influences we have to contend with.

Unless you are absolutely confident the person you ask padded the estimate, then as a business person any estimate you receive from a developer should be multiplied by 2.5 for an accurate idea of how long it will take to implement.

Now, a crucial point on this is the word “implement”, which means “the time required to spend working on the task” (i.e. working hours).
It does not mean “it will be finished in that amount of time after it is started”.
It is not a delivery time.

When working on a task, a huge chunk of software development is more than just writing new code. It is:

  • Thinking.
  • Scrapping or changing what’s already been built.
  • Integrating into a larger project (and often having to make cascading changes across the project).
  • Testing.
  • Researching.
  • Discussing with colleagues.

A note on “testing”: Developers will not factor in time for testing in estimates, almost guaranteed.

On top of that, anything but the smallest task cannot be completed in one sitting.
Even a task that can be finished in 4 hours will need to split split over multiple days, to take into account time to think, time to test (especially if other teams are involved), general interruptions, and meetings that come with working in a business.

One final tangential but related point is around asking for progress updates.
There are a few of things to think about when asking for an update:

  • Be clear about whether you are asking “how much of the expected time is taken” vs “how much of the feature is complete“?
    Unless you ask specifically for a time based answer, assume the answer will be in terms of feature completeness and expressed as a relative value, either a percentage (e.g. 80%) or a vague “almost done”, “half way”, “only just started”.
  • A percentage of feature completeness is not proportional to the time taken.
    • A task that is 80% complete does not mean “80% of the time is used”.
      Nor does it mean the remaining work should take only 25% more time (math lesson: 20% of 100% is 25% of 80%).
      Many tasks can reach 80% complete in just 20% of the estimated time (and some can take 250% of the remaining time to complete).

Above all, NEVER hold a software developer to an estimate!

Dr Evil: We'll ask for estimates and treat them as deadlines.

It’s a well known joke in the industry, but it’s also a reality (I’ve been subjected to this many times over my career) and it is, to put it quite bluntly, a fucking toxic approach at will destroy your credibility with the very people you rely on.

Hopefully by now you realise why an estimate cannot be considered a deadline.

On the matter of estimates vs deadlines, here’s the best approach to take:

If you have a deadline that must be met, set it upfront and only use estimated for approximate planning.
Estimates are otherwise worthless in this scenario.
Instead, make a call on “feature completeness”, “quality”, resources working on the solution, budget, and what other work can be dropped.
And always assume when hitting deadlines developers are going to work at least 25% more hours than a standard work day.
(The only think more stressful to a developer than an estimate, is a deadline.)

Otherwise, if you want an estimate then treat is as a “rough idea”.
Assume the plan and schedule will change.
Don’t create any business critical plans against it.
And ensure the work is not part of something that has deadlines.

 

Bonus: How many hours can a software developer work behind a keyboard?

Software development is hard work.
It’s mentally and physically exhausting and requires a lot of stamina, especially over a long term, and especially of a term of sustained effort.

My rule of thumb is:

In a standard 8 hours work day, assume a maximum of 6 hours behind the keyboard.

That’s an absolute maximum. It’s not going to be every day. And that’s if you want quality work.

Remember to factor in things that take people away from the keyboard:

  • Meetings
  • Planning sessions (eg. at a whiteboard).
  • Coffee breaks and water cooler chats (essential for workplace productivity, and often a source of ideas and inspiration).
  • General break to clear the mind.

But software development is not about being behind a keyword and writing code. A huge percentage of it is thinking and learning/research.

Software development is not factory line work and cannot be thought of the same way in terms of output. It is creative and analytical.

And not every day is going to be the same.
Some days a developer will be in “flow” (a mental state when they are churning out code in a easy, satisfying way).
Some days personal life may be making them a bit flat.
Some days they will be battling technology gremlins.
Some days in their flow they will punch out a solid 10 hours of work.
The next day they’re fried and admin tasks or a bit of learning is the best you can hope for.

Software developers are people.
Not machines.
Not “resources”.
People with brains and bodies and lives like everyone else, who have the same ebbs and flows and worries and energy as everyone else.

An approach to handling long lists in Vue.js (2.x) (hint: Vanilla JavaScript)

Vue.js is an excellent front-end web application framework and my framework of choice.

However, one area where it falls down is rendering long lists. Typically, I experience issues when a list has over 1,500 times.

My understanding is the problem revolves primarily around reactivity of properties and how that impacts rendering. I can’t remember the technical details but a Google/Bing search for “vue.js render long lists” will soon provide StackOverflow answers that explain it better than I can.

I also get the impression that long lists is not a common problem in most web applications. Unfortunately, my development for Lotus has me needing to render a few very long lists for back-end reporting and debugging. A typical timesheet (the core business of Lotus) can include over 2,000 (and sometimes up to 4,000) data records which need to be rendered in a single, continuous (un-paginated) scroll list for analysis.
And we now have a couple of internal reports that can include up to 10,000 items.

Ideally some of these reports will be eventually re-architected to include either pagination or better sub-filters. For now it’s a matter just making them available for viewing and download, so the long-list problem is one I need to contend with.

 

My Approach: Vanilla JavaScript

Earlier attempts to remove Vue.js reactivity via Object.freeze() (after following per blog and StackOverflow suggestions) didn’t seem to improve performance. I don’t know why, and I don’t have time to dig into it.

So I came up with a simpler solution that simply cut out Vue altogether: I used plain old vanilla JavaScript.

Now, an important factor to remember is: once I’ve rendered a list, I don’t need to update it again. So reactivity and and event binding are not a concern for me in these situations.
Well, that’s not quite true. In once instance I do need to update a CSS class based on a click event in a table row, but that too was handled easily with Vanilla JS (explained below).

Rendering is super simple.

1. Create a target element with an ID in your app/component, like this: <div id="vanillaJsRender"></div>

2. Load your data in your Vue app/component as normal, then create a Vue component method to call after the data is loaded, that iterates over the data, generates a string with your HTML to render, like the following simple example:

var html = "<ul>";
for (var i = 0; i < data.length; i++)
{
    html = html + "<li class='row-" + data[i].ID + "' onClick='onReportResultsRowSelectVanillaJs(" + data[i].ID+ ")'>" + data[i].MyValueToDisplay + "</li>";
}
html = html + "</ul>";

3. The insert the HTML into the target element like so: document.getElementById("vanillaJsRender").innerHTML = html;

It’s not pretty, but it’s simple and it works. And render is much, much, much faster than a Vue v-for loop.

Something I’ve noted with this approach is scrolling 10,000 records with of rendered HTML still causes some level of lag in the browser, though to be expected, and it’s manageable and not at bad as the Vue-based alternative.

 

Binding click events/updating CSS classes

Note the following class='row-" + data[i].ID + "' onClick='onReportResultsRowSelectVanillaJs(" + data[i].ID+ ")' added to the <li> in the sample above.

If I want to apply or remove a CSS class to a row in the HTML rendered outside of Vue, I just need a function like the following within the standard <script> section of our Vue app or component.

//-- Vanilla JS onClick handler
window.onReportResultsRowSelectVanillaJs = function(id)
{
    // Vanilla JavaScript to add/remove the `selected` class on the row
    var row = document.querySelector('.row-' + rowId);

    if (row.classList.contains("selected"))
    {
        row.classList.remove("selected");
    }
    else
    {
        row.classList.add("selected");
    }
}

Again, we’re using Vanilla JavaScript to manipulate the DOM and it works fine alongside Vue.

Note the window in window.onReportResultsRowSelectVanillaJs. We can’t simply define a function onReportResultsRowSelectVanillaJs() { ... } because the scope is not global. We need a globally scoped function (hence the attaching to window) for it to be accessible via onClick.

Just remember to name the function something that won’t cause potential naming conflicts in the global namespace.

I could have bound the function to the target element via a DOM addEventListener() method, but the way I did it was simple and it works perfectly well for my situation.

 

Another Approach: Server-Side Rendering

Before trying the above JavaScript approach I also tried generating the HTML a server-side.

To be clear, the app is a very clearly separated HTML front-end that is driven entirely by Vue.js, and backend that is pure API and ordinarily performs no HTML rendering (e.g. it’s not an MVC web application).

So in my server-side rendering approach, the API that is called would normally return a set of structure data but instead returns a string that is the HTML to be injected into the page. Again, the injection is performed via document.getElementById("vanillaJsRender").innerHTML = html.

Why take this approach? I come from an old-school web application background where all HTML used to be server side rendered, so this is always an option. And recently I’ve been revisiting blogs and talks by DHH (David Heinemeier Hansson) and has reminded that rendering on the server is often a fuck load faster than in the browser.

Also, why not?

 

Conclusion

There’s no profound conclusion. I simply took other experiences and thought a little ways out of the box (the Vue box) to solve a problem.

The solutions may not be elegant to some people but they’re simple, they work, and they solve the problem, which at the end of the day is what we’re all about as software developers.

Twitter Thread: Ranting about “right” and “wrong” architecture

I just posted a Twitter thread (a short rant, really) about software architecture, patterns and practices, and the “right” and “wrong” way.

You can find it at https://twitter.com/GDayJason/status/1359409433521004547.

But here it is in it’s entirety as well. Double-line spaces show the break between each Tweet.


I’m doing some .NET Core training on Pluralsight and along the way diving into REST API architecture and other related topics.

The thing that really shits be about architecture discussion and training is all the “you should do X” but no one EVER explains WHY!

 

 

If you’re going to write a document or build a training course that states a right way and wrong way, then explain why.

Why should I listen to you otherwise?

Give me pros and cons and concrete examples I can learn from. Help me “understand” to make good decisions.

 

 

But once again, I come back to a point I often make: “Most patterns and practices in software development are just MARKETING.”

They’re the opinion of one or a handful of people who decided how something should be done and wrote a book (or thesis) on it.

 

 

Oh, the ideas might have merit, but don’t been fooled by a flashy cover or title known to all.

These ideas are conceived and written by people just like you and me.

The danger we then face is new and good ideas are poo-pooed with “that’s not how it’s done according to X”.

 

 

Here’s the thing: “Today’s best practise is often tomorrow’s anti-pattern”.

Or it might still be a good practise, but other ideas have come to play as technology evolves.

 

Here’s the thing: “Today’s best practise is often tomorrow’s anti-pattern”.

Or it might still be a good practise, but other better practices have come to play that reflect the evolving technology.

 

 

There’s space enough for different ideas. Including ideas the CHERRY PICK from multiple practices to best fit the situation.

 

 

There’s space enough for different ideas.

Including ideas that can be picked from multiple practices to best fit the situation.

 

 

At the end of the day there is one, and only one, thing that truly matters:

The software solves a business problem.

Yes – maintenance, testing, readability, etc. But none of that matters if the product isn’t solving a problem AND being used.

 

 

But this is just my opinion.

I don’t do conference talks. I haven’t written a book.

I just have 20 years working with a lot of projects and solutions – some mine, many inherited.

And if I had a dollar for every time I saw something done the “wrong” I’d be well retired now.

 

 

And the #1 thing every single “wrong” solution I worked with did right?

It solved a real business need.

(And most developers could happily keep it running.)

Adding Rollbar to ASP.NET Core 2+: “Some services are not able to be constructed” and “Unable to resolve service for type ‘Microsoft.AspNetCore.Http.IHttpContextAccessor'”

I’m adding Rollbar to a new ASP.NET Core 5 (which is Core 3+) API and following the guide at https://docs.rollbar.com/docs/integrating-with-aspnet-core-2-and-newer.

After adding the required code I received the following exception when starting the API:

System.AggregateException
HResult=0x80131500
Message=Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Rollbar.NetCore.AspNet.RollbarLoggerProvider Lifetime: Singleton ImplementationType: Rollbar.NetCore.AspNet.RollbarLoggerProvider': Unable to resolve service for type 'Microsoft.AspNetCore.Http.IHttpContextAccessor' while attempting to activate 'Rollbar.NetCore.AspNet.RollbarLoggerProvider'.)
Source=Microsoft.Extensions.DependencyInjection
StackTrace:
at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(IEnumerable`1 serviceDescriptors, IServiceProviderEngine engine, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
at Microsoft.Extensions.DependencyInjection.DefaultServiceProviderFactory.CreateServiceProvider(IServiceCollection containerBuilder)
at Microsoft.Extensions.Hosting.Internal.ServiceFactoryAdapter`1.CreateServiceProvider(Object containerBuilder)
at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
at Microsoft.Extensions.Hosting.HostBuilder.Build()
at Lotus.API.Integration.Program.Main(String[] args) in D:\WorkspacesLotusAI\Management\Lotus.API.Integration\Program.cs:line 16

This exception was originally thrown at this call stack:
[External Code]

Inner Exception 1:
InvalidOperationException: Error while validating the service descriptor 'ServiceType: Rollbar.NetCore.AspNet.RollbarLoggerProvider Lifetime: Singleton ImplementationType: Rollbar.NetCore.AspNet.RollbarLoggerProvider': Unable to resolve service for type 'Microsoft.AspNetCore.Http.IHttpContextAccessor' while attempting to activate 'Rollbar.NetCore.AspNet.RollbarLoggerProvider'.

Inner Exception 2:
InvalidOperationException: Unable to resolve service for type 'Microsoft.AspNetCore.Http.IHttpContextAccessor' while attempting to activate 'Rollbar.NetCore.AspNet.RollbarLoggerProvider'.

A search for “Unable to resolve service for type ‘Microsoft.AspNetCore.Http.IHttpContextAccessor’ while attempting to activate ‘Rollbar.NetCore.AspNet.RollbarLoggerProvider’” lead me to answers at https://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc.

The accepted answer revealed “IHttpContextAccessor is no longer wired up by default, you have to register it yourself” with a sample services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>(); to be added in the ConfigureServices()  method of the StartUp class. Another answer points out “as of .NET Core 2.1 there is an extension method” that has been added to do the same thing: services.AddHttpContextAccessor();.

 

This is also yet another example of the craziness and breaking changes between the different versions of .NET Core. And while I’m thankful I’m only now making the jump from .NET Framework to .NET Core/5, it well highlights the difficulties developers face when entering the industry and looking up documentation, or when finally make a step up from earlier version – i.e. it looks like even steps from Core 2 to 2.1, and .NET 2 to 3 will give developers some unexpected surprises.

Swagger error in ASP.NET Core 5 MVC API Web App (MVC)

I created an ASP.NET Core 5 Web App for “API” (similar to MVC) with the OpenAPI (aka Swagger) option turned on.

To note: I have nearly 2 decades experience with .NET but this is my first real-world dive into .NET Core/5, so I’m skipping the whole “learning from first principals” and figuring it out as I go off the back of what I already know.
In this case I’m setting up a new project to move some part of an existing ASP.NET 4.6 MVC app into it.

It was all working fine until I wanted to add an OnActionExecuting() override to the Controller, from the IActionFilter interface.
Once I added the interface and the 2 required method the calls to the actual controller, calling the endpoints worked fine. But F5 debug runs of the project, which loaded the https://localhost:xxxxx/swagger/index.html page, would produce the error:

Failed to load API definition.

Errors

Fetch errorundefined /swagger/v1/swagger.json

 

Which in typical 3rd party framework fashion is fucking useless for consuming and gives use no useful information to work with.

So off to StackOverflow I go.

After a search for OnActionExecuting Fetch errorundefined /swagger/v1/swagger.json I came across this page: https://stackoverflow.com/questions/48450262/asp-net-core-swashbuckle-not-creating-swagger-json-file, specifically the answer https://stackoverflow.com/a/53632914/115704 which mentioned [NoAction]. Things then clicked for me.

The [NoAction] attribute on the 2 interface methods didn’t work for me, but after a bit more searching I found [NonAction] and which solved the problem.

Then I was back up and working with Swagger again.

 

 

Screenshots

Code before the fix

(Noting the [NonAction] is not impmented)

 

The error from Swagger

Honestly, how fucking useless is this an an error? About as good as the classic “an unexpected error occurred” (to which I always exclaim: “no shit, Sherlock!” Like any developer actually expects an error).

 

Code after the Fix

[NonAction] attributes have been implemented.

 

Swagger after the fix

And look, Swagger works again.

 

At the end of the day this was a couple of hours of my night lost.

Partly my fault for implementing a new version of .NET without doing the obligatory 40 hours of training. Also partly Swaggers fault because, well, it pissed me off for not giving a more detailed error message, especially in a development environment.

“Reading” is a struggle for me

Oddly, this is something I’ve never publicly mentioned before, nor have I randomly come across it in my own web searches.

But:

“Reading” is a struggle for me.

It is, quite literally, the hardest thing I do ever day.

And as someone who writes computer code for a living, and has to spend much of my life, every day, reading to learn and keep abreast of new development and news, it may seem surprising.

But when you think about it: reading is not a natural skill humans possess.

It is something people have to be taught, learn and practise.

And I believe (base on past reading, ironically) it is something that was once designed to separate classes of people.

I am not ashamed to say reading is a major difficulty for me.

Recall memory is another even bigger problem I deal with every day.

Ironically, I write a lot down to remember.

But have a great visual memory (and no, written words are not “visual”. I can’t tell you why, but it don’t correlate for me).
I have an “index” mind, meaning I know where to find what I have once seen quite easily.
And even though I forget nouns (especially people’s names), I never forge a face.

And I’m the the person strangers will approach on an intersection to ask for directions or help.

All this to say: it’s OK to struggle with so-called “simple every day tasks.

The people who truly master reading – especially fast reading – are rare.
They also master high skilled jobs, like: lawyers; politicians; scientists (?); certain types of information workers.
But they are the exception we hear about, not the rule.

The rest of us struggle.
Every. Single. Day.

I call it “brute forcing my way through life”.
We may look smart.
We may look like we know what we’re doing.
But it’s brute force and adaptation that makes it look that way.

Reading is hard.
Learning is harder.
Both are learnt skills.

Accepting and figuring out how to adapt will set you free and give you a hand in stay ahead.

Parcel.js “ENOENT: no such file or directory” on build

Problem

Running Parcel.js build command (e.g. I run `npm run dev` script) to build and start the site with generates an error similar to the following:

D:\Workspaces\my-project\my-folder\my-file.vue: ENOENT: no such file or directory, open 'D:\Workspaces\my-project\my-folder\my-file.vue'
Error: ENOENT: no such file or directory, open 'D:\Workspaces\my-project\my-folder\my-file.vue'

Solution

Delete the .cache and dist folders and re-run the build command.

References

https://stackoverflow.com/questions/59196917/parcel-bundler-enoent-no-such-file-or-directory-when-delete-files-from-projec

Feedback to Microsoft Teams

Sharing some feedback I provided within the Microsoft Teams app.

Hello,

Just wanted to give a few thoughts after a couple of months of using Teams.

* It would be great to separate “Chats” with individuals from groups.

* It took me a couple of minutes to figure out how to start a new chat with someone in the desktop app – the little icon up the top beside the search bar is out of context of the existing chats, and “blends in” to the background.

* Not having threads in a conversation (ie. replies to a specific comment) is a big pain in the backside. I’m forever chatting across multiple ideas and tracking what is being replied to gets problematic.

* You really need to include the standard emoji set. The old Skype for Business emojis are good not nowhere near enough. And the “Emoji One” integration is half-baked. I only stumbled on it by typing “:th …”, but it has no search, and typing “:P” automatically inserts the Skype “tongue out” icon. It might not seem important, but our team is quite expressive with emojis.

Maybe it’s because I come from using Slack for 4 years, but Teams doesn’t feel as simple or slick. Sorry to say it, but you really need to up the game to compete with Slack, especially now in a highly remote workforce.

Are you a Microsoft Teams user? What are your thoughts and gripes on the usability of the application?

In a rare occurrence, I’m opening up comments on this post.

UPDATE – 4 OCT 20202: Comments are closed. Too much SPAM. Sheesh, 2020 Internet people suck.

Limoncello Recipe

This is mainly a note for myself to quickly access the Limoncello recipes I’ve been using.

 

I’m currently resting my first Stage 1 jar: