<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
	<title>Lee Kelleher - Umbraco</title>
	<link>https://leekelleher.com/</link>
	<description>Latest Umbraco posts by Lee Kelleher - Umbraco contributor</description>
	<language>en-GB</language>
	<lastBuildDate>Sun, 11 Feb 2024 15:53:00 +0000</lastBuildDate>
	<image>
		<url>https://leekelleher.com/assets/img/nxnw_300x300.png</url>
		<title>Lee Kelleher - Umbraco</title>
		<link>https://leekelleher.com/</link>
	</image>
	<atom:link rel="self" href="https://leekelleher.com/umbraco/feed/"/>

	<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/"&gt;Matt with Vendr&lt;/a&gt;, &lt;a href="https://jumoo.co.uk/uSync/"&gt;Kevin with uSync&lt;/a&gt;, &lt;a href="https://soetemansoftware.nl/"&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/"&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/"&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"&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/"&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://media.dev.to/cdn-cgi/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://media.dev.to/cdn-cgi/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='"Lee was here"' 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(ish?)
&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)"&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/"&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;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Maybe in another life I'd have been a librarian, learning the Dewey Decimal system. I like the idea of being able to intuitively find resources by categorisation and semantics.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&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"&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"&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"&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"&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"&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/"&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"&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/"&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"&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"&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"&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"&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/"&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"&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"&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/"&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/"&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/"&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"&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"&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/"&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"&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"&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"&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/"&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/"&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/"&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"&gt;the Umbraco v9 / .NET Core migration work&lt;/a&gt;. Ultimately, I started off from scratch, then 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-compontent 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"&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"&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"&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"&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><guid isPermaLink="true">https://leekelleher.com/2020/01/clientdependency-filters-manipulate-html</guid><link>https://leekelleher.com/2020/01/clientdependency-filters-manipulate-html</link><title>Using ClientDependency Filters to manipulate HTML</title><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"&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"&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"&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"&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"&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;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;&lt;span style="color:#0000FF;"&gt;using&lt;/span&gt; System.Configuration;
&lt;span style="color:#0000FF;"&gt;using&lt;/span&gt; System.Web;
&lt;span style="color:#0000FF;"&gt;using&lt;/span&gt; ClientDependency.Core.Config;
&lt;span style="color:#0000FF;"&gt;using&lt;/span&gt; ClientDependency.Core.Module;
&lt;span style="color:#0000FF;"&gt;using&lt;/span&gt; Umbraco.Core;
&lt;span style="color:#0000FF;"&gt;using&lt;/span&gt; Umbraco.Web.Composing;

&lt;span style="color:#0000FF;"&gt;namespace&lt;/span&gt; Umbraco.Community.Web
{
    &lt;span style="color:#0000FF;"&gt;public&lt;/span&gt; &lt;span style="color:#0000FF;"&gt;class&lt;/span&gt; UpdateHtmlExampleComposer : IUserComposer
    {
        &lt;span style="color:#0000FF;"&gt;public&lt;/span&gt; &lt;span style="color:#0000FF;"&gt;void&lt;/span&gt; Compose(Composition composition)
        {
            ClientDependencySettings.Instance.ConfigSection.Filters
                .Add(&lt;span style="color:#0000FF;"&gt;new&lt;/span&gt; ProviderSettings(nameof(UpdateHtmlExampleFilter), &lt;span style="color:#0000FF;"&gt;typeof&lt;/span&gt;(UpdateHtmlExampleFilter).GetFullNameWithAssembly()));
        }
    }

    &lt;span style="color:#0000FF;"&gt;public&lt;/span&gt; &lt;span style="color:#0000FF;"&gt;class&lt;/span&gt; UpdateHtmlExampleFilter : IFilter
    {
        &lt;span style="color:#0000FF;"&gt;public&lt;/span&gt; HttpContextBase CurrentContext { &lt;span style="color:#0000FF;"&gt;get&lt;/span&gt;; &lt;span style="color:#0000FF;"&gt;private&lt;/span&gt; &lt;span style="color:#0000FF;"&gt;set&lt;/span&gt;; }

        &lt;span style="color:#0000FF;"&gt;public&lt;/span&gt; &lt;span style="color:#0000FF;"&gt;bool&lt;/span&gt; CanExecute()
        {
            &lt;span style="color:#0000FF;"&gt;return&lt;/span&gt; Current.UmbracoContext?.IsFrontEndUmbracoRequest == &lt;span style="color:#0000FF;"&gt;true&lt;/span&gt;;
        }

        &lt;span style="color:#0000FF;"&gt;public&lt;/span&gt; &lt;span style="color:#0000FF;"&gt;void&lt;/span&gt; SetHttpContext(HttpContextBase ctx) =&amp;gt; CurrentContext = ctx;

        &lt;span style="color:#0000FF;"&gt;public&lt;/span&gt; &lt;span style="color:#0000FF;"&gt;string&lt;/span&gt; UpdateOutputHtml(&lt;span style="color:#0000FF;"&gt;string&lt;/span&gt; html)
        {
            &lt;span style="color:#008000;"&gt;// TODO: Do your HTML updates in here! &lt;/span&gt;
            &lt;span style="color:#008000;"&gt;// ------------------------------------&lt;/span&gt;
            &lt;span style="color:#008000;"&gt;//    o    o/    o     o/    o     o/  &lt;/span&gt;
            &lt;span style="color:#008000;"&gt;//  //|   /|   //|    /|   //|    /|   &lt;/span&gt;
            &lt;span style="color:#008000;"&gt;//   / \  / \   / \   / \   / \   / \  &lt;/span&gt;
            &lt;span style="color:#008000;"&gt;// ------------------------------------&lt;/span&gt;

            &lt;span style="color:#0000FF;"&gt;return&lt;/span&gt; html
                .Replace(&lt;span style="color:#A31515;"&gt;"Headless"&lt;/span&gt;, &lt;span style="color:#A31515;"&gt;"Heartcore"&lt;/span&gt;);
        }

        &lt;span style="color:#008000;"&gt;// NOTE: If ClientDependency's MvcFilter is valid, then I'm cool with that.&lt;/span&gt;
        &lt;span style="color:#0000FF;"&gt;public&lt;/span&gt; &lt;span style="color:#0000FF;"&gt;bool&lt;/span&gt; ValidateCurrentHandler() =&amp;gt; &lt;span style="color:#0000FF;"&gt;true&lt;/span&gt;;
    }
}

&lt;/code&gt;&lt;/pre&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/"&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"&gt;Safe Mail Link&lt;/a&gt;); or a super-quick way to rename a product across an entire website?&lt;/p&gt;
</description><pubDate>Thu, 16 Jan 2020 10:37:00 Z</pubDate></item>

	<item><guid isPermaLink="true">https://leekelleher.com/2019/02/ending-umco-patreon</guid><link>https://leekelleher.com/2019/02/ending-umco-patreon</link><title>Ending our UMCO Patreon campaign</title><description>&lt;p&gt;This evening Matt &amp;amp; I &lt;a href="https://www.patreon.com/posts/umco-patreon-is-24951765"&gt;posted on our Patreon campaign for UMCO&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm cross-posting here for posterity...&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The UMCO Patreon campaign is ending&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Reflecting back on the past 2 years of running our Patreon campaign, we've had great success and gained quite a few backers (which we are extremely grateful for), but at the same time we've learned a few things about what running a successful campaign actually means for OSS and what the expectations this brings.&lt;/p&gt;
&lt;p&gt;We started our Patreon campaign as a way to explore how we could formalise a support strategy for our UMCO projects. It gave agencies and individuals a way to financially support our packages, whilst keeping them free and open-source. From the outside, it may look like we've succeeded in doing that, but the reality is that the what it brings in, isn't enough to schedule dedicated time to our packages so we are mostly supporting them in our spare time much like we previously had been doing.&lt;/p&gt;
&lt;p&gt;Unfortunately, by having people support us financially, it has also brought additional demands and stresses to our projects that makes supporting them much harder than it was prior to the campaign.&lt;/p&gt;
&lt;p&gt;We started to feel guilty that we weren't showing enough effort to our Patreon supporters. If we took a holiday or had a quiet month, people may wonder what we were up to. Self-guilting ourselves into feeling we needed a constant presence or even to get a patch release out.&lt;/p&gt;
&lt;p&gt;Adding to this, the Patreon model may have given the wrong impression, in that paying $100 a month would entitle an agency to dedicated support of our Umbraco packages. Which would be a gross undervaluing our services.&lt;/p&gt;
&lt;p&gt;Ultimately, Patreon was an experiment and from that experiment we have learned that Patreon isn't the right approach for us.&lt;/p&gt;
&lt;p&gt;We'd like to thank everyone for their support...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To add to this, we still aim on being very active in the Umbraco community, Umbraco core, package development, &lt;a href="https://umbristol.co.uk"&gt;umBristol meetups&lt;/a&gt;... and CodeCabin!&lt;/p&gt;
&lt;p&gt;Speaking of which, this year's &lt;strong&gt;CodeCabin&lt;/strong&gt; is open for applications! Visit &lt;a href="https://codecab.in/"&gt;https://codecab.in/&lt;/a&gt;!&lt;/p&gt;
</description><pubDate>Mon, 25 Feb 2019 20:05:00 Z</pubDate></item>

	<item><guid isPermaLink="true">https://leekelleher.com/2018/12/24days-umbraco-content-apps</guid><link>https://leekelleher.com/2018/12/24days-umbraco-content-apps</link><title>24 Days: Content Apps gold rush</title><description>&lt;p&gt;I wrote an article for this year's &lt;strong&gt;24 Days In Umbraco&lt;/strong&gt; Christmas Calendar, entitled &lt;a href="https://24days.in/umbraco-cms/2018/content-apps-gold-rush/"&gt;Who will win in the Content Apps gold rush?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here's a brief summary...&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Content Apps are a new feature in Umbraco v8, there is much interesting in their potential. But will this be done individually or by collaboration?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="https://24days.in/umbraco-cms/2018/content-apps-gold-rush/"&gt;You can read the article over on the 24 Days In Umbraco 2018 website.&lt;/a&gt;&lt;/p&gt;
</description><pubDate>Fri, 21 Dec 2018 15:46:00 Z</pubDate></item>

	<item><guid isPermaLink="true">https://leekelleher.com/2018/11/history-of-our-umbraco-package-names</guid><link>https://leekelleher.com/2018/11/history-of-our-umbraco-package-names</link><title>History of "Our.Umbraco.*" package names</title><description>&lt;p&gt;Earlier this year, &lt;a href="https://twitter.com/callumbwhyte/status/820641163334053889"&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"&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/" title="Umbraco community hacking"&gt;&lt;img src="/assets/media/umb-collab.jpg" alt="IMG_4590"&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/"&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/"&gt;Config Tree&lt;/a&gt; and &lt;a href="https://our.umbraco.com/packages/backoffice-extensions/google-maps-datatype/"&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/"&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"&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><pubDate>Tue, 27 Nov 2018 10:50:00 Z</pubDate></item>

	<item><guid isPermaLink="true">https://leekelleher.com/2018/01/umco</guid><link>https://leekelleher.com/2018/01/umco</link><title>UMCO</title><description>&lt;p&gt;I've been meaning to talk about UMCO for a while, but Matt got there before me... &lt;a href="https://outfield.digital/blog/what-exactly-is-umco/"&gt;What exactly is UMCO?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.flickr.com/photos/percipientstudios/18087735533/in/album-72157653985426100/" title="Lee and Matt hacking, Photo by Douglas Robar, Percipient Studios"&gt;&lt;img src="https://farm1.staticflickr.com/505/18087735533_6eaf4dfc3b_h.jpg" alt="CG15-1128"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;UMCO Links&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://outfield.digital/umco/"&gt;UMCO profile on Outfield Digital&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/UMCO"&gt;UMCO on GitHub - source-code for our Umbraco packages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;s&gt;&lt;a href="https://www.patreon.com/umco"&gt;UMCO Patreon page - if you'd like to support our work&lt;/a&gt;&lt;/s&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://weareumco.com/"&gt;We are UMCO - a landing page, with these links&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description><pubDate>Tue, 23 Jan 2018 12:38:00 Z</pubDate></item>

</channel>
</rss>