Thursday, November 21, 2024

Open a web page when a project can't be built

When writing the Uno book, we wanted a way to have the project fail with a useful message if a required dependency hadn't also been set up correctly.

Below is what I came up with.


<Target Name="CheckForSfChart">
    <Exec Condition="!Exists('..\..\..\syncfusion-Uno.SfChart\Src\Syncfusion.SfChart.Uno.csproj')" Command="cmd.exe /c start https:////github.com/PacktPublishing/Creating-cross-platform-applications-with-Uno/tree/main/Chapter6/readme.md" />
    <Error Condition="!Exists('..\..\..\syncfusion-Uno.SfChart\Src\Syncfusion.SfChart.Uno.csproj')" Text="The SfChart project is also needed. See https://github.com/PacktPublishing/Creating-cross-platform-applications-with-Uno/tree/main/Chapter6/readme.md" />
  </Target>

See the real thing in GitHub.


If the required other project is missing, it:

  • Opens a webpage with more details.
  • Outputs a message with details in the build output.


Points of note:

  • Yes, msbuild will fail to compile the solution with missing project anyway. This is just additional info to help in debugging.
  • Repeated slashes in the url ("https:////" instead of "https://") due to them assumed to be being escaped
  • Because this call cmd.exe, it will only work on Windows.
  • Not a perfect solution but better than nothing.



Documenting this now before I forget.


The lack of a visual designer is actually offensive

One of the biggest complaints and requests relates to a lack of a "visual designer" for creating UIs with XAML for WinUI3 and .NET MAUI applications.

For a long time, Microsoft had no plans to build one. Although that may be changing...

There are other, related tools that they are working on but are not the designer people are asking for.

I've even heard it said (by people who are employed by Microsoft) that "these tools are better than a designer so you don't need one".

That's what I find offensive.

The claim that MS know what people want better than they know themselves. And, the implication that people are wrong about what they say they want. More importantly (and concerning) is that I don't think MS are listening to the "real" request. 

Yes, the Hot and Live tools are great for working with existing code when the app is running, but there's also a need to help with a completely blank app (or page, or window...)

There needs to be a better way to help people get started and give them confidence that what is in the source is correct before they start debugging (or even compiling?) the code.


I have worked with people creating drag-and-drop-related tools for XAML UIs, so I know what's possible and how hard it is. That's also why I'm not trying to build one myself.

I think there's another way. It's not necessarily better at first look, but it's certainly very helpful, powerful, and able to offer more productivity than arguing about why something that isn't what people are asking for isn't what they want or need.



Logging in Testing

Once upon a time, I was working with a codebase that contained significant and detailed levels of logging. It supported recording multiple loggers and various levels of details, depending on the required "LogLevel".

While looking at how this code is (and can be) tested, I made a discovery that I hope to bring to many other projects in the future.


Taking a step back, there are a few broad questions to think about in terms of testing and logging:

  • Ignoring logging, does the code do everything it is supposed to?
  • Are the correct things logged when they should be?
  • Does the code do everything it should when there are no loggers registered?
  • Does the code do everything it should when there are one or more loggers registered?
  • Are we sure that any exceptions in the code are not logged and ignored?
  • How does logging code affect the code coverage of tests?

I started thinking about this only when having to deal with a "weird" bug that meant functionality appeared to be working, but the lack of a logger meant a code path failed silently as it was configured to quietly log the exception and then do nothing. :(


My solution: add a wrapper around all tests so that they're run multiple times, with different test-specific loggers attached.
  • One test execution had no loggers attached. (To find code that was unexpectedly dependent upon always having at least one logger.)
  • One test execution with a logger that listened at all levels but did nothing. (To verify that the presence of a logger had no impact on correct functionality and to ensure that all logging code paths were followed.)
  • One test execution with a logger that would cause the test to fail if an error or exception was logged. (Because we shouldn't log errors as part of normal execution.)

This was all on code that ran hundreds of tests in a couple of seconds.
The impact of running multiple times was negligible.
The fact the total number of tests went up considerably was nice. (It also helped people reluctant to write tests feel good as every test they did write was now counted as three, so they felt more productive.)
This gave us more realistic code coverage reports, as the logging paths were now included in the coverage. (Previously, logging code wasn't--mostly--covered, making it harder to identify areas with particularly low coverage.)


Tests for logic, specifically about the loggers or reliant on specific logging behaviour, were put in classes that were excluded from the above.

Adding those different test scenarios found more issues than the one that led me to the original investigation.

I'll definitely do this again.

It's also good to have all these different test and logging combinations configured early in development. Hopefully, by the time you think development is finished, there shouldn't be any exceptions being thrown. It is hard to verify that nothing bad happens when an exception is thrown (and logged). You don't want the handling (logging) of an exception to cause another exception and end up in an infinite loop. These things can be hard to check for, but I've found that having all the different logging combinations available (without me really having to think about them) has made it possible to catch some logging issues I might otherwise have missed.

How do you name "theme" level resources?

This would have been a social media post, but it quickly became too long.

If you have some software that:

a) Has a specific color (or colors) that is (are) used for branding reasons.

b) Adjusts to "light" and "dark" themes.


I have some questions:

  • What do you call that (those) color(s)? 
  • Do you have different versions of those colors for when in a dark or light theme? And if so, how do you name them?

I've seen lots of variations in the ways the above are answered, but no consensus.





Monday, November 18, 2024

Here's how I wasted $249 on code signing, so you don't have to!

I don't have positive experiences with code signing.

As of today I have another tale of confusion, frustration, anger, disappointment, and expense.


I'll try and keep this to just the facts, so I don't let my emotions carry me away:

  • I sign my VSIX (Visual Studio extension) and NuGet packages with a code signing certificate.
  • I use a hosted Code Signing solution from DigiCert.
  • Their certificates are initially limited to signing 1000 files per year. (Additional issuances are available for $249 for another 1000.)
  • I got through my initial thousand MUCH faster than I was expecting.  
  • I found out I'd used my allocation when signing suddenly started failing.
  • It turns out that, when signing a .vsix file, the default behaviour is to also (first) sign all the files inside the package and then sign the package as a whole.
  • Even if the internal files are already signed.
  • Regardless of where the files in the package are from.
  • So, when I thought I was signing one file, under the hood it was signing many more.
  • In some cases it was signing 30-40 files each time.
  • In the past I bought the certificate, installed it on my build machine and it didn't matter how many files I signed a file (or multiple packages in a file.)
  • Now that everything is a subscription (and especially for expensive ones), it becomes even more important to understand how the things you're using work and you may end up being billed for using them.
  • No, the documentation on this is far from extensive, clear, or useful.
  • I worked out the solution based on the description here "Some artifacts are containers that contain other signable file types."
  • Then I found the setting `--filelist` in the documentation at https://learn.microsoft.com/en-us/visualstudio/extensibility/dotnet-sign-cli-reference-vsix?view=vs-2022#options 
  • I've now updated all my signing scripts to only sign what's absolutely necessary. As an example see this commit.



Not mentioned: dealing with DigiCert support and how they made it hard for me to pay them money to buy more "issuances". :'(