<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lee Kelleher</title>
    <description>The latest articles on DEV Community by Lee Kelleher (@leekelleher).</description>
    <link>https://dev.to/leekelleher</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F32134%2F09f40c7b-03c3-463e-affb-892d19446f25.jpeg</url>
      <title>DEV Community: Lee Kelleher</title>
      <link>https://dev.to/leekelleher</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/leekelleher"/>
    <language>en</language>
    <item>
      <title>Umbraco Bellissima WIP articles</title>
      <dc:creator>Lee Kelleher</dc:creator>
      <pubDate>Sun, 11 Feb 2024 16:24:18 +0000</pubDate>
      <link>https://dev.to/leekelleher/umbraco-bellissima-wip-articles-29f8</link>
      <guid>https://dev.to/leekelleher/umbraco-bellissima-wip-articles-29f8</guid>
      <description>&lt;p&gt;With the release of Umbraco's new backoffice (codenamed Bellissima) drawing closer, (May 2024), I wanted to keep a list of work-in-progress (WIP) links to articles and resources for anyone future extension developers.&lt;/p&gt;

&lt;p&gt;As a first port of call for the most up-to-date list of links and resources, please check out the &lt;strong&gt;Umbraco Packages Community Team page &lt;a href="https://github.com/umbraco/Umbraco.Packages/tree/main/bellissima" rel="noopener noreferrer"&gt;Umbraco v14 "Bellissima" Resources&lt;/a&gt;&lt;/strong&gt;, much of this is based on &lt;strong&gt;Markus Johansson's (&lt;a class="mentioned-user" href="https://dev.to/markusjoha"&gt;@markusjoha&lt;/a&gt;) &lt;a href="https://www.enkelmedia.se/blogg/2023/11/18/resources-for-umbraco-14-belissima-new-backoffice" rel="noopener noreferrer"&gt;Resources for Umbraco 14 Bellissima (new Backoffice)&lt;/a&gt;&lt;/strong&gt; page, thank you to Markus! 🙏&lt;/p&gt;

&lt;p&gt;The rest of this post is intended to compliment, not compete with, Markus's page.&lt;/p&gt;

&lt;h5&gt;
  
  
  Matt Brailsford (&lt;a class="mentioned-user" href="https://dev.to/mattbrailsford"&gt;@mattbrailsford&lt;/a&gt;)
&lt;/h5&gt;

&lt;p&gt;In the earliest stages of Bellissima, Matt put together a series of articles that explore each aspect of the frontend tech stack. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/mattbrailsford/series/20031"&gt;Back to the Front-end: Exploring the Future of the Umbraco UI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Kevin Jump (&lt;a class="mentioned-user" href="https://dev.to/kevinjump"&gt;@kevinjump&lt;/a&gt;)
&lt;/h5&gt;

&lt;p&gt;Kevin is actively documenting his developer journey as an early adopter of Bellissima.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kevinjump/series/26221"&gt;EarlyAdopter's Guide Umbraco v14&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kevinjump/series/26289"&gt;EarlyAdopter's Umbraco v14 - Gotchas&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kevinjump/series/26248"&gt;EarlyAdopter's Guide Umbraco v14 - Communication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kevinjump/series/26366"&gt;EarlyAdopter's Guide Umbraco v14 - Property Editors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Me, Lee Kelleher (&lt;a class="mentioned-user" href="https://dev.to/leekelleher"&gt;@leekelleher&lt;/a&gt;)
&lt;/h5&gt;

&lt;p&gt;I started writing a series of articles about how I am migrating my Contentment package over to Bellissima.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/leekelleher/series/25453"&gt;Contentment for Bellissima&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>umbraco</category>
      <category>bellissima</category>
    </item>
    <item>
      <title>Lee joined Umbraco HQ</title>
      <dc:creator>Lee Kelleher</dc:creator>
      <pubDate>Sun, 11 Feb 2024 14:57:18 +0000</pubDate>
      <link>https://dev.to/leekelleher/lee-joined-umbraco-hq-2h6k</link>
      <guid>https://dev.to/leekelleher/lee-joined-umbraco-hq-2h6k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;TL;DR, I joined Umbraco HQ, to work on the Bellissima team. Yes, I'm being paid to work on an open-source project. No, Umbraco did not acquire my Contentment package.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Now, the longer story, with plenty of nuance...&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At the start of 2022, after 10 years I left my agency, Umbrella. I'd gotten weary with the grind of agency-land, a lack of fulfilment with the quality of work. I wanted to explore a path down a product development route. I'd been developing Umbraco packages for a long time, I enjoyed that type of work and people valued using those packages.&lt;/p&gt;

&lt;p&gt;My initial thought was to follow the path that my peers had paved, and go down a commercial Umbraco package route; &lt;a href="https://vendr.net/" rel="noopener noreferrer"&gt;Matt with Vendr&lt;/a&gt;, &lt;a href="https://jumoo.co.uk/uSync/" rel="noopener noreferrer"&gt;Kevin with uSync&lt;/a&gt;, &lt;a href="https://soetemansoftware.nl/" rel="noopener noreferrer"&gt;Richard Soeteman&lt;/a&gt;, et al.&lt;/p&gt;

&lt;p&gt;Initially, I explored what I could do with my Contentment package. There didn't feel like much I could explore, it was already open-source after all. Some advised that I could close-source it and charge a nominal fee, (e.g. under $50), but looking at the stats (from my own telemetry data), this wouldn't be sustainable for me - especially when compared to a freelance Umbraco developer's day rate.&lt;/p&gt;

&lt;p&gt;I gave myself 6 months to come up with an alternative idea (whether it'd be Umbraco related or not). I'd already planned for this when leaving Umbrella, so made sure I was financially stable during this time.&lt;/p&gt;

&lt;p&gt;During the 6 months, I'd had many conversations with people within the community, lots of ideas, all with potential, but all suffered from a similar concern - was the Umbraco ecosystem large enough to sustain these ideas. Most of the ideas would require heavy marketing to gain any momentum... and let's face it, I'm hardly a "sales guy".&lt;/p&gt;

&lt;p&gt;I had lots of "what ifs", envisaging what a successful commercial Umbraco package look like, and what would be the end goal. I kept come to one of two outcomes, either a decent lifestyle business or being acquired by Umbraco HQ. &lt;em&gt;(Spoiler alert, Vendr was acquired by Umbraco in April 2023.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Towards the end of my 6 month idea exploration, I'd been chatting a lot with &lt;a href="https://gibe.digital/" rel="noopener noreferrer"&gt;Steve at Gibe&lt;/a&gt; about helping them to productise their sports portal solution. I joined Gibe on a freelance contract to build &lt;a href="https://www.useplaymaker.com/" rel="noopener noreferrer"&gt;Playmaker&lt;/a&gt;. If you attended the Umbraco Spark conference 2023, we did a talk about it; &lt;a href="https://umbracospark.com/media/vu5laxcb/spark-iii_2023_playmaker_danceswithwolvespptx-1.pdf" rel="noopener noreferrer"&gt;Playmaker: Dances with Wolves&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I felt happier building a product that had long term visions.&lt;/p&gt;

&lt;p&gt;After finishing up with Gibe, around end of the summer 2023, I went back to the drawing board, had a few ideas, but nothing I wanted to pursue. The lure of the freelancer day rate was more appealing than bootstrapping a new venture. I slowly resigned myself to going back to agency-land, it wasn't exciting, but gotta feed the kids, hey ho!&lt;/p&gt;

&lt;p&gt;I tried to put the feelers out on LinkedIn, got a bombarded with recruitment agents, urgh, it didn't feel like the right move.&lt;/p&gt;

&lt;p&gt;Mid-December 2023, I was chatting with a close friend (outside the tech world), who asked me what the heck I was up to and when was I going to sort my shit out. Some days you need to a mate to give you a swift kick up the arse.&lt;/p&gt;

&lt;p&gt;Next day, I was chatting with Matt, and the topic of "would I consider working for Umbraco?" came up. Okay, subplot...&lt;/p&gt;




&lt;p&gt;Now, I had thought about working for Umbraco HQ a couple of years ago. &lt;a href="https://www.andybutland.dev/" rel="noopener noreferrer"&gt;Andy Butland&lt;/a&gt; had recently joined and was looking for an Integrations Developer to join the new DXP team and build all those integration/connector packages. I'd chatted with Andy about it, it was all exciting, but then something strange happened at the same time.&lt;/p&gt;

&lt;p&gt;This little fella popped his head over the wall...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gge23ftb855x9n70qsb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gge23ftb855x9n70qsb.png" alt="" width="160" height="50"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I got a message from Ilham at Umbraco, asking me about the little character in my Contentment package. Turns out that they'd had a complaint from an Umbraco Cloud customer who thought that my Contentment package had hacked their CMS backoffice. Obviously, this wasn't the case, but Ilham wasn't sure so wanted to check with me first. I'd explained it was along the same lines as Umbraco's manifesto 6.13% crazy, "Happy Caturday" and all that nonsense.&lt;/p&gt;

&lt;p&gt;All was fine. Except, I couldn't shake the thought that if I took a job with Umbraco, then I may have felt guilty about this and/or been encouraged to remove such tomfoolery from my package.&lt;/p&gt;

&lt;p&gt;At the time, I felt I needed my own autonomy to do what I wanted to do, without repercussion, so I let Andy know that I wouldn't be pursuing the position. I felt a bit rubbish about that, as it would have been cool working with Andy on those packages.&lt;/p&gt;




&lt;p&gt;Okay, back to chatting with Matt. I said that I'd drop Filip an email, just to put the feelers out there. In my mind, I was thinking I'd hear back in a few weeks, maybe chat in a few months or maybe at CodeGarden, just see where it goes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nope!&lt;/strong&gt; 4 minutes later, Filip replied, saying he'll check internally. Next day Filip emailed back saying there wasn't any open positions for me, but we should have a call the following day. On the Friday, I have a call with Filip and he offers me a job on the Bellissima team... and can I start immediately, and oh, can I fly out to Denmark the following week to meet the team.&lt;/p&gt;

&lt;p&gt;Wow, this was quite the whirlwind. I'd never had a job enquiry turnaround so quickly, it was all very exciting.&lt;/p&gt;

&lt;p&gt;After a couple of days back and forth of contract discussions, we were all happy. For those interested, there was zero mention of Contentment being acquired or absorbed into the core CMS. The focus of my work is to help the team deliver the new backoffice for Umbraco 14. I'm sure we'll talk about Contentment (or its features) once v14 has launched.&lt;/p&gt;

&lt;p&gt;You may be wondering what changed for me. Am I still concerned about giving up autonomy on my own work? I'm less concerned these days. What became apparent to me since leaving Umbrella is that I was looking for a way to get paid to be an open-source developer, and now that's a reality.&lt;/p&gt;

</description>
      <category>umbraco</category>
      <category>career</category>
    </item>
    <item>
      <title>Lee's opinions on Umbraco + naming things</title>
      <dc:creator>Lee Kelleher</dc:creator>
      <pubDate>Wed, 06 Dec 2023 17:36:45 +0000</pubDate>
      <link>https://dev.to/leekelleher/lees-opinions-on-umbraco-naming-things-8k7</link>
      <guid>https://dev.to/leekelleher/lees-opinions-on-umbraco-naming-things-8k7</guid>
      <description>&lt;h2&gt;
  
  
  Naming things is hard (maybe?)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Text casing styles
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: I'll be mentioning different text casing styles in this article. In case you aren't aware of these, here's a quick primer...&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;
  Lexicon the different text casing styles
  &lt;p&gt;These are the different text casing styles for naming things like folders, files, URLs, variables, etc. Along with the typical &lt;code&gt;UPPERCASE&lt;/code&gt;, &lt;code&gt;lowercase&lt;/code&gt;, &lt;code&gt;Title Case&lt;/code&gt; and &lt;code&gt;Sentence case&lt;/code&gt;, there are also...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PascalCase&lt;/code&gt; - spaces removed, each word is capitalised, &lt;em&gt;(popularized by the &lt;a href="https://en.wikipedia.org/wiki/Pascal_(programming_language)" rel="noopener noreferrer"&gt;Pascal language&lt;/a&gt;)&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;camelCase&lt;/code&gt; - same as PascalCase, but starts with lowercase, &lt;em&gt;(because the capitals look like camel humps)&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kebab-case&lt;/code&gt; - spaces replaced with hyphens/dashes, generally lowercase, &lt;em&gt;(named on a late Saturday night after the pub closed)&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;snake_case&lt;/code&gt; - spaces replaced with underscores, generally lowercase, &lt;em&gt;(named after some slippery character)&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;For further explanation on these text casings, take a read of &lt;a href="https://www.freecodecamp.org/news/snake-case-vs-camel-case-vs-pascal-case-vs-kebab-case-whats-the-difference/" rel="noopener noreferrer"&gt;freeCodeCamp's article on &lt;strong&gt;What's the Difference Between Casings?&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;



&lt;/p&gt;

&lt;h2&gt;
  
  
  General naming of things
&lt;/h2&gt;

&lt;p&gt;For anything that is going to be a public-facing web-asset, e.g. folders, filenames, anything that'll become a URL, then I go with &lt;strong&gt;kebab-case&lt;/strong&gt; (lowercase) all the way.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;In the early 2000s, the GOV.UK team (Alphagov back then, now GDS), released a bunch of guidelines on file naming, the kebab-case one stuck in my mind. Unfortunately, I can't find a link to the original document.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For Visual Studio projects, the folder structure would &lt;em&gt;generally&lt;/em&gt; correspond C# namespaces and types, so they'd be in &lt;strong&gt;PascalCase&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For C# variables names; &lt;strong&gt;camelCase&lt;/strong&gt;, but I still underscore prefix &lt;code&gt;_&lt;/code&gt; for private backing fields, &lt;em&gt;(old habits die hard)&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Namespaces
&lt;/h2&gt;

&lt;p&gt;From my early .NET and XML days I learnt about the importance of clear and decisive namespaces. To be treated like a classification system, (scoped however you need, e.g. per project, per organisation, for global usage). I'd spend a silly amount of time deliberating on the namespace taxonomy for my code libraries.&lt;br&gt;
It's like creating your own mini &lt;a href="https://en.m.wikipedia.org/wiki/Dewey_Decimal_Classification" rel="noopener noreferrer"&gt;Dewey Decimal system&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For Visual Studio/.NET projects and libraries, I follow the &lt;a href="https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/names-of-namespaces" rel="noopener noreferrer"&gt;general .NET convention&lt;/a&gt; of dot-delimited, capitalised/PascalCase namespaces.&lt;/p&gt;

&lt;p&gt;Nowadays, especially for any Umbraco extensions I develop, I try to follow Umbraco's own namespaces as closely as possible. e.g. I'd put my custom &lt;a href="https://github.com/umbraco/Umbraco-CMS/blob/release-10.0.0/src/Umbraco.Core/Routing/IContentFinder.cs" rel="noopener noreferrer"&gt;&lt;code&gt;IContentFinder&lt;/code&gt;&lt;/a&gt; classes under a &lt;code&gt;[Brand].Web.Routing&lt;/code&gt; namespace. Mostly so that it feels logical for any other developers who may be familiar with Umbraco core code.&lt;/p&gt;

&lt;h3&gt;
  
  
  .NET libraries
&lt;/h3&gt;

&lt;p&gt;As I start planning out an ASP.NET website, I try to judge how much application code it will need. For basic brochureware websites, there may be an odd API controller, so I'll end up placing that code within the website itself, &lt;em&gt;(for legacy ASP.NET, I'd put it in &lt;code&gt;App_Code&lt;/code&gt;; for .NET Core, it'd be in the main project, pre-compiled).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When there is more application code required, I'd separate out code into additional library dependencies, which needs to be named - &lt;strong&gt;what do I call them?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Historically, I'd go with initially adding a &lt;code&gt;[Brand].Core&lt;/code&gt; library, and whack everything in there. Then if needed, separate out larger features to their own libraries. But &lt;strong&gt;what do I call them?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As mentioned in the previous section, with my Umbraco work, I'd been following a similar namespace pattern to Umbraco CMS itself.&lt;br&gt;
I'd typically start off with naming my main project as &lt;strong&gt;&lt;code&gt;[Brand].Web&lt;/code&gt;&lt;/strong&gt;, this would house the Umbraco CMS instance, the Razor views, wwwroot, and not much else.&lt;/p&gt;

&lt;p&gt;For the public-facing, website specific code, (including Surface/API controllers, ViewComponents, extension methods, etc). I'd name that &lt;strong&gt;&lt;code&gt;[Brand].Cms.Web.Website&lt;/code&gt;&lt;/strong&gt; library (as Umbraco has a corresponding named library).&lt;/p&gt;

&lt;p&gt;For any CMS backoffice specific code, e.g. property-editors, dashboards, notification handlers, (maybe even a &lt;a href="https://github.com/leekelleher/umbraco-contentment/blob/develop/docs/editors/data-list.md#extending-with-your-own-custom-data-source" rel="noopener noreferrer"&gt;custom Contentment Data List source&lt;/a&gt;), etc. I'd name this &lt;strong&gt;&lt;code&gt;[Brand].Cms.Web.BackOffice&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If there is application code that needs to be shared between the &lt;code&gt;Website&lt;/code&gt; and the &lt;code&gt;BackOffice&lt;/code&gt; libraries, e.g. generated ModelsBuilder classes, Configuration classes; I'd go with having a shared library called &lt;strong&gt;&lt;code&gt;[Brand].Cms.Web.Common&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For any additional features, say a 3rd-party integration, then I'd follow similar to how Umbraco have done with their &lt;a href="https://www.nuget.org/packages?q=Umbraco.Cms.Integrations" rel="noopener noreferrer"&gt;&lt;code&gt;Umbraco.Cms.Integrations.*&lt;/code&gt; packages&lt;/a&gt;, so for a MailChimp integration, I'd go with &lt;strong&gt;&lt;code&gt;[Brand].Cms.Integrations.MailChimp&lt;/code&gt;&lt;/strong&gt;; or a YouTube integration, &lt;strong&gt;&lt;code&gt;[Brand].Cms.Integrations.YouTube&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For something that is more short-lived, such as a pre-launch content migration using &lt;a href="https://github.com/Jumoo/uSyncMigrations" rel="noopener noreferrer"&gt;uSync Migrations&lt;/a&gt;, that may require custom code, I'd have a standalone &lt;strong&gt;&lt;code&gt;[Brand].Cms.ContentMigration&lt;/code&gt;&lt;/strong&gt; library, so that it can easily be removed prior to launch/production.&lt;/p&gt;

&lt;h3&gt;
  
  
  NuGet packages
&lt;/h3&gt;

&lt;p&gt;Most often when naming a NuGet package, you'd go with whatever the name of your Visual Studio project library is, they fall hand-in-hand. However, if you named your library something simple, say after a generic English word, or something that has no context outside of your scope/project, then it can look messy.&lt;/p&gt;

&lt;p&gt;I try to take a worldview; think globally. 🌍&lt;/p&gt;

&lt;p&gt;Many developers prefix their package ID with their organisation's name; this is quite common, good advertising and totally acceptable.&lt;/p&gt;

&lt;p&gt;With open-source Umbraco community-related NuGet packages, I've seen several misnamed packages, but not to pick faults with others, I'll keep focus on my own mistakes. Let's take &lt;a href="https://our.umbraco.com/packages/backoffice-extensions/ucomponents/" rel="noopener noreferrer"&gt;&lt;strong&gt;uComponents&lt;/strong&gt;&lt;/a&gt; (circa 2010), as the name may imply, it's a bunch of components for Umbraco, (hence the u-prefix, part of a trend of packages around that time; uCommerce, uBlogsy, uCssClassNameDropdown, uSync, etc), it made sense, it was a good brand name. The Visual Studio project was named &lt;code&gt;uComponents&lt;/code&gt;, so when we made the NuGet package, the obvious choice was, &lt;em&gt;you guessed it&lt;/em&gt;, &lt;a href="https://www.nuget.org/packages/uComponents" rel="noopener noreferrer"&gt;&lt;code&gt;uComponents&lt;/code&gt;&lt;/a&gt;! 🤦&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why is this a problem?&lt;/strong&gt; At face value, it isn't a problem. Taking a step back at a more global level, what does "uComponents" mean to the rest of the world? Many of the .NET developers who heavily use NuGet may have not even heard of Umbraco CMS, let alone a 3rd party plugin for it. What if people from the &lt;a href="https://platform.uno/" rel="noopener noreferrer"&gt;Uno Platform&lt;/a&gt; community are browsing NuGet for some kind of components extension library? You can see, this could get confusing outside the scope of the Umbraco community/ecosystem.&lt;br&gt;
On top of this, uComponents was developed against Umbraco v4, with its last release in 2016, now it's there to be lingering on the NuGet repository until the end of time, set in stone.&lt;/p&gt;

&lt;p&gt;After that I started to prefix my package names under something more scoped to the context of the Umbraco ecosystem, a la &lt;code&gt;Our.Umbraco.*&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can read an old post of mine about the &lt;a href="https://dev.to/leekelleher/history-of-our-umbraco-package-names-34f2"&gt;History of "Our.Umbraco.*" package names&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;More recently, Umbraco HQ allowed use of the &lt;code&gt;Umbraco.Community.*&lt;/code&gt; prefix, which I've use for my &lt;a href="https://www.nuget.org/packages/Umbraco.Community.Contentment" rel="noopener noreferrer"&gt;Contentment package&lt;/a&gt; and I actively advocate other package developers to do the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub repositories
&lt;/h3&gt;

&lt;p&gt;Given the name of a public GitHub repository is part of its URL, I'll use kebab-case. Additionally, I'll include a prefix to set the scope/context/namespace of the repository itself, this would typically be the primary technology used, e.g. &lt;code&gt;umbraco-contentment&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;My reasoning behind this, is for GitHub's approach to repository forking. Let's take for example &lt;a href="https://github.com/umbraco/rfcs" rel="noopener noreferrer"&gt;Umbraco's RFCs repo, &lt;code&gt;umbraco/rfcs&lt;/code&gt;&lt;/a&gt;; the name of the organisation is &lt;code&gt;umbraco&lt;/code&gt; and the name of the repository is &lt;code&gt;rfcs&lt;/code&gt;, &lt;em&gt;(all makes sense!).&lt;/em&gt; If I were to fork this repo, (&lt;a href="https://github.com/leekelleher/umbraco-rfcs" rel="noopener noreferrer"&gt;which I have&lt;/a&gt;), then that would become &lt;code&gt;leekelleher/rfcs&lt;/code&gt;, losing it's context of it being about Umbraco - so I'd personally rename my fork to &lt;code&gt;leekelleher/umbraco-rfcs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does it matter?&lt;/strong&gt; In the greater schemes probably not, but I prefer the semantics of such naming.&lt;/p&gt;

&lt;p&gt;The majority of my GitHub repositories are Umbraco-related, so mostly have an &lt;code&gt;umbraco-&lt;/code&gt; prefix, but if I was developing a dependency-free library in a specific language/framework, I'd used whatever prefix deemed relevant, e.g. &lt;code&gt;dotnet-&lt;/code&gt;, &lt;code&gt;php-&lt;/code&gt;, &lt;code&gt;wordpress-&lt;/code&gt;, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Umbraco CMS schema style guide
&lt;/h2&gt;

&lt;p&gt;I wanted to briefly touch on naming things in Umbraco CMS itself, e.g. the schema: Document Types, Property Types, Templates, etc.&lt;/p&gt;

&lt;p&gt;For Document Types and Property Types, I try to keep the names as &lt;strong&gt;Sentence case&lt;/strong&gt;, (not Title Case), I used to do this, but I tried out (Sentence case) and it felt more natural and friendly to read. With the aliases, these are camelCase by default, no arguments there. As for the descriptions, I try to write simple/plain English summaries, avoiding any technical jargon.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Document Type icon colours.&lt;/strong&gt; I try to have a consistency based on the content type, e.g. Compositions are &lt;strong&gt;Lime&lt;/strong&gt;; Pages (nodes in the tree) are &lt;strong&gt;Indigo&lt;/strong&gt;; Element Types/Blocks are &lt;strong&gt;Blue-Grey&lt;/strong&gt;. &lt;em&gt;(I dunno, it makes me happy).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;p&gt;If you're interested in how things are named in other web-tech, here are a few links for further reading...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://html.spec.whatwg.org/multipage/semantics-other.html" rel="noopener noreferrer"&gt;HTML5 spec on &lt;strong&gt;Common idioms&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://codeguide.co/" rel="noopener noreferrer"&gt;&lt;strong&gt;Code Guide&lt;/strong&gt; by Mark Otto&lt;/a&gt;, Standards for developing consistent, flexible, and sustainable HTML and CSS.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>umbraco</category>
      <category>nuget</category>
    </item>
    <item>
      <title>Lee's opinions on Umbraco + coding standards</title>
      <dc:creator>Lee Kelleher</dc:creator>
      <pubDate>Mon, 04 Dec 2023 09:05:00 +0000</pubDate>
      <link>https://dev.to/leekelleher/lees-opinions-on-umbraco-coding-standards-4c7n</link>
      <guid>https://dev.to/leekelleher/lees-opinions-on-umbraco-coding-standards-4c7n</guid>
      <description>&lt;p&gt;When you learn a programming language, your initial coding style is dictated by the lessons; your teacher; the books you study. My first programming language was Sinclair BASIC on the ZX Spectrum 48K. I had a book on how to code simple games, that would influence how I'd name variables, etc. &lt;em&gt;(mostly as single letters, which was a terrible idea).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Several years later, I'd got into developing with Visual Basic, &lt;a href="https://en.wikipedia.org/wiki/Hungarian_notation" rel="noopener noreferrer"&gt;Hungarian notation&lt;/a&gt; was all the rage; (TL;DR, prefixing variable names to indicate its type, e.g. &lt;code&gt;iCount&lt;/code&gt; for an integer variable to count something with).&lt;/p&gt;

&lt;p&gt;Even later, when I was learning C#, Hungarian notation had fallen out of favour, mostly due to Visual Studio compile-time type-checking; and that it was deemed healthier and maintainable to have semantic variable names. You adapt with the times (and your development teams) and evolve your coding style.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tabs vs spaces
&lt;/h2&gt;

&lt;p&gt;My long time personal preference for indentation is &lt;strong&gt;tabs&lt;/strong&gt;. It made sense to me. A single character of variable width (configurable in your code editor/IDE). However most development teams that I've worked on have had a stronger preference for the use of spaces, so we'd end up have tiresome debates on which was better. &lt;em&gt;(When I became the Lead Developer on my team, there were less debates, tabs would win out).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This all changed when I started working on open-source projects. The evilest type of indentation is mixed tabs &amp;amp; spaces - it's the kind of thing that'd turn my stomach! You have to pick a style and stick with it; consistency. Of course, I would pick tabs, but when I receive a pull request contribution, I'd often find there'd be either a mix of tabs &amp;amp; spaces, or worse, entire files re-indented from tabs to spaces... &lt;a href="https://en.wikipedia.org/wiki/Law_of_triviality" rel="noopener noreferrer"&gt;things would get tribal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I soon came to the conclusion that I was swimming against the tide arguing for tabs, when the majority of developers would use spaces. I wanted to play nicely with others, &lt;em&gt;I cared less for the bike-shed,&lt;/em&gt; so I adapted to use spaces and evolved my coding style. &lt;em&gt;(It took me a few years to get used to this!)&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: With the widespread adoption of &lt;a href="https://editorconfig.org/" rel="noopener noreferrer"&gt;the &lt;strong&gt;&lt;code&gt;.editorconfig&lt;/code&gt;&lt;/strong&gt; specification&lt;/a&gt;, &lt;em&gt;(circa. 2017)&lt;/em&gt;, it became simpler to enforce a consistent coding style for an entire project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Brace! Brace!
&lt;/h2&gt;

&lt;p&gt;Code readability is something that I'd become more aware of since contributing to open-source projects. Reviewing code changes on pull requests in a web browser can get a little tricky to mentally process.&lt;/p&gt;

&lt;p&gt;For example, take a single line conditional, I'd be tempted to write...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentNullException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is fine and acceptable. However if we were to modify this line, say with an extra condition or change the exception logic, the line gets longer; the diff looks messy; it can take a little more mental processing to understand the exact change.&lt;/p&gt;

&lt;p&gt;I opted to take the more verbose approach of having newline-braces for all code blocks, including single line conditionals.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ArgumentNullException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The C# compiler doesn't care, and it's more readable to me.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ternary conditional operator
&lt;/h3&gt;

&lt;p&gt;I do like the ternary conditional operator, &lt;em&gt;(&lt;code&gt;?:&lt;/code&gt; uh huh huh),&lt;/em&gt; it can make simple single-line if/else statement more succinct. In a similar vein to the code blocks, I end up placing the resulting expressions on indented newlines.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;flag&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"Success"&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Failure"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, more verbose, but more readable in my mind and gives a structure for any future amends; understanding diff changed, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cognitive load
&lt;/h2&gt;

&lt;p&gt;On the topic of code readability, you may have noticed in my previous code snippet I added &lt;code&gt;== true&lt;/code&gt; to the condition. Many developers see this as ugly and redundant code, as the condition is implied to be &lt;code&gt;true&lt;/code&gt;. Sure, once you understand that's happening, that's fine, you're an experienced developer, totally acceptable.&lt;/p&gt;

&lt;p&gt;Let's take this condition...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we read this condition, we think, &lt;em&gt;"okay, if the string is not null or empty or whitespace then proceed".&lt;/em&gt; But optically, scanning the text from left to right, you have to mentally take note of the unary logical negation operator &lt;em&gt;(&lt;code&gt;!&lt;/code&gt; bang),&lt;/em&gt; then understand what the &lt;code&gt;string.IsNullOrWhiteSpace&lt;/code&gt; method means; in both terms of resultant object-type (hopefully a Boolean) and the argument parameter. Your brain is keeping track of a couple of things here, the negation and the method result, then cognitively swapping them around to make a natural English sentence (in my mind).&lt;/p&gt;

&lt;p&gt;Taking the same example, but now with the explicit Boolean operator...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsNullOrWhiteSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For me, optically, the text scans the way I comprehend the logic, &lt;em&gt;"is the string null or empty or whitespace? no? then proceed".&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The C# compiler doesn't care whether you use the &lt;code&gt;!&lt;/code&gt; bang or &lt;code&gt;== false&lt;/code&gt;, it all compiles down to the exact same bytecode, &lt;em&gt;(trust me, try it out in &lt;a href="https://www.linqpad.net/" rel="noopener noreferrer"&gt;LINQPad&lt;/a&gt;, view the generated IL code).&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you strongly disagree with me on this one, that's cool, &lt;a href="https://www.reddit.com/r/csharp/comments/vdkx68/boolean_false_or_boolean/" rel="noopener noreferrer"&gt;there's a special reddit thread for experienced developers&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  C# language evolutions
&lt;/h2&gt;

&lt;p&gt;Much of my C# syntax keeps changing as the language itself evolved. It didn't take me too long to switch over to using &lt;code&gt;var&lt;/code&gt; declarations and &lt;code&gt;$"Hello {name}"&lt;/code&gt; string interpolation. But some other new language features have taken me longer, like the file-scoped namespace declaration &lt;em&gt;(as opposed to have surrounding braces for the namespace),&lt;/em&gt; or &lt;code&gt;Span&amp;lt;char&amp;gt;&lt;/code&gt; pattern matching &lt;em&gt;(way too much cognitive load, it hurts my head).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I try to evaluate the latest C# language features, to get a feel for if they appear comprehensible to a newcomer. If so, then I'd most likely adopt it.&lt;/p&gt;

</description>
      <category>umbraco</category>
    </item>
    <item>
      <title>Lee's opinions on Umbraco + [topic]</title>
      <dc:creator>Lee Kelleher</dc:creator>
      <pubDate>Mon, 04 Dec 2023 09:04:00 +0000</pubDate>
      <link>https://dev.to/leekelleher/lees-opinions-on-umbraco-topic-3o3k</link>
      <guid>https://dev.to/leekelleher/lees-opinions-on-umbraco-topic-3o3k</guid>
      <description>&lt;h2&gt;
  
  
  Strong Opinions, Weakly Held
&lt;/h2&gt;

&lt;p&gt;To open with &lt;a href="https://youtu.be/yoEezZD71sc?t=376" rel="noopener noreferrer"&gt;a quote by Tim Minchin&lt;/a&gt;...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;A famous bon mot asserts that &lt;a href="https://en.wikipedia.org/wiki/Wikipedia:Opinions_are_like_arseholes" rel="noopener noreferrer"&gt;opinions are like assholes&lt;/a&gt;, in that everyone has one.  There is great wisdom in this, but I would add that opinions differ significantly from assholes, in that yours should be constantly and thoroughly examined.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Many years ago, I read a post on Jeff Atwood's Coding Horror blog, &lt;a href="https://blog.codinghorror.com/strong-opinions-weakly-held/" rel="noopener noreferrer"&gt;Strong Opinions, Weakly Held&lt;/a&gt;, this resonated with me; over my years with Umbraco, I'd racked up numerous MVPs, to the point where some may have perceived me as an authority on all things Umbraco; I'm not, I'm always learning - and whilst I can have strong opinions from time to time, I do try to keep an open mind about them, to be challenged and evolve accordingly.&lt;/p&gt;

&lt;p&gt;Offering an unsolicited opinion on a particular topic can be a terrible idea. &lt;em&gt;I mean, who cares about Silicon Valley boardroom power struggles, right?&lt;/em&gt; But then sometimes people do care, and want you to share your thoughts and insights - so at the request of my good friend &lt;a class="mentioned-user" href="https://dev.to/lottepitcher"&gt;@lottepitcher&lt;/a&gt;...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;a class="mentioned-user" href="https://dev.to/leekelleher"&gt;@leekelleher&lt;/a&gt; I have always thoroughly enjoyed, and benefitted from, hearing all the opinions that you have in and around the #umbraco ecosystem. So maybe a post per opinion that you have the desire and energy to share?! Off the top of my head: naming things (classes/projects/repos/nuget); coding styles for readability; why one should work in public (I mean you share &lt;em&gt;a lot&lt;/em&gt;, why is that?!). That’s my two cents at least ☺️&lt;/em&gt;&lt;br&gt;
&lt;a href="https://umbracocommunity.social/@lotte/111448500067158203" rel="noopener noreferrer"&gt;https://umbracocommunity.social/@lotte/111448500067158203&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This series of articles will offer my opinions on various aspects of working with Umbraco CMS, .NET development and the community package ecosystem.&lt;/p&gt;

</description>
      <category>umbraco</category>
      <category>opinion</category>
    </item>
    <item>
      <title>Contentment for Bellissima</title>
      <dc:creator>Lee Kelleher</dc:creator>
      <pubDate>Thu, 30 Nov 2023 12:59:06 +0000</pubDate>
      <link>https://dev.to/leekelleher/contentment-for-bellissima-199d</link>
      <guid>https://dev.to/leekelleher/contentment-for-bellissima-199d</guid>
      <description>&lt;h2&gt;
  
  
  Preamble
&lt;/h2&gt;

&lt;p&gt;This series is about the migration of my Umbraco package, Contentment, to the new Umbraco backoffice, codenamed Bellissima.&lt;/p&gt;

&lt;p&gt;
  If you don't know what any of that means, expand this section for background reading and lexicon for this series.
  &lt;ul&gt;
&lt;li&gt;
&lt;a href="https://marketplace.umbraco.com/package/umbraco.community.contentment" rel="noopener noreferrer"&gt;Contentment&lt;/a&gt; is the name of my Umbraco package, it contains a bunch of useful property-editors.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to see Contentment in action, I did a 30 minute presentation at CodeGarden 2023, &lt;a href="https://www.youtube.com/watch?v=fYPcFOxeN4c" rel="noopener noreferrer"&gt;Finding Contentment&lt;/a&gt;, exploring each of the editor components.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://umbraco.com/blog/bellissima-preview-releases-of-the-new-backoffice/" rel="noopener noreferrer"&gt;Bellissima&lt;/a&gt; is the project codename of the new backoffice for Umbraco CMS, (circa v14).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Bellissima web tech... e.g. Web Components, TypeScript, Lit, Vite, see &lt;a class="mentioned-user" href="https://dev.to/mattbrailsford"&gt;@mattbrailsford&lt;/a&gt;'s series of articles &lt;a href="https://dev.to/mattbrailsford/series/20031"&gt;Back to the Front-end: Exploring the Future of the Umbraco UI&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Disclaimer: I am part of the &lt;a href="https://community.umbraco.com/learn-about-the-community/community-teams/the-backoffice-community-team/" rel="noopener noreferrer"&gt;Umbraco Backoffice Community Team&lt;/a&gt; - my opinions in these articles are my own and do not reflect the opinions of the community team nor Umbraco HQ.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The detail in these articles tries to be as accurate as possible (at the time of writing), if reading this a year or two from now, I'd expect there to be many changes with how Umbraco extension development is approached.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Where to begin?
&lt;/h2&gt;

&lt;p&gt;At CodeGarden (June 2023), a preview of v14 was released, but wasn't quite ready for package development. By August 2023, &lt;a href="https://umbraco.com/blog/bellissima-preview-releases-of-the-new-backoffice/" rel="noopener noreferrer"&gt;&lt;code&gt;14.0.0--preview002&lt;/code&gt; was released&lt;/a&gt;, including the Extension API, so package developers could register their extension points, e.g. dashboards, property-editors, etc. Meaning it was ready to explore.&lt;/p&gt;

&lt;p&gt;My initial dilemma was should I attempt to make the existing Contentment codebase work with Bellissima, or start from scratch?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Note: I had a similar dilemma with &lt;a href="https://github.com/leekelleher/umbraco-contentment/discussions/105" rel="noopener noreferrer"&gt;the Umbraco v9 / .NET Core migration work&lt;/a&gt;. Ultimately, I started off from scratch, then did a complete U-turn and ended up with the .NET multi-targeting solution, supporting multiple versions of Umbraco in a single package. (Which has turned out quite well for Contentment.)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My gut feeling was to keep the existing codebase as-is, making sure that the .NET assembly library has binary compatibility (e.g. the C# server-side bits), before thinking about the backoffice-frontend/web-component bits.&lt;/p&gt;

&lt;p&gt;Umbraco v13 and v14 would be compiled against .NET 8.0, so I got the latest .NET 8 preview installed and configured Contentment's &lt;code&gt;.csproj&lt;/code&gt; file to target &lt;code&gt;net8.0&lt;/code&gt; and reference Umbraco's &lt;code&gt;14.0.0--preview002&lt;/code&gt; NuGet packages.  As expected, this gave me a bunch of compiler errors from &lt;a href="https://our.umbraco.com/download/releases/1300" rel="noopener noreferrer"&gt;breaking-changes in v13&lt;/a&gt;/v14 codebase.&lt;/p&gt;

&lt;p&gt;Fixing up the breaking-changes was straight forward, nothing complicated, given my .NET multi-targeting approach, I could make use pre-processor directives for specific fixes, e.g. &lt;code&gt;#if NET8_0_OR_GREATER&lt;/code&gt;. All time consuming, but no headaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Versioning dilemmas
&lt;/h2&gt;

&lt;p&gt;Once the compiler errors were resolved, I was able to run Contentment against an Umbraco instance of &lt;code&gt;14.0.0--preview002&lt;/code&gt;. Of course, I wasn't able to do anything with it, there were no property-editors registered, but the initial hurdle was overcome.&lt;/p&gt;

&lt;p&gt;Before I got going with the backoffice-frontend/web-components prototyping, I wondered about whether Contentment should take the RCL (Razor Class Library) approach. &lt;em&gt;Meaning that the &lt;code&gt;App_Plugins&lt;/code&gt; folder would be served from the NuGet package itself, rather than copied over at build-time. (It's what all the cool kids are doing these days!)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This presented another dilemma, RCL is a .NET Core technology, so this wouldn't work for legacy .NET Framework, meaning that I'd need to drop support for Umbraco v8. And whilst I was considering dropping support for old versions, I could drop Umbraco v9 too. I gave it all some thought and updated &lt;a href="https://github.com/leekelleher/umbraco-contentment/blob/master/.github/ROADMAP.md" rel="noopener noreferrer"&gt;Contentment's ROADMAP&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In terms of Contentment's version numbers, and expecting to add support for Umbraco v13/.NET 8, I could do a Contentment v5 to drop support for v8/v9, add v13 (LTS) and do the RCL. This would be paving the way for a Contentment v6 to add support for Bellissima, (although because of the .NET multi-targeting, it'd need to be the next .NET major, so .NET 9, which would be Umbraco v15). &lt;em&gt;(There's probably a lot to unpack in this paragraph, it'll make sense in a future article).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I still haven't fully decided whether to continue with the .NET multi-targeting approach after Bellissima, I may change my mind, but I do like the idea of having a single NuGet package (and codebase) that could support multiple versions of Umbraco. It'd be interesting to explore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next time...
&lt;/h2&gt;

&lt;p&gt;Next time, I'll show my starting steps for the backoffice-frontend/web-components, installing TypeScript/Vite/Lit, et al.&lt;br&gt;
In the meantime, if you want to skip ahead and see the code, here are links to areas of interest on Contentment's GitHub repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/leekelleher/umbraco-contentment/discussions/357" rel="noopener noreferrer"&gt;Support for Umbraco Bellissima, (aka new backoffice) #357&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/leekelleher/umbraco-contentment/tree/dev/wip/bellissima" rel="noopener noreferrer"&gt;The work-in-progress branch &lt;code&gt;dev/wip/bellissima&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>umbraco</category>
      <category>cms</category>
      <category>dotnet</category>
      <category>webcomponents</category>
    </item>
    <item>
      <title>A polyfill for Umbraco packages</title>
      <dc:creator>Lee Kelleher</dc:creator>
      <pubDate>Wed, 27 Apr 2022 14:29:20 +0000</pubDate>
      <link>https://dev.to/leekelleher/a-polyfill-for-umbraco-packages-3ljc</link>
      <guid>https://dev.to/leekelleher/a-polyfill-for-umbraco-packages-3ljc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Update: 2023-05-23. Due to the lack of interest, the Umbraco Polyfill package has now been deprecated. The source code is available on GitHub: &lt;a href="https://github.com/leekelleher/umbraco-polyfill" rel="noopener noreferrer"&gt;https://github.com/leekelleher/umbraco-polyfill&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;If you are unfamiliar with the term polyfill in web development, here is the definition from MDN...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A polyfill is a piece of code (usually JavaScript on the Web) used to provide modern functionality on older browsers that do not natively support it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Polyfill" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Glossary/Polyfill&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Typically, polyfills are referenced in the context of front-end web development, but they could also be applied to server-side APIs.&lt;/p&gt;




&lt;p&gt;I hear you asking: &lt;em&gt;What does this have to do with Umbraco packages?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This time last year, &lt;a href="https://github.com/leekelleher/umbraco-contentment/discussions/105" rel="noopener noreferrer"&gt;I'd started migrating my Umbraco package&lt;/a&gt;, &lt;a href="https://our.umbraco.com/packages/backoffice-extensions/contentment/" rel="noopener noreferrer"&gt;Contentment&lt;/a&gt; to support &lt;a href="https://umbraco.com/products/umbraco-cms/umbraco-9/" rel="noopener noreferrer"&gt;Umbraco 9&lt;/a&gt; on ASP.NET Core 5. My initial approach was to drop support for &lt;a href="https://umbraco.com/products/umbraco-cms/umbraco-8/" rel="noopener noreferrer"&gt;Umbraco 8&lt;/a&gt; to focus exclusively on Umbraco 9. A decision that niggled me.&lt;/p&gt;

&lt;p&gt;During the code migration, I'd discussed with fellow Umbraco package developers about &lt;a href="https://github.com/leekelleher/umbraco-contentment/discussions/105#discussioncomment-1547429" rel="noopener noreferrer"&gt;multi-targeting .NET frameworks&lt;/a&gt; within the same codebase, and indeed it was possible, meaning that Contentment could still support Umbraco 8. The downsize would be that there would be many &lt;code&gt;#if&lt;/code&gt;/&lt;code&gt;#else&lt;/code&gt; pre-processor directives littered throughout the codebase.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For more details on this approach, take a read of &lt;br&gt;
the &lt;a href="https://umbraco.com/blog/multi-targeted-package-migration/" rel="noopener noreferrer"&gt;Package Migration to V9 Using Multi-Targeting&lt;/a&gt; post on the Umbraco blog.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#if NET
    private readonly ILogger&amp;lt;MyClass&amp;gt; _logger;

    public MyClass(ILogger&amp;lt;MyClass&amp;gt; logger) 
    {
        _logger = logger;
    }
#else
    private readonly ILogger _logger;

    public MyClass(ILogger logger) 
    {
        _logger = logger;
    }
#endif

    public void MyMethod() 
    {
        // Do some common logic and log a result
        var result = "Some value";
#if NET
        _logger.Debug(result);
#else
        _logger.Debug&amp;lt;MyClass&amp;gt;(result);
#endif
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Code snippet taken from &lt;a class="mentioned-user" href="https://dev.to/mattbrailsford"&gt;@mattbrailsford&lt;/a&gt;'s &lt;a href="https://dev.to/mattbrailsford/adding-ilogger-t-support-to-umbraco-v8-5cg8"&gt;Adding &lt;code&gt;ILogger&amp;lt;T&amp;gt;&lt;/code&gt; support to Umbraco v8&lt;/a&gt; post.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Whilst I really liked the idea of multi-targeting, the amount of pre-processor directives did start to get silly. I wondered why that was and what could be done about it.&lt;/p&gt;

&lt;p&gt;Of course, the API between Umbraco 8 and 9 were different, some changes were subtle, others breaking. All for understandable reasons.&lt;/p&gt;

&lt;p&gt;With Contentment, one of the more common bits was that the &lt;code&gt;IOHelper.ResolveUrl()&lt;/code&gt; was no longer a static method, and a new &lt;code&gt;IIOHelper&lt;/code&gt; instance would need to be injected, meaning adding an extra parameter to the class constructor.&lt;/p&gt;

&lt;p&gt;Since &lt;code&gt;IIOHelper&lt;/code&gt; wasn't available in Umbraco 8, I ended up using conditional pre-processor directives...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#if NET472
    public DropdownListDataListEditor()
    {
    }
#else
    private readonly IIOHelper _ioHelper;
    public DropdownListDataListEditor(IIOHelper ioHelper)
    {
        _ioHelper = ioHelper;
    }
#endif
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and this happened in a &lt;strong&gt;lot&lt;/strong&gt; of places!&lt;/p&gt;

&lt;p&gt;My thinking was that I could introduce a polyfill for &lt;code&gt;IIOHelper&lt;/code&gt; in Umbraco 8 only. &lt;em&gt;(Given the v8 roadmap, I doubted that it would ever be added to v8.x patch release.)&lt;/em&gt; So that's what I did, &lt;a href="https://github.com/leekelleher/umbraco-contentment/blob/dev/v3.x/src/Umbraco.Community.Contentment/Polyfill/IIOHelper.cs" rel="noopener noreferrer"&gt;here's a link to the code for the &lt;code&gt;IIOHelper&lt;/code&gt; polyfill&lt;/a&gt; and &lt;a href="https://github.com/leekelleher/umbraco-contentment/blob/dev/v3.x/src/Umbraco.Community.Contentment/Composing/ContentmentComposer.cs#L37" rel="noopener noreferrer"&gt;how it is registered using dependency injection in a Composer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now my code would look like this...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    private readonly IIOHelper _ioHelper;
    public DropdownListDataListEditor(IIOHelper ioHelper)
    {
        _ioHelper = ioHelper;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Removing the need for the conditional pre-processor directives, and maintaining the same functionality and logic.&lt;/p&gt;

&lt;p&gt;Taking this approach to some of the other v9-only interfaces and services, I was able to reduce the verbosity of Contentment's codebase. &lt;a href="https://github.com/leekelleher/umbraco-contentment/tree/dev/v3.x/src/Umbraco.Community.Contentment/Polyfill" rel="noopener noreferrer"&gt;You can see the other polyfill code on the GitHub repository&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Okay, now what?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This was all great for my Contentment package, happy days. Until when I started developing a new Umbraco package. I developed the code against Umbraco 9, but when I reviewed the code I could see the potential of adding support for Umbraco 8 with a few conditional pre-processor directives. So I copied the polyfill code over from Contentment... &lt;strong&gt;wait a minute, what am I doing?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At this point I separated out the polyfill code to its own code library, so that it could be referenced in my other (future) Umbraco packages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/leekelleher/umbraco-polyfill" rel="noopener noreferrer"&gt;https://github.com/leekelleher/umbraco-polyfill&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;...and released a NuGet package:&lt;br&gt;
&lt;a href="https://www.nuget.org/packages/Our.Umbraco.Community.Polyfill/" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/Our.Umbraco.Community.Polyfill/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just to note, in it's current release, this library should be considered a continued work-in-progress, and &lt;strong&gt;NOT&lt;/strong&gt; feature complete. If you are a package developer and find there are missing features, &lt;a href="https://github.com/leekelleher/umbraco-polyfill" rel="noopener noreferrer"&gt;I'm happy to collaborate with you on the GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>umbraco</category>
      <category>polyfill</category>
    </item>
    <item>
      <title>Umbraco Image Crop Picker using Contentment Data List</title>
      <dc:creator>Lee Kelleher</dc:creator>
      <pubDate>Thu, 11 Feb 2021 12:02:43 +0000</pubDate>
      <link>https://dev.to/leekelleher/umbraco-image-crop-picker-using-contentment-data-list-5coi</link>
      <guid>https://dev.to/leekelleher/umbraco-image-crop-picker-using-contentment-data-list-5coi</guid>
      <description>&lt;p&gt;A couple of weeks ago, &lt;a href="https://dev.to/zajkowskimarcin"&gt;Marcin Zajkowski&lt;/a&gt; and &lt;a href="https://dev.to/aochmann"&gt;Adrian Ochmann&lt;/a&gt; announced the release of their new Umbraco package, &lt;a href="https://our.umbraco.com/packages/backoffice-extensions/image-crop-picker/" rel="noopener noreferrer"&gt;Image Crop Picker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1354821151541710850-866" src="https://platform.twitter.com/embed/Tweet.html?id=1354821151541710850"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1354821151541710850-866');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1354821151541710850&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Image Crop Picker&lt;/strong&gt; is a property-editor that enables a specific image crop to be selected from the configuration of a Image Cropper data-type. This can be useful for when a content-editor needs control over which crop is used for rendering an image.&lt;/p&gt;

&lt;p&gt;The package has releases for both Umbraco v7 and v8, and has plans to extend the functionality in future releases. If it suits your needs, then please use it. 👍&lt;/p&gt;

&lt;p&gt;Now what does this all have to do with my &lt;a href="https://our.umbraco.com/packages/backoffice-extensions/contentment/" rel="noopener noreferrer"&gt;Contentment&lt;/a&gt; package? Since developing the &lt;a href="https://github.com/leekelleher/umbraco-contentment/blob/develop/docs/editors/data-list.md" rel="noopener noreferrer"&gt;&lt;strong&gt;Data List&lt;/strong&gt;&lt;/a&gt; property-editor, whenever I see another package use a dropdown-list, checkbox-list or radiobutton-list, I can't shake the concept of separating the data-source from the list-editor.&lt;/p&gt;

&lt;p&gt;So with the the &lt;strong&gt;Image Crop Picker&lt;/strong&gt; package, I wondered - &lt;em&gt;Could that be achieved as a custom Data Source?&lt;/em&gt; 🤔&lt;/p&gt;

&lt;p&gt;It would need a way to select a pre-configured Image Cropper data-type, then get all the crop definitions from that data-type... &lt;em&gt;Yeah, why not!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;🕙🕚🕛 &lt;strong&gt;TL;DR,&lt;/strong&gt; If you want to skip the explanation and see the code, it is available this gist: &lt;a href="https://gist.github.com/leekelleher/5c0abddb3246185ce0ba50a99975e310" rel="noopener noreferrer"&gt;&lt;code&gt;UmbracoImageCropDataListSource.cs&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To do this, I needed to define the crops in my own &lt;strong&gt;Image Cropper&lt;/strong&gt; data-type. &lt;em&gt;I opted to copy Marcin's examples.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxy0bmwy48bk0p3atvh9w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxy0bmwy48bk0p3atvh9w.png" alt="Image Cropper data-type configuration" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, once I had the code (&lt;a href="https://gist.github.com/leekelleher/5c0abddb3246185ce0ba50a99975e310" rel="noopener noreferrer"&gt;from the gist&lt;/a&gt;) in place, I could create my custom &lt;strong&gt;Data List&lt;/strong&gt; data-type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyj7ix994yfqjvyv8a6yk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyj7ix994yfqjvyv8a6yk.png" alt="Data List data-type with Umbraco Image Crops as the data-source" width="800" height="957"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The configuration for the data-source needs to select a pre-configured &lt;strong&gt;Image Cropper&lt;/strong&gt; data-type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4d05iuo3869n9j62g60m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4d05iuo3869n9j62g60m.png" alt="Umbraco Image Crops data-source configuration" width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this UI, I opted to use the Item Picker editor, I thought it would be a nicer UI, in case have numerous Image Cropper data-types. This could have easily been done with a dropdown-list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzqax96ah0yb1terk3mpe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzqax96ah0yb1terk3mpe.png" alt="Umbraco Image Crops data-source, select an Image Cropper data-type" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftmukjbcws2cym5bfh5jq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftmukjbcws2cym5bfh5jq.png" alt="Umbraco Image Crops data-source, selected Image Cropper data-type" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once selected, you can configure the list-editor you would like to use. For this example, I chose a radiobutton-list.&lt;/p&gt;

&lt;p&gt;You can then save the Data List data-type and add it to your document-type.&lt;/p&gt;

&lt;p&gt;On your content page, it will be displayed like so...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdbgpk2vr3zh1b5l3x64i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fdbgpk2vr3zh1b5l3x64i.png" alt="image-crop-picker-editor" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, if you prefer a different list-editor - say a dropdown-list, or enable multiple selections with a checkbox-list or Item Picker, you can do that.&lt;/p&gt;

&lt;p&gt;Here is the Umbraco Image Crops data-source code in full...&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;em&gt;If people think it would be interesting for me to break down and explain the code in more detail, please let me know. I'm happy to do so, just didn't want to do it unwarranted.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;🔌 &lt;em&gt;Plugs and begging...&lt;/em&gt; 🙏&lt;br&gt;
If you already use the Contentment package, please remember to give it a vote-up on the Our Umbraco project page: &lt;a href="https://our.umbraco.com/packages/backoffice-extensions/contentment/" rel="noopener noreferrer"&gt;https://our.umbraco.com/packages/backoffice-extensions/contentment/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you use my open-source Umbraco packages on commercial projects and want to say thanks - consider becoming a sponsor: &lt;a href="https://github.com/sponsors/leekelleher" rel="noopener noreferrer"&gt;https://github.com/sponsors/leekelleher&lt;/a&gt; ❤&lt;/p&gt;

</description>
      <category>umbraco</category>
      <category>contentment</category>
      <category>cms</category>
    </item>
    <item>
      <title>Using ClientDependency Filters to manipulate HTML</title>
      <dc:creator>Lee Kelleher</dc:creator>
      <pubDate>Thu, 16 Jan 2020 10:37:00 +0000</pubDate>
      <link>https://dev.to/leekelleher/using-clientdependency-filters-to-manipulate-html-4n4f</link>
      <guid>https://dev.to/leekelleher/using-clientdependency-filters-to-manipulate-html-4n4f</guid>
      <description>&lt;p&gt;On a recent Umbraco project, I needed to be able to manipulate the HTML contents before it was sent to the browser.&lt;/p&gt;

&lt;p&gt;Typically, on Umbraco projects you'd do whatever you need do within Razor templating, but in my case, I had to do after the entire page markup was built. &lt;em&gt;(I won't go into details, as the requirement is specific to my client project.)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My initial thought for the solution was using a &lt;code&gt;Request.Filter&lt;/code&gt;. I'd done this previously in my ASP.NET WebForms days - even open-sourced a packaged called &lt;a href="https://our.umbraco.com/packages/website-utilities/safe-mail-link" rel="noopener noreferrer"&gt;Safe Mail Link&lt;/a&gt; that utilised this approach, &lt;em&gt;(it would encode/protect any email addresses found in the markup)&lt;/em&gt;. The guts of the &lt;code&gt;Request.Filter&lt;/code&gt; came from &lt;a href="https://weblog.west-wind.com/posts/2009/nov/13/capturing-and-transforming-aspnet-output-with-responsefilter" rel="noopener noreferrer"&gt;Rick Strahl's &lt;code&gt;ResponseFilterStream&lt;/code&gt; blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Given the original &lt;code&gt;ResponseFilterStream&lt;/code&gt; code was originally posted over 10 years ago, &lt;em&gt;(wow!)&lt;/em&gt; I wasn't sure whether the approach would work with latest Umbraco &lt;em&gt;(v8 is ASP.NET MVC 5)&lt;/em&gt;. Turns out, it does!&lt;/p&gt;

&lt;p&gt;As I started to implement this approach, I recalled that the ClientDependency library &lt;em&gt;(which ships with Umbraco)&lt;/em&gt; uses a &lt;code&gt;HttpModule&lt;/code&gt; to manipulate the HTML output to insert references to its bundled CSS &amp;amp; JS assets. So, thought it best to look at the source-code.&lt;/p&gt;

&lt;p&gt;...and as it happens, &lt;a href="https://github.com/Shazwazza/ClientDependency/blob/v1.9.8/ClientDependency.Core/Module/ClientDependencyModule.cs" rel="noopener noreferrer"&gt;&lt;code&gt;ClientDependencyModule&lt;/code&gt;&lt;/a&gt; has a lovely undocumented feature in there... its very own &lt;a href="https://github.com/Shazwazza/ClientDependency/blob/v1.9.8/ClientDependency.Core/Module/IFilter.cs" rel="noopener noreferrer"&gt;&lt;code&gt;IFilter&lt;/code&gt;&lt;/a&gt; interface. This enables you to piggyback ClientDependency's &lt;code&gt;HttpModule&lt;/code&gt; and manipulate the HTML with your own code!&lt;/p&gt;

&lt;p&gt;After &lt;a href="https://github.com/Shazwazza/ClientDependency/blob/v1.9.8/ClientDependency.Core/Module/ClientDependencyModule.cs#L126-L142" rel="noopener noreferrer"&gt;a small bit of reverse-engineering&lt;/a&gt;, &lt;em&gt;(I know, I know, it's all open-source ... so I mean "researching")&lt;/em&gt;, I had a working prototype! Here's a reduced example (for Umbraco v8) ...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;using System.Configuration;
using System.Web;
using ClientDependency.Core.Config;
using ClientDependency.Core.Module;
using Umbraco.Core;
using Umbraco.Web.Composing;

namespace Umbraco.Community.Web
{
    public class UpdateHtmlExampleComposer : IUserComposer
    {
        public void Compose(Composition composition)
        {
            ClientDependencySettings.Instance.ConfigSection.Filters
                .Add(new ProviderSettings(nameof(UpdateHtmlExampleFilter), typeof(UpdateHtmlExampleFilter).GetFullNameWithAssembly()));
        }
    }

    public class UpdateHtmlExampleFilter : IFilter
    {
        public HttpContextBase CurrentContext { get; private set; }

        public bool CanExecute()
        {
            return Current.UmbracoContext?.IsFrontEndUmbracoRequest == true;
        }

        public void SetHttpContext(HttpContextBase ctx) =&amp;gt; CurrentContext = ctx;

        public string UpdateOutputHtml(string html)
        {
            // TODO: Do your HTML updates in here! 
            // ------------------------------------
            // o o/ o o/ o o/  
            // //| /| //| /| //| /|   
            // / \ / \ / \ / \ / \ / \  
            // ------------------------------------

            return html
                .Replace("Headless", "Heartcore");
        }

        // NOTE: If ClientDependency's MvcFilter is valid, then I'm cool with that.
        public bool ValidateCurrentHandler() =&amp;gt; true;
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examples of things you could do with this, could be: minify the HTML markup; inject external scripts before the closing &lt;code&gt;&amp;lt;/body&amp;gt;&lt;/code&gt; tag, (e.g. &lt;a href="https://instant.page/" rel="noopener noreferrer"&gt;instant.page&lt;/a&gt;); protect/encode email address (a la &lt;a href="https://our.umbraco.com/packages/website-utilities/safe-mail-link" rel="noopener noreferrer"&gt;Safe Mail Link&lt;/a&gt;); or a super-quick way to rename a product across an entire website?&lt;/p&gt;

</description>
      <category>umbraco</category>
      <category>clientdependency</category>
    </item>
    <item>
      <title>History of "Our.Umbraco.*" package names</title>
      <dc:creator>Lee Kelleher</dc:creator>
      <pubDate>Tue, 27 Nov 2018 10:50:00 +0000</pubDate>
      <link>https://dev.to/leekelleher/history-of-our-umbraco-package-names-34f2</link>
      <guid>https://dev.to/leekelleher/history-of-our-umbraco-package-names-34f2</guid>
      <description>&lt;p&gt;Back in early 2017, &lt;a href="https://twitter.com/callumbwhyte/status/820641163334053889" rel="noopener noreferrer"&gt;Callum asked the question&lt;/a&gt;…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Can someone explain the history behind the "Our.Umbraco.X" naming convention for packages? It seems it's used by only a few now #umbraco&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I &lt;a href="https://twitter.com/leekelleher/status/820727834536767488" rel="noopener noreferrer"&gt;replied at the time&lt;/a&gt; - but felt an explanation longer than a couple of tweets would be nice, (and findable for future reference). I had a draft of this post sitting around for a while now, thought best to publish it!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.flickr.com/photos/rikhelsen/6269167834/in/album-72157627950157764/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw9qg1ekbaf1gp80rsu94.jpg" alt="Umbraco community hacking" width="800" height="492"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I started to work with Umbraco, back in late 2007, my company was called &lt;strong&gt;Bodenko&lt;/strong&gt;. When we developed any back-office features, they all ended up being bundled into a single project called &lt;strong&gt;"Bodenko.Umbraco"&lt;/strong&gt; - this quickly became a dumping ground for all our extensions.&lt;/p&gt;

&lt;p&gt;After getting more involved with the community, asking a lot of questions on the forum - and starting to answer some of them, I thought that I should really open-source the packages we'd developed at Bodenko. Our first was the &lt;a href="https://our.umbraco.com/packages/developer-tools/robotstxt-editor/" rel="noopener noreferrer"&gt;&lt;strong&gt;Robots.txt Editor&lt;/strong&gt;&lt;/a&gt; (which is surprisingly still popular today - and with very little updates to the original codebase) … I named the assembly &lt;strong&gt;"Bodenko.Umbraco.RobotsTxtEditor"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In 2009, I'd parted ways with Bodenko to go as a solo freelancer, we dissolved the company. Around this time, I'd attended my first CodeGarden - where they'd launched the new forum… &lt;strong&gt;Our Umbraco&lt;/strong&gt; - it was a very exciting time within the community. The Robots.txt Editor project was due a patch release (roll up of bug fixes), but when I reviewed the code, I felt that my old company name held little relevance to the package itself. There wasn't much point in using the package to "advertise" our old company and services. So, I looked to change it.&lt;/p&gt;

&lt;p&gt;My company name for my freelance work was called &lt;strong&gt;Vertino&lt;/strong&gt; , I could have swapped it with that, but that didn't feel quite right either. Around the same time, I'd noticed there were a few other newly released packages that contained a name/reference to the company that developed them, and it somewhat felt a little &lt;em&gt;anti-community&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Rather than trying to come up with a new base part for my code's namespaces, I did a swap of &lt;strong&gt;"Bodenko"&lt;/strong&gt; with &lt;strong&gt;"Our"&lt;/strong&gt;. I still can't decide if that was a clever idea or I was being lazy - &lt;em&gt;probably the latter&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;I never envisaged this as trying to start a convention, then as I got involved with other established Umbraco packages, e.g. &lt;a href="https://our.umbraco.com/packages/developer-tools/config-tree/" rel="noopener noreferrer"&gt;Config Tree&lt;/a&gt; and &lt;a href="https://our.umbraco.com/packages/backoffice-extensions/google-maps-datatype/" rel="noopener noreferrer"&gt;Google Maps DataType&lt;/a&gt;, with the agreement of their developers, we renamed the namespaces and assemblies over time.&lt;/p&gt;

&lt;p&gt;Ironically, we never changed the &lt;a href="https://our.umbraco.com/packages/backoffice-extensions/ucomponents/" rel="noopener noreferrer"&gt;uComponents&lt;/a&gt; namespace or assemblies - considering that at the time, that project was considered to be the &lt;em&gt;de facto&lt;/em&gt; Umbraco community project.&lt;/p&gt;

&lt;p&gt;The idea was that these packages were &lt;strong&gt;made by the Umbraco community, for the Umbraco community&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I didn't push this naming convention, but interestingly I noticed other package developers had started to use it. It had become an unspoken guideline.&lt;/p&gt;

&lt;p&gt;More recently, the packages that I've collaborated on with &lt;a href="https://twitter.com/mattbrailsford" rel="noopener noreferrer"&gt;Matt Brailsford&lt;/a&gt; have generally come from working together at my company &lt;strong&gt;Umbrella&lt;/strong&gt; (where Matt has freelanced with us). However, when we started coding and setting up namespaces, if we used &lt;strong&gt;"Umbrella.Umbraco.*"&lt;/strong&gt; it wouldn't feel quite right. We knew from the outset that certain back-office extensions had the potential to be released as fully-fledged Umbraco packages - we always start out with that mindset… &lt;strong&gt;"for the community"&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;So, if you ever look in your website's &lt;code&gt;/bin&lt;/code&gt; folder and see a bunch of "Our.Umbraco.*" assemblies, then you now know they were developed with the community in mind and are a sign of thoughtful, well-crafted Umbraco packages.&lt;/p&gt;

</description>
      <category>umbraco</category>
    </item>
  </channel>
</rss>
