Saturday, April 29, 2023

What if your XAML code was much simpler?

Over the last 6 months, I've given talks at a dozen user groups and conferences. 

In those sessions, I've discussed some of the thinking and experimentation I've done over the last couple of years, exploring ways of improving how we think about and work with XAML.

With each talk, I've refined and expanded my thoughts based on feedback and discussions with attendees immediately afterward.  (Yes, I'm prepared to drive 4 hours each way for the chance to talk about XAML--I get it; that makes me an outlier.)

<simple:XAML Is="Possible?" />

I've been reluctant to share too much detail while I refine how I communicate these ideas. 

I can spend an hour talking about how C# best practices can be applied to XAML and how it makes a massive difference to the code you write, but no one wants to read that. (Please tell me if I'm wrong.)

I can also show you how I can take even a relatively simple XAML file and massively reduce the complexity. But the difference is so big it's easy to miss all the changes and understand why the differences are there.

As I start to work out how I can best share these ideas, I'm putting together small videos and pieces of writing to explain the differences and the tools I've made to help.

Here's a short video demonstrating one such tool that I released on my YouTube channel this week.

>

I'd love your thoughts on the video, and on the tool if you try it.


Thank you ElektroStudio for helping spread the VB love

I've built more than a few Visual Studio extensions.

Most of them only work with C# code.

I'd like to support VB.Net in more of them, but other priorities get in the way.

Const Visualizer is one that hasn't had the love it could have. It's really useful in some instances, but I haven't found the time to address the things about it that niggle at me when I use it.

Given that I haven't found the time to add the C# related fixes I want, you'll not be surprised to hear that VB support wasn't high on my priority list.

So, when I was asked about adding VB support, I had to acknowledge that it was only going to happen if someone else contributed it. Thankfully, ElektroStudios did just that, and now version 2 is in the marketplace with C# & VB.Net support.

I know that many people still use VB every day and that some of you even look to me for advice and tools on building with it. I wish I had more time to focus on supporting it, but maybe if more people contribute some of the work, we can build better tools for VB development together.

Whatever happens, thank you, Elektro, for your contribution.



Wednesday, April 19, 2023

global (and implicit) using directives - but for XAML?

One of the great things about .NET 6 and C# 10 was the introduction of global and implicit using directives. Namespaces that could be defined once and then made available to all C# files in a project.

These small features simplified code by reducing the boilerplate and noise at the top of each file.

As part of my exploration into how XAML files could be made better, I've been looking at whether something similar could be done and whether the duplication at the top of each file could be removed.

The top of a XAML file with all the namespace aliases highlighted
The five highlighted lines in the above image (and many like them) are in almost every file. I even have some files with many more aliases defined. 

These lines add noise and distraction. Plus, inconsistent use of XML namespace aliases across different files can become confusing and lead to errors and unexpected behavior. 

What if we could have all the namespaces (and aliases) defined in a single place and available to all xaml files in a project? With a file like this:

File showing just the xmlns statements from the first image

I decided to see if I could make this possible.

Because I have previously spent time looking at the internal .NET MAUI code relating to XAML files, I started there.

In theory, this idea is applicable to any flavor of XAML, but I wanted to start by creating a working example of what I was thinking as after having talked to hundreds of developers about thinking of XAML in different ways, I know that many have a hard time even considering something different to what they've always done. I hoped that showing what was (or could be) possible might help open imaginations more easily.

But it's not valid XML!

Before I started, I knew that there would be objections to this idea. 

I knew some would not like it because it is different.

I know some would not like it because it technically makes the document invalid. XAML documents are (or should be) valid XML documents and, as such, cannot use undeclared namespaces (and aliases).

I pressed on regardless. I knew it will make the document technically invalid, but I hoped that the benefits it might bring could outweigh this.
If going back to the C# comparison, a C# file that relies on namespace directives that are implicit or defined (globally) in another file isn't much good on its own, either. Similarly, a XAML file that is "valid" but makes references to types that are in other files is of limited use by itself too.
This wasn't enough to stop me.

Going through the XAML source, I soon discovered that XAML files are potentially read (and things done with them) in many different places in the code and in different ways. The small chance that this would be an easy thing to explore and experiment with quickly got smaller and dissolved away entirely.

But I pressed on.

My goal of showing a working example was quickly scaled back to be just the smallest proof of concept appropriate.

Rather than support multiple namespace aliases, I opted for just one. (xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml")


And I got there. 

Look, here's a file without the "x" alias defined, but it still works.

A small XAML document without the "x" alias defined but still used

I know you're skeptical.

After all, look at those blue squiggly lines under the code where the "x" alias is used.

It turns out they're coming from the editor. It's trying to parse the document too.

As soon as I saw how frequently the MAUI code processed XAML content as XML, I thought this could be a problem. I had an increased concern that there could be a lot of other tools and features that relied on XAML files always being valid XML documents.

As a simple example, here's the dialog I see every time I save that file.

Information dialog: --------------------------- Microsoft Visual Studio --------------------------- Error in StylerPackage:  'x' is an undeclared prefix. Line 3, position 5.    If this deems a malfunctioning of styler, please kindly submit an issue at https://github.com/Xavalon/XamlStyler. --------------------------- OK    ---------------------------

Very early on in my thinking about this, I did worry that additional tools needing to be able to process XAML files could be an issue. It quickly became a bigger issue than I expected.


I've looked at lots of code that works with XAML files (and written a lot, too), and the majority of it does treat XAML as XML and uses framework-provided functionality.
In fact, to get MAUI to treat my modified XAML documents as valid XML, I ended up having to add the missing namespace alias declarations into the document each time it tried to process them.

This wouldn't have been the end of the world if such a modification was needed in one or two places, but this isn't practical on a such a wide level. There is too much code (inside VS, frameworks, extensions, and other tools) that assumes XAML files will always be valid XML files too.

[Aside: I assume C# was able to add features such as global and implicit namespace directives as it is responsible for the entire toolchain that reads, parses, and complies '.cs' documents. Any 3rd party code that isn't using Roslyn/CodeAnalysis libraries to do the work has to take care of any special scenarios like this by itself, but I expect very few do. It's not like XAML which has been around for a long time and always supported files being treated as valid XML.]


So, my experiment was a failure.

In part.

I'd learned that this wasn't a practical thing to implement and that the impact on the wider ecosystem was almost certainly going to be too big for me to overcome.

Like all good experiments, I wasn't trying to do this. I was testing a hypothesis that it was possible and that it would be useful if it was.

I'd hoped to get to the point of starting a wider discussion on making global XML namespace aliases possible in XAML by showing that it was achievable. A discussion on how best to implement it while providing something that others could experiment with so they could experience the benefits is not to be.

But, as part of this experiment, I've become increasingly pleased by not having to look at all the noise the alias declarations add to the opening element of a XAML file.

Rather than remove them, what if they were hidden?

Well, this feels like a simpler thing to implement and with a much lower risk of side effects too.


Take a look at the following highlighted item. (It's in a WinUI3 project, but that doesn't matter.) 

A partial XAML file screenshot showing a new outlining node next to xmlns multi-line attributes

Yes, it's a new outlining node.

Guess what it can be used to collapse... or look below.

As with the above but all the lines containing xmlns declaraions ahve been collapsed behind a comment reading "[xmlns...]"

Isn't that nicer?


And for completeness, here's the original document from above with the 5 long lines all now collapsed behind one short placeholder. 

Partial XAML screenshot with 5 xmlns attributes hidden

I'll make this publicly available soon.

Of course, this doesn't address the duplication across files and the possibility of issues due to aliases being used inconsistently across files within a project, but I have separate ideas for addressing those.

But for that, and details of other ways to XAML can be improved (without needing to make changes to the frameworks being used,) stay tuned for future posts.




2 types of testing - but only 1 that AI can help with

A robot surrounded by text on computer screens

There's currently a lot of discussion about using ChatGPT (or other, similar, AI tools) to create unit tests for code. 

This has the opportunity to be valuable, but it's important to consider that there are two broad categories of tests when it comes to software. Each answers one of the following questions:

  1. Does the code do the right/correct thing?
  2. Does the code not do the wrong thing?

At first glance, you might mistake these for being the same. But there's a subtle difference.


Does the code do the right/correct thing? 

Does it do all that it's supposed to?

Does it correctly implement all of the requirements?

By only looking at the code, it's impossible to know for sure. Well-written code should provide many indications about what it should do, and wider knowledge of the application and the domain to which it relates can also provide insight but without knowing the full requirements, you can't know for sure.

If all you have is the source code, you must assume it's correct. Until you find something wrong or that needs changing.


Does the code not do the wrong thing?

Sometimes the requirements for an app might include a statement that "the code should not crash unexpectedly" or "the code should be secure." Often this is just implied. Who wants an app that crashes or is insecure? 

Fortunately, these are the kind of things you can test for without any wider knowledge of what the code should do. This is how they're different from the first kind of tests.

AI (& other) tooling can be a really good way of creating tests that try and break code. If it finds something, and you fix the issue, you get better (more reliable) code. But be wary of relying on such tests alone.

Yes, having more tests is generally better. But beware of relying on these tests for identifying regressions and the introduction of bugs in the future.

One of the great benefits of having tests is that they not only help you verify the code is correct now but also that it isn't accidentally changed in unexpected ways in the future.

Having tests that verify the code does the correct thing (produces the correct output given specific inputs) is good. But, of greater benefit is that the tests can verify that the code still produces the correct output if you need to modify the internal code. Tests that only make sure that the app doesn't crash, given particular inputs, aren't as valuable in the long term.

It might be great to say you have lots of tests and to even have high test coverage, but if they're not helpful as the code changes, are they really all that useful?



Yes, "it depends"

It's not as black-and-white as I've laid out above. There are times when AI might be able to generate useful tests of whether the code is doing the right thing based on the names and patterns it identifies in the code. Or comments in (and around) the code may provide sufficient context to generate useful tests.

Your mileage may vary when it comes to having a tool (AI-based or otherwise) generate tests for you, but I've always found thinking about these 2 types of tests helpful.