In 2014, at the VS Live in Chicago, Ben Dewey, a Microsoft MVP for Windows Client at the time, presented the session: XAML Anti-patterns. Not to be confused with Markus Egger’s excellent series with the same name in Code Magazine (also in 2014); Ben’s session had the playful subtext: The Seven Deadly Sins of XAML Development.
Between the two authors, they saw a regular set of common developer practices that harmed the efficiency and maintainability of XAML applications. In this article, I wanted to iterate those insights, consider the actuality of them, and review if they remain relevant to modern developers using newer, evolved XAML technologies and tooling.
Okay. Before I start, it’s only fair to confess I also, in 2014, took the Biblical approach to software, presenting The Ten Commandments of MVVM at Dev Intersections, writing a never-published blog of the same title.
Let’s begin with my 10 commandments, evaluate their value today, then do the same for the other authors so long ago.
1. Software delivery is job one
Still valid? yes, and it always will be
You might be surprised to sit at a table of architects hearing them argue: “bad code makes software useless”. I think the argument goes: with architectural debt, a code base cannot be maintained or enhanced. Though true, this axiom is teaching the goal of software is the product, not architecture. The test of a good developer/architect is their balancing those competing factors.
2. Reconsider MVVM altogether
Still valid? yes
Every design pattern has a certain cost. Sometimes the cost is in size: constraining resources to the app’s physical or memory footprint. Sometimes it is in performance: requiring more code for the sake of the developer’s convenience. These aren’t always wrong, but this axiom is teaching that design patterns, even MVVM, should be added with mindfulness, not blindness.
3. Choose MVVM for your own reasons
Still valid? yes
One common reason to choose MVVM is unit-testability. But, if we were to be honest, many development teams aren’t motivated to employ unit tests – for whatever reason. If the value of MVVM is for unit testing, then those development teams might also misperceive the value of MVVM. This axiom is teaching that patterns solve different problems for different apps; we aren’t all the same. MVVM solves unit testing for you, but something else for me.
4. Don’t build the model for the UI
Still valid? yes
This is specifically referring to the model in your service layer. Many developers surface their service models in their UI, and when a UI-specific property is required, they add it to their service layer model. I’ve done it, but have learned. This axiom is teaching that models in your service layer are for your service layer and your UI layer needs its own models – reuse feels like we’re working smarter but we’re really working so much harder.
5. Reference only in one direction
Still valid? yes
This is referring to your view-model, that it should not reference your view. It continues that your model would not reference your view-model, though your view-model references your model. This ideal not only keeps things clean, it also prevents hard-coupling that makes new, future features difficult and expensive to add. This axiom is teaching that in MVVM, the view sees the view-model, and the view-model sees the model - not the opposite.
6. Have only one view for one view-model
Still valid? yes
Some views are nested in other views and have their own reusable view-models. Every view has a view-model, but what do you do when two views are nearly identical? Should they share a view-model. The argument against shared view-models follows the reasoning that views today might change tomorrow, and a single view-model fakes a kind of polymorphism to support it. This axiom is teaching to go ahead, bite the bullet, and create those near-identical view-models for the sake of clarity now and an unforeseen future.
7. Use binding
Still valid? yes
It’s difficult to imagine a XAML developer not using binding. Without MVVM, it is less relevant, but you can still use it against the code-behind file. Binding and commanding allows you to declare your UI in the XAML designer, minimizing the need for raw, custom code – which will need to be tested manually. This axiom is teaching binding, like several framework features, should be your default approach, not custom-building one.
I would like to follow-up that binding is notoriously costly when it comes to performance, especially in WPF. But in UWP, compiled binding “{x:Bind}” was introduced to solve the performance issue. With RS3, or the Creators Fall Update, of Windows 10, compiled binding is basically in feature-parity with classic binding “{Binding}” and should be your default, when possible.
I would also like to follow-up that Commanding, which is an artifact of the binding pattern, allows developers to bind to the Click event of a Button, while maintaining two-way control over the Enabled property of the same Button. With compiled binding, developers can now bind events directly to a method in their view-model fundamentally calling into question the overhead of ICommand. In fact, you’d work hard to convince me to use it (in UWP).
8. User Experience trumps Developer Experience
Still valid? yes
Well, this one is a painful one. There is an inverse relationship between the user experience and the developer experience. As we discussed above, many patterns introduce some type of cost – a cost almost universally paid by the user. Some patterns slow the app, some complicate the interface, some increase hardware demand. None of these are developer inconveniences. This axiom is teaching that when you weigh the cost/value of any experience, the user experience is, by default, the most important experience in the equation.
I want to follow-up here with a snippet from another talk I give: The Most Important Goals of Software – things like performance, security, user experience, and scalability. Spoiler alert, the most important is User Acceptance. Here’s the reality: if your users hate your app, your incredible architecture, perf., or devops-process won’t change their minds. You’ve failed.
9. Discriminate against code-behind
Still valid? yes
Oh, the frustration when talking to a die-hard MVVM developer. It’s a jihad against code-behind, shaming apps with it, banishing developers who do it. Of course, I exaggerate, but many developers lead with the false premise that MVVM is against code-behind. It isn’t. This axiom is teaching that code-behind can have its place, can solve real problems, but should not be preferred. That is to say, code-behind is wrong, except when it isn’t.
10. There are no commandments
Still valid? yes
Sort of like fanatics of agile methodologies, getting too dogmatic over a design pattern like MVVM doesn’t teach fundamental computer science principles to developers: it frustrates them. Still, MVVM more than most others, is one of the most flexible and fluid design patterns: your implementation and mine may vary vastly, but we are both using MVVM in our XAML apps. Remember, other than having a view-model manage your data, there’s no other fundamental requirement of the MVVM pattern. This axiom is simply teaching: chill out.
This brings us to the end of reviewing my Ten Commandments of MVVM. For the most part, I think we could agree these are still quite relevant, three years later. Most of them, I might add, will remain valid for a long time.
Ben’s deadly sins
Well, here we go, on to Ben Dewey’s deadly sins for XAML developers. These, you will find, are less about the architectural approach to the app, and more the real-world, practical approach by the developer in markup. They are very prescriptive and, as a result, very opinionated. Let’s dig in.
1. Thou shalt not use inline styling
Still valid? was it ever?
If you have code like this: <TextBox FontSize="16" /> then he is recommending that you instead create either <TextBox FontSize="{StaticResource FontSize}" /> or <TextBox Style="{StaticResource Size16TextBox}" />. All three approaches are semantically similar, producing the same result, but are not identical in their execution. I think it’s important to remember execution because it impacts the user’s experience the most directly.
The introduction of a static resource requires the framework to parse and build out that resource before it can assign it to any control’s property. For the sake of reuse, this can be quite valuable to a developer, but let’s not understate that with hundreds or several hundreds of varying controls with similar static styles, the cost to startup is consequential. Is it right to use styles and static resources? Of course. Yes. Should it be a certainty? No.
Aside: I am quite willing to acknowledge care can be taken to reduce the cost and impact of styles and static resources. But, as a general rule, those performance techniques are black magic to the everyday XAML developer, and will not be implemented. It’s because of the latter I think this can’t be a general rule of thumb worth keeping.
2. Thou shalt not use hardcode colors
Still valid? yes
First of all, I could come up with several scenarios where an in-line, hard-coded color makes perfect sense. But generally speaking, the use of color is an intentional part of the user experience. Because user experiences can change based on Light, Dark, and High Contrast and impact theme resources injected at an application’s highest scope, those colors must not be static. Granted, Ben didn’t sell this rule based on the Themes we introduced to UWP a year after, he sold it based on reuse – a sort repeat of number one. But, that doesn’t matter: Theme resources make rule 2 more valid today than ever.
3. Thou shalt not use bitmap icons
Still valid? amen
Wow, this was a big problem in 2014 and it’s a bigger problem in 2017. Using bitmap images in your app for any reason introduces an amazing amount of complexity to handle them properly. Depending on the resolution and capability of your monitor, the built-in resource system in the Universal Windows Platform will self-select assets to render on the screen, meaning if you provide the right asset your app will look great and if you don’t it will blow chunks.
The solution for bitmaps in UWP is far more elegant than UWP, but even that is a near-nightmare. You provide and decorate a bitmap in various scales, letting the PRI subsystem pick the best option. Windows Store can break scaled groups into separate, downloadable asset packs reducing your installation footprint or initial download size, but you need to know what you are doing.
There’s just something painful about the near-exponential feel of including the 100% scale, the 150% scale, the 200% scale, the 250% scale, and the 300% scale of every bitmap in your app over and over. I know, sometimes bitmaps are your only option, but in general, they suck donkey.
Then, using bitmaps in your app can also be dangerous as you gobble up available memory because you improperly decode your images. With RS2, the platform introduced the ability to decode images properly by setting the source of your <Image/> tag to a BitmapImage with a DecodePixelType property.
MSDN: DecodePixelType can be set to Logical or Physical. The default value is Physical. If DecodePixelType is not set, or set to Physical, the image is decoded using DecodePixelWidth and DecodePixelHeight values that represent physical pixels, and the decode operation uses these values directly. If DecodePixelType is set to Logical, the image is decoded using DecodePixelWidth and DecodePixelHeight values that represent logical pixels. Internal logic converts the decode width and height based on device resolution info and how logical and physical pixels are factored on the target device.
Whew.
The better approach today is to use PNG or vector XAML paths, but shortly the platform will introduce the capability to natively render SVG (even animated SVG) and eventually colored fonts which can scale endlessly without the need for extra assets, both inside your app and its tile/live tile.
4. Thou shalt not set properties manually
Still valid? no
The main idea is to not set properties from code-behind. If you read back a few pages, you’ll see my diatribe on code-behind – you can interpolate some of my conclusion from those statements, but setting properties from code-behind is generally wrong. It typically means you are doing things without a view model or, even worse, without using the Visual State Manager. This behavior short circuits the designers ability to help you, check you or preview for you. It also means you can’t use the additional tooling to manipulate the logical tree without potentially breaking your invisible code-behind.
Aside: this rule is effectively an argument for MVVM and view-models. As I stated above I love MVVM, but I also disagree that it is a requirement for an excellent XAML application. I will likely always use MVVM in my apps, but I can understand a mindful developer choosing not to, too.
So, should you set property values of your XAML controls from your code-behind? Well, generally, no. But, a developer doesn’t have to introduce view-models, and with the introduction of Composition UI and its incredible, mesmerizing capabilities, many of which are only through code-behind, you can’t say “don’t do it” without a dozen attached caveats, which effectively invalidates the whole notion of a reusable axiom for XAML.
5. Thou shalt not duplicate chunks of XAML
Still valid? mostly
I would like to dispel a common developer statement: “Don’t repeat code.” This is best characterized as well-meaning stupidity. In a very narrow context, it makes plenty of sense. The more code you write the more code you need to test. Fine. But as a general rule, it coerces developers to introduce abstraction and encapsulation into the nooks and crannies of code, ad nauseam.
Consider, here, the needless complexity of Class01 over Class02:
Don’t get me wrong: if you are paid by the hour, then I understand your desire and attraction to Class02, but generally, there’s nothing wrong with letting a developer write code; they are equally testable. And, should we look at real-world examples, we will find applications with so much freaking code abstraction that reasoning over their logic is nearly impossible, and the duplicity saved is measurably trivial.
But, I digress.
This XAML rule is based on the precept of not repeating code, which, at its heart is reasonable, just generally inapplicable. That being said, XAML markup is a voluminous syntax that, unless it is precompiled (another condition short-circuiting this axiom), must be read, parsed, loaded and rendered. This processing pipeline is relatively expensive and can be reduced by reusing XAML in user controls, just as this rule prescribes. To that end, this rule is dead on and I follow it myself. But there are too many caveats and asides. This is not a rule, just a good habit for developers to adopt as they code.
Aside: part of the origin of this rule is a XAML developer’s natural addiction to binding. Because binding decouples logic, binding should be used as infrequently as possible. Yeah, you read that right. Use data binding for connecting your UI to your view-model and models, sure. But don’t go crazy with element binding because it ultimately frustrates real-world debugging of complex UI in significant applications.
6. Thou shalt not wrap content repeatedly
Still valid? no
One of the best qualities of XAML is its ability to re-template any control or container for to meet immediate needs of the UI. Not to be confused with data templates, these are control templates. Now to it: control templates are both XAML’s best feature and XAML’s worst feature. Why? I am glad you asked.
Have you ever wondered why the out-of-the-box toolbox in Visual Studio is not filled with even more controls than it already has? I mean, really, is it that hard to create a data grid? Well, it turns out, yes. That is to say, when a company like Microsoft makes a control they make it look great, they make it adaptive, they make it low memory, high performance, completely accessible, localizable, and more. Those requirements for first-party controls make their cost high and their construction slow.
I say all that to say this, when you re-template a control, there’s a 99% likelihood that you are going to mess it up – either the style, accessibility, localization, or the future update of the control’s template when the platform is revved a version or two. Again, we aren’t talking about data templates. It is for this likelihood that this rule that ultimately gravitates developers to the creation of custom controls is inherently problematic. We inevitably forestall the native capabilities of controls when we re-template them.
A contrary rule would serve the general XAML community better. Something more like: use the built-in controls and try not to re-template them. They are faster than custom controls. They are more compliant than custom controls. They are, generally speaking, better than custom controls.
Aside: having said all that, if Microsoft can write a good control so can your development team. But, we can all agree ahead of time, such an endeavor is no small task to be “knocked out” in a sprint or two. And, inevitably it will require maintenance as the platform matures.
7. Thou shalt not use absolute positioning
Still valid? yes
Absolute positioning, in XAML, might be best understood as positioning a UI element from 0,0 (or the top-left corner of the viewport). Relative positioning, by contrast moves something closer to or farther from an existing object in an arbitrary location. The RelativePanel, introduced to UWP in Anniversary Update, is a wonderful panel for arranging elements relatively to the panel or siblings within it. Android developers might compare it to RelativeLayout.
The only times you usually see absolute positioning in XAML is when developers use Canvas (which actually requires absolute positioning) and when a UI element is relocated around the interface by changing its margin.
We’ve all done it, there’s no reason to pretend I am better than you – especially here. The Visual Studio XAML designer actually does this by default and is sort of to blame for programming bad developer behavior. Once you also set the right and bottom margins, there’s no wonder new developers wrongly conclude that XAML is difficult and unpredictable. It’s a hot mess.
With the introduction of Windows 10 across various device types including Mobile, IoT, and HoloLens, the adaptive story of UWP apps was pushed to the foreground with force. Developers had to handle the changes of physical dimensions in ways WPF developers generally didn’t. The use of Visual States with the introduction of Adaptive Triggers for Visual States made the arduous task less brutal, but clarified the near-nemesis status of absolute positioning.
There are fewer and fewer games written in XAML. Frameworks like Unity have made it too simple to make compelling games cross-platform while enjoying C# and the Windows development environment. As a result, games, which were the primary use case for absolute positioning, rarely justify the practice; the presence of absolute positioning is generally a developer error.
Aside, the web has taught us developers a lot about how to build responsive and adaptive user interfaces. XAML has, built-in, corollaries of most of the conventions used on the web; it might even have more when you consider the scope and power of the Visual State Manager. The approach is basically the same – and the distain for absolute positioning is also in web development.
Reversed
I like that Ben turned the negative into positives, I will sign-off with his positive slide. The rules are the same, and the current validity remains the same, but it’s just nicer to be positive instead of negative. I think.
I wish I could have agreed more. But, I can’t.
But wait, didn’t I say I would also discuss Markus Egger’s XAML Anti-Pattern article(s) from Code Magazine? Yes. Yes, I did. But, today is August 29, 2017 and Hurricane Harvey is screwing up Houston and that appears to include the Code Magazine servers, which are down right now. So, I will have to circle back and do it later. And, I think we all know, that means I will never do it. :)
Best of luck!