<?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>Forem: Joe Glombek</title>
    <description>The latest articles on Forem by Joe Glombek (@joeglombek).</description>
    <link>https://forem.com/joeglombek</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%2F288452%2F598a42a8-9f53-4a89-af7e-88e693f56966.jpg</url>
      <title>Forem: Joe Glombek</title>
      <link>https://forem.com/joeglombek</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/joeglombek"/>
    <language>en</language>
    <item>
      <title>Masto-meta: Gaining insights into fediverse accounts</title>
      <dc:creator>Joe Glombek</dc:creator>
      <pubDate>Sun, 24 Mar 2024 08:49:47 +0000</pubDate>
      <link>https://forem.com/joeglombek/masto-meta-gaining-insights-into-fediverse-accounts-f1o</link>
      <guid>https://forem.com/joeglombek/masto-meta-gaining-insights-into-fediverse-accounts-f1o</guid>
      <description>&lt;p&gt;Authenticity in the fediverse isn't as simple as a blue tick (then again, it's not that simple on Twitter any more either!) but there are some insights we can gather from a quick glace at a profile. I often see people attempting to interact with fediverse accounts that aren't real people, so these tips ought to help.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usernames and instances
&lt;/h2&gt;

&lt;p&gt;A fediverse username has two parts, the "local username" and the "instance name". For example, my current username is &lt;code&gt;@joe@umbracocommunity.social&lt;/code&gt;. &lt;code&gt;joe&lt;/code&gt; is my chosen username and &lt;code&gt;umbracocommunity.social&lt;/code&gt; is the domain name (web address) of the server or instance I signed up with. This isn't always a Mastodon server, but can be any ActivityPub compliant site.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://press.coop/about"&gt;press.coop&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;An account ending with &lt;code&gt;@press.coop&lt;/code&gt; are unofficial bots which scrape RSS feeds of various news sites. They reject replies to posts (but that won't stop you tagging them!) and no replies are visible to anyone at the news organisations. All accounts are marked as bots (see below) and have a meaningless gold checkmark emoji.&lt;a href="https://press.coop/@BBCNews"&gt;@BBCNews@press.coop&lt;/a&gt; is a popular account but has nothing to do with the BBC. Although &lt;a href="https://social.bbc/about"&gt;the BBC is running a trial of Mastodon&lt;/a&gt;, this does not yet include any official news sources.&lt;/p&gt;

&lt;h3&gt;
  
  
  bird.makeup (and other domains containing &lt;code&gt;bird&lt;/code&gt; or &lt;code&gt;birdsite&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://sr.ht/~cloutier/bird.makeup/"&gt;Bird.Makeup&lt;/a&gt; is an open-source one-way bridge from Twitter/X to the Fediverse. You cannot interact with a bird.makeup user, since the bridge is one way. There can also be sizable delays in posts appearing. There's no way to opt out or redirect from an old account to a new one, so &lt;code&gt;@umbristol@bird.makeup&lt;/code&gt; still works even though we have an active Mastodon account at &lt;code&gt;@umbristol@umbracocommunity.social&lt;/code&gt; - so make sure if you're tagging someone, you tag the right account! These are only good for reading posts from people not on the fediverse. Think &lt;a href="https://umbracocommunity.social/@potus@bird.makeup"&gt;@potus&lt;/a&gt; or &lt;a href="https://umbracocommunity.social/@callumbwhyte@bird.makeup"&gt;@callumbwhyte&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  threads.net
&lt;/h3&gt;

&lt;p&gt;This week, Instagram Threads announced they were extending their Fediverse trial to a wider audience - including all Threads accounts in the US, Canada and Japan (at time of writing). The integration must be &lt;a href="https://help.instagram.com/760878905943039"&gt;manually enabled&lt;/a&gt; is currently limited to one-way (Threads to Fediverse) meaning replies can't be seen from Threads and Threads users can't yet follow other Fediverse accounts, but Fediverse likes do show up in Threads.&lt;/p&gt;

&lt;p&gt;Interestingly verified accounts on Threads don't show up in the Mastodon interface in any way yet. But if you want, you can now follow what @&lt;a href="mailto:zuck@threads.net"&gt;zuck@threads.net&lt;/a&gt; has to say!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zxaK1RVv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://joe.gl/media/hh2pghqu/zuck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zxaK1RVv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://joe.gl/media/hh2pghqu/zuck.png" alt="A screenshot of Mark Zuckerberg's Threads profile from Mastodon." width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Sites that aren't a social network
&lt;/h3&gt;

&lt;p&gt;We already touched on &lt;code&gt;bird.makeup&lt;/code&gt; not being a Mastodon server. It's its own thing. But there's nothing stopping any site being on the Fediverse - you just need to implement certain API endpoints! This means that &lt;a href="https://wordpress.com/support/enter-the-fediverse/"&gt;many Wordpress blogs&lt;/a&gt; and other non-social network sites are followable from your Mastodon feed. Replies to posts from non-social networks can be a bit of an unknown. They may be rejected, ignored or show up as comments. Who knows!&lt;/p&gt;

&lt;p&gt;Warren's Hack Make Do blog is followable at &lt;a href="https://umbracocommunity.social/@blog.hackmakedo.com@blog.hackmakedo.com"&gt;@blog.hackmakedo.com@blog.hackmakedo.com&lt;/a&gt;, or you can choose to follow the human &lt;a href="https://umbracocommunity.social/@warrenbuckley"&gt;@warrenbuckley@umbracocommunity.social&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checkmarks
&lt;/h2&gt;

&lt;p&gt;You might see some accounts with checkmarks in the names of accounts. These are simply custom emoji on the instance the account lives on and means nothing special. Some instances &lt;em&gt;may&lt;/em&gt; restrict which accounts they allow to have a certain emoji, but there's no guarantee.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bot accounts
&lt;/h2&gt;

&lt;p&gt;Mastodon has a feature to clearly show whether an account is automated (a bot) or not. This isn't a bulletproof system - it generally relies on folks being honest about it. But if a profile displays a "Bot" or "Automated" flag (depending on the client you're using), don't expect a human reply if you get a reply at all!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://umbracocommunity.social/@umbfyi"&gt;@umbfyi@umbracocommunity.social&lt;/a&gt; is a bot account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8kU9RPeY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://joe.gl/media/4bedxzw0/umbfyi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8kU9RPeY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://joe.gl/media/4bedxzw0/umbfyi.png" alt="A screenshot of @umbfyi@umbracocommunity.social's profile, complete with an &amp;quot;Automated&amp;quot; or bot flag." width="800" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Link verification
&lt;/h2&gt;

&lt;p&gt;The best way to tell if a profile is genuine is through checking for verified links. Umbraco's official account is a great example of this. Since we already trust umbraco.com to be owned by Umbraco, the fact that @&lt;a href="mailto:Umbraco@umbracocommunity.social"&gt;Umbraco@umbracocommunity.social&lt;/a&gt; has a verified link for umbraco.com in their profile shows they have editorial control over that page. &lt;a href="https://joinmastodon.org/verification"&gt;You can verify multiple links using the &lt;code&gt;rel="me&lt;/code&gt; syntax&lt;/a&gt; in any page you can edit (your blog, Github profile, etc).&lt;/p&gt;

&lt;p&gt;The first verified link shows up in search results on the default Mastdon client:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oMNp481P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://joe.gl/media/2d1d52x2/umb-search.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oMNp481P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://joe.gl/media/2d1d52x2/umb-search.png" alt="A search result for Umbraco with the verified umbraco.com link" width="500" height="110"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and all links, verified or not, show up in the bio, although the verified links show in green with a checkmark:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PredV1D4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://joe.gl/media/ngggesak/umb-profile.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PredV1D4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://joe.gl/media/ngggesak/umb-profile.png" alt="A screenshot of Umbraco's profile with both verified links" width="800" height="686"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to tell a user is genuine
&lt;/h2&gt;

&lt;p&gt;So, in summary, to check you're interacting with the correct account:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Check for validated links&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Do you trust the server?&lt;/li&gt;
&lt;li&gt;Are they a bot?&lt;/li&gt;
&lt;li&gt;Check their bio (sometimes they'll state they're unofficial)&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>fediverse</category>
      <category>mastodon</category>
      <category>verification</category>
    </item>
    <item>
      <title>What do we mean when we say “Umbraco”?</title>
      <dc:creator>Joe Glombek</dc:creator>
      <pubDate>Thu, 07 Dec 2023 08:00:56 +0000</pubDate>
      <link>https://forem.com/joeglombek/what-do-we-mean-when-we-say-umbraco-4fom</link>
      <guid>https://forem.com/joeglombek/what-do-we-mean-when-we-say-umbraco-4fom</guid>
      <description>&lt;p&gt;&lt;strong&gt;Spoiler: we don’t always mean the CMS.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you’re reading this article, there’s a high chance you're acquainted with Umbraco, but perhaps you're not fully aware of the nuance that comes with the phrase. So what exactly do we mean when we say “Umbraco”?&lt;/p&gt;

&lt;p&gt;The term encompasses more than just a CMS; it embodies a rich, open-source ecosystem consisting of the Umbraco CMS, the vibrant Umbraco Community, and our custodian and driving force, Umbraco HQ. Let's delve into all things “Umbraco” to uncover the multifaceted meanings and explore the intriguing interplay between these components.&lt;/p&gt;

&lt;h2&gt;
  
  
  “Unbrako” the contraption
&lt;/h2&gt;

&lt;p&gt;Unbrako is the Danish name for an Allen key - that’s a “hex wrench” if you want the &lt;em&gt;real&lt;/em&gt; name - and although to most of you reading this article this one is unlikely to cause any confusion Umbraco HQ say they do &lt;a href="https://umbraco.com/about-us/why-are-we-called-umbraco/"&gt;occasionally get Allen-key purchase requests&lt;/a&gt;. But that’s not &lt;em&gt;really&lt;/em&gt; what this article is about!&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%2Ftaxjubez3wbz1ly5xzwi.jpg" 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%2Ftaxjubez3wbz1ly5xzwi.jpg" alt="Hex wrenches of multiple sizes hanging on a wall, surrounded by other tools" width="800" height="432"&gt;&lt;/a&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@tonchik?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash"&gt;Anton Savinov&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-bunch-of-tools-are-hanging-on-a-wall-EDhZOuEMHXo?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash"&gt;Unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  “Umbraco” the CMS
&lt;/h2&gt;

&lt;p&gt;According to Umbraco HQ (we’ll get onto that!):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Umbraco is a CMS that’s fully extendable, highly customizable, and user-friendly.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Umbraco CMS is the product all this “Umbraco” hangs off of. Created in 1999 by Niels Hartvig and open sourced in 2005, Umbraco has undergone significant transformations, evolving from a basic CMS to a sophisticated platform that powers websites of all sizes.&lt;/p&gt;

&lt;p&gt;Umbraco has always (at least since I’ve been around) been pitched as &lt;a href="https://umbraco.com/about-us/values/why-the-friendly-cms/"&gt;“The Friendly CMS”&lt;/a&gt; which, as well as hinting at it’s user- and developer-friendliness and open-source nature, indicates how welcoming the community is. Community is a large part of what makes Umbraco, Umbraco. But it’s sometimes important to make the distinction between the two.&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%2F6cu8mbpbd28c8gtzjwa6.jpg" 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%2F6cu8mbpbd28c8gtzjwa6.jpg" alt='A photo by Umbraco HQ on Flickr of large 3D letters "CMS" at Codegarden.' width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  “Umbraco” the community
&lt;/h2&gt;

&lt;p&gt;The first Codegarden in 2005 is our first indication of the beginnings of the Umbraco Community and it’s grown hugely from there. Communities often form around open source projects as people from across the world problem-solve and learn together to produce something that benefits themselves and other users, all with a shared philosophy for free (as in beer and as in speech) software. But I’ve heard &lt;a href="https://umbracocommunity.social/@emaburst"&gt;Emma Burstow, Director of Developer Relations at Umbraco HQ&lt;/a&gt;, proudly state that people refer to Umbraco as “the one with the community”, which surely shows we have something special going on!&lt;/p&gt;

&lt;p&gt;The Umbraco Community is also set apart from other software communities because of who make up our community. In a recent conversation with &lt;a href="https://umbracocommunity.social/@carlcod_es"&gt;Carl Sargunar&lt;/a&gt;, he pointed out:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Very unusually Umbraco isn’t a community of developers, it’s a community of people who use the platform”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Umbraco Community is so much more than the occasional developer making the odd code contribution - it’s a lifestyle choice! And I only mean that partially as a joke! Codegarden, community-run conferences, &lt;a href="https://codecab.in"&gt;unconferences&lt;/a&gt;, &lt;a href="https://www.meetup.com/pro/umbraco/"&gt;meetups&lt;/a&gt;, gaming sessions, social media, podcasts, a whole &lt;a href="https://skrift.io"&gt;digital magazine&lt;/a&gt;, &lt;a href="https://umbracocommunity.social"&gt;a federated social network instance&lt;/a&gt;, and even daily Wordle-sharing mean we’re never far away from our friends in the community.&lt;/p&gt;

&lt;p&gt;Although largely developers, the community very actively includes agency owners, account and project managers, CMS administrators, end users and Umbraco HQ employees - the Umbraco Community is more about the lifestyle surrounding Umbraco than the code.&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%2F1xfv1p51z46oiom6e2m5.jpg" 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%2F1xfv1p51z46oiom6e2m5.jpg" alt="A photo by Umbraco HQ on Flickr of MVPs and a couple of HQers on stage at Codegarden 2023, celebrating the announcements of the new MVPs" width="800" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repeat &lt;del&gt;offenders&lt;/del&gt; contributors are acknowledged by Umbraco HQ through the &lt;a href="https://mvp.umbraco.com/"&gt;MVP programme&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Umbraco community members call each other “Umbracians” (&lt;em&gt;um-brak-ians&lt;/em&gt; or &lt;em&gt;umb-raishe-ans&lt;/em&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  “Umbraco” the company
&lt;/h2&gt;

&lt;p&gt;Umbraco, Umbraco HQ, or just “HQ” is the name we use for the company, Umbraco A/S (and Umbraco, LLC in the US). HQ are the maintainers of the Umbraco CMS but also own the Umbraco commercial products Cloud, Heartcore, Forms, Commerce, Deploy, Workflow and UI Builder. They also monetize Umbraco through the sale of support plans.&lt;/p&gt;

&lt;p&gt;HQ hires a developer relations team including developer advocates (also &lt;a href="https://medium.com/@unicodeveloper/the-birth-of-developer-avocados-61e4ac235033"&gt;called developer avocados 🥑&lt;/a&gt;) whose role is to encourage and grow the community.&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%2F8g9wc6bn1hcnyd1t8e3i.jpg" 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%2F8g9wc6bn1hcnyd1t8e3i.jpg" alt="A photo by Umbraco HQ on Flickr of a group photo of HQ employees from Codegarden 2022. They have their hands raised in the air and are smiling and cheering." width="800" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Members of staff at HQ are “HQers”.&lt;/p&gt;

&lt;p&gt;Just to confuse things even more “HQ” can also refer to the &lt;a href="https://umbraco.com/contact-us/"&gt;physical office locations of Umbraco A/S and Umbraco, LLC&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where paths cross
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Community recognition
&lt;/h3&gt;

&lt;p&gt;It surprises me how often a community-run conference, meetup or package gets attributed to Umbraco HQ or assuming organisers, speakers or community teams members are paid for their efforts.&lt;/p&gt;

&lt;p&gt;Although I consider open-source as part of my job (and I’m lucky enough to have an employer who agrees), even I pour more emotional and time effort into community contributions than I do into the rest of my day job (it’s hard to get too emotionally invested in C#, eh?). And I’m one of the lucky ones: many community members are dedicating evenings and weekends to make their contributions.&lt;/p&gt;

&lt;p&gt;The community can benefit itself by acknowledging non-profit community effort. Acknowledgement and appreciation go a long way to making a contribution feel worthwhile.&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%2F8eorf0f3ztblarp3uucm.jpg" 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%2F8eorf0f3ztblarp3uucm.jpg" alt="A photo by Umbraco HQ on Flickr of a man holding a Captain America-style shield with an orange Umbraco logo in the centre" width="800" height="532"&gt;&lt;/a&gt;&lt;em&gt;Not all heroes wear capes, but this one &lt;strong&gt;does&lt;/strong&gt; have a shield. Photo by &lt;a href="https://www.flickr.com/photos/149619560@N07/52993707730/"&gt;Umbraco HQ on Flickr&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;But also, &lt;a href="https://engineering.atspotify.com/2022/10/open-source-work-is-work/"&gt;open source &lt;em&gt;is&lt;/em&gt; work&lt;/a&gt; and employers who profit from the Umbraco CMS and community should do more to support their own employees’ contributions as well as sponsor open source packages and community events that directly benefit their business. Umbraco co-founder, community member and Director at Docker, &lt;a href="https://twitter.com/pploug"&gt;Per Ploug&lt;/a&gt;, has &lt;a href="https://engineering.atspotify.com/2022/10/open-source-work-is-work/"&gt;written about this&lt;/a&gt; and his &lt;a href="https://www.youtube.com/watch?v=QAttjA8brVs"&gt;Codegarden talk is available to watch online&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Money for “nothing”
&lt;/h3&gt;

&lt;p&gt;Umbraco CMS, being open source, is free to anyone who wants to download and use it. This makes things difficult for open source maintainers, like Umbraco HQ, who need to sustain a business while giving their primary product away for free.&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%2Fas4rmo9oodadmk6o2z5i.jpg" 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%2Fas4rmo9oodadmk6o2z5i.jpg" alt="A photo by Umbraco HQ on Flickr of Joe helping himself to sweets at Codegarden, next to a sign reading “Candy bar - Self-service”" width="800" height="440"&gt;&lt;/a&gt;&lt;em&gt;Rumour has it people like free things. Photo by &lt;a href="https://www.flickr.com/photos/149619560@N07/52993834798/"&gt;Umbraco HQ on Flickr&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Since 2021 Umbraco HQ has been owned by Monterro, a growth investor. Open source maintenance is an unusual business model, and since the Monterro investment, we’ve seen a larger push for commercial offerings from Umbraco but there remains a huge focus on open-source offering and the community.&lt;/p&gt;

&lt;p&gt;Traditionally, &lt;a href="https://www.forbes.com/sites/forbestechcouncil/2023/02/02/how-to-make-open-source-profitable/"&gt;open source maintainers make money by providing services&lt;/a&gt; and Umbraco HQ is no different. HQ sell Umbraco Cloud as a SAAS offering along with additional premium packages and support. Although Umbraco tends to avoid these situations, this business model can result in priorities misaligning with the community.&lt;/p&gt;

&lt;h3&gt;
  
  
  Community as a Commodity
&lt;/h3&gt;

&lt;p&gt;It’s sometimes important to attach a business case to the value of a community to ensure a business like Umbraco HQ can continue to invest in their communities. And as &lt;a href="https://twitter.com/umbraco/status/1714197052735832199"&gt;pointed out by Emma Burstow&lt;/a&gt;, businesses are finally starting to see value in community because&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“People are less inclined to buy things from sales people and far more likely to buy things from people like them”.&lt;/p&gt;
&lt;/blockquote&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%2Fb3xx0kdtdcu7mdimic2v.jpg" 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%2Fb3xx0kdtdcu7mdimic2v.jpg" alt="A photo by Umbraco HQ on Flickr of two people in rabbit costumes holding up a board covered in “bats” including a jar of rubber bat toys, a model Batmobile, a padel racket and two ping-pong paddles." width="800" height="341"&gt;&lt;/a&gt;&lt;em&gt;Are bats on a board a “commodity”? Photo by &lt;a href="https://www.flickr.com/photos/149619560@N07/52992756002/"&gt;Umbraco HQ on Flickr&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;However, the attitude of community members and their contributions being seen as commodities can be difficult for community members.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Venture capitalists are actually using community activity as one of the metrics that they’re going to measure against before they acquire companies”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Contributions aren’t made to keep Umbraco HQ valuable and afloat, they’re made for the betterment of the open-source product, to encourage the progression of individuals within the community and to grow the community itself. But in doing so, contributors provide value to HQ. And although we all see value in Umbraco HQ doing well, a volunteer contribution benefiting a profitable company can feel uncomfortable.&lt;/p&gt;

&lt;p&gt;It is important to comprehend that businesses understanding the value of community does mean that they can justify investing more time and money into fostering the community. And Umbraco HQ does put a lot of time and effort into fostering the Umbraco Community: Umbraco now has a dedicated developer relations team and fund community-run events. A strong community (as a commodity) can ensure their stewardship of the open source portions of the platform for many more years to come.&lt;/p&gt;

&lt;h3&gt;
  
  
  Accountability
&lt;/h3&gt;

&lt;p&gt;“&lt;em&gt;Stewardship&lt;/em&gt;” is an important word there. Umbraco HQ own the trademarks around the name Umbraco, but the CMS itself is in the public domain. Under &lt;a href="https://www.tldrlegal.com/license/mit-license"&gt;the MIT License&lt;/a&gt;, people are free to “use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies” of Umbraco CMS. If Umbraco HQ ceased to be, or made a questionable product decision, the Umbraco CMS would likely continue to exist under a different name, possibly along with the community.&lt;/p&gt;

&lt;p&gt;This has happened before, with the &lt;a href="https://umbraco.com/about-us/what-happened-to-version-5/"&gt;death of Umbraco 5&lt;/a&gt;, members of the community split off from Umbraco and created &lt;a href="https://github.com/RebelCMS/rebelcmsxu5"&gt;RebelCMS&lt;/a&gt;. The CMS was short-lived, with the last commit now almost 12 years ago, but it does show that it can be done.&lt;/p&gt;

&lt;p&gt;This is an important thing to remember because, although it’s very unlikely to happen, it makes Umbraco HQ accountable to the community - they can’t do something strongly against what the community wants and need to listen to the community’s requests to keep their stewardship. This fact helps to ensure that community-effort, although benefiting Umbraco HQ, means that HQ’s profitability benefits the community, in a circular way.&lt;/p&gt;

&lt;h2&gt;
  
  
  A delicate balance
&lt;/h2&gt;

&lt;p&gt;I don’t mean for this article to cause any controversy, but believe the discussion around profitability and open source is an important one and needs to be had out in the open. The Umbraco CMS can continue to provide a valuable product for both Umbraco HQ and the Umbraco Community, but it’s a delicate balance and as a community we need to acknowledge where conflicts of interest may arise.&lt;/p&gt;

&lt;p&gt;As contributors we should know who our contribution benefits, and ensure we’re getting enough value for ourselves from that interaction to prevent feeling cheated or burning out.&lt;/p&gt;

&lt;p&gt;It’s also vital that Umbraco HQ continue to recognise the value of the community in steering the direction of the Umbraco CMS.&lt;/p&gt;

&lt;p&gt;Together, we’ve build something great and are continuing to build something even better.&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%2F1jkg210ylep0zyfadeve.jpg" 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%2F1jkg210ylep0zyfadeve.jpg" alt="A photo by Umbraco HQ on Flickr of Codegarden 2023 attendees sat at long tables, with hands raised in the air ready to play bingo!" width="800" height="532"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>umbraco</category>
      <category>community</category>
    </item>
    <item>
      <title>Azure DevOps Pipelines breaks my "additional arguments" when using Deploy to Azure</title>
      <dc:creator>Joe Glombek</dc:creator>
      <pubDate>Thu, 16 Nov 2023 12:21:55 +0000</pubDate>
      <link>https://forem.com/joeglombek/azure-devops-pipelines-breaks-my-additional-arguments-when-using-deploy-to-azure-ck2</link>
      <guid>https://forem.com/joeglombek/azure-devops-pipelines-breaks-my-additional-arguments-when-using-deploy-to-azure-ck2</guid>
      <description>&lt;p&gt;Recently, something in the Azure DevOps Pipelines "Deploy to Azure" flow has been messing up parameters in the "additional arguments" field under "Additional Deployment Options".&lt;/p&gt;

&lt;p&gt;We historically had parameters to skip the &lt;code&gt;umbraco&lt;/code&gt; and &lt;code&gt;umbraco_client&lt;/code&gt; folders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-skip:objectname=filePath,absolutepath="\\(umbraco|umbraco_client)\\" -skip:objectname=dirPath,absolutepath="\\(umbraco|umbraco_client)\\"

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

&lt;/div&gt;



&lt;p&gt;However, somewhere along the lines, this was being corrupted to produce the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;msdeploy.exe [...] -skip:objectname=filePath,absolutepath="\\\(umbraco|umbraco_client)\\" -skip:objectname=dirPath\,absolutepath=\\(umbraco|umbraco_client)\\

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

&lt;/div&gt;



&lt;p&gt;And thus, the error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;##[error]Error: 'umbraco_client)\\' is not recognized as an internal or external command, operable program or batch file.

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

&lt;/div&gt;



&lt;p&gt;It looks like Pipelines is doing &lt;em&gt;some&lt;/em&gt; of the work to escape backslashes (&lt;code&gt;\&lt;/code&gt;) and double quotes (&lt;code&gt;"&lt;/code&gt;) itself but getting confused, removing some, and adding them back in all the wrong places!&lt;/p&gt;

&lt;p&gt;We tried various variations of removing and escaping with different characters, trying to reverse-engineer what Pipelines was doing to our simple text string until &lt;a href="https://ie.linkedin.com/in/fnmenezes/en"&gt;Fernando&lt;/a&gt; suggested removing the (required) quotes altogether, which worked!&lt;/p&gt;

&lt;p&gt;Additional arguments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-skip:objectname=filePath,absolutepath=\\(umbraco|umbraco_client)\\ -skip:objectname=dirPath,absolutepath=\\(umbraco|umbraco_client)\\

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

&lt;/div&gt;



&lt;p&gt;Generated command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;msdeploy.exe [...] -skip:objectname=filePath,absolutepath="\\(umbraco|umbraco_client)\\" -skip:objectname=dirPath,absolutepath="\\(umbraco|umbraco_client)\\"

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

&lt;/div&gt;



&lt;p&gt;If anybody has any further insight into this, please do to &lt;a href="https://joe.gl/ombek/contact/"&gt;get in touch via social media&lt;/a&gt; - I'd love to expand on the details here.&lt;/p&gt;

</description>
      <category>cicd</category>
      <category>devops</category>
      <category>pipelines</category>
    </item>
    <item>
      <title>Umbrastodon: the Umbraco Community in the Fediverse and on Mastodon</title>
      <dc:creator>Joe Glombek</dc:creator>
      <pubDate>Fri, 15 Sep 2023 02:29:11 +0000</pubDate>
      <link>https://forem.com/joeglombek/umbrastodon-the-umbraco-community-in-the-fediverse-and-on-mastodon-3c5k</link>
      <guid>https://forem.com/joeglombek/umbrastodon-the-umbraco-community-in-the-fediverse-and-on-mastodon-3c5k</guid>
      <description>&lt;p&gt;A guide to getting started with Mastodon and the Fediverse tailored to the Umbraco Community.&lt;/p&gt;

&lt;p&gt;Following on from discussions around how distributed our online communities have become since the ongoing fall of Twitter/X on &lt;a href="https://owain.codes/blogs/2023/september/where-is-the-umbraco-community/"&gt;Owain's blog&lt;/a&gt; and &lt;a href="https://www.youtube.com/live/uIxj2gzMqSQ?si=5kARiGdX1jsW9rQr&amp;amp;t=1817"&gt;UmbraCoffee #292&lt;/a&gt;, Mastodon has been raised as one of the locations the community is slowly moving to. As an established Fediverse user, and admin of the &lt;a href="https://umbracocommunity.social"&gt;UmbracoCommunity.social&lt;/a&gt; Mastodon instance, some people have been asking me Mastodon questions and I thought a blog post might be a good way to communicate these tips to a wider audience.&lt;/p&gt;

&lt;p&gt;I've &lt;a href="https://umbracocommunity.social/@joe/111022977851392865"&gt;mentioned before&lt;/a&gt; how I hope Federation is the future of social networking and how &lt;a href="https://umbracocommunity.social/@joe/111062571685624450"&gt;Mastodon may well fit the needs of the Umbraco Community going forwards&lt;/a&gt;, and I truly believe we need something analogous to "old" Twitter, that's less instant than chat tools such as Discord, more social than the Forums and shorter form than blog posts. Mastodon can be just that.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Fediverse?
&lt;/h2&gt;

&lt;p&gt;This blog post is tailored to the Umbraco Community, so I won't go into all the details here, but will keep to the relevant parts.&lt;/p&gt;

&lt;p&gt;The Fediverse is generally used to refer to a group of servers that conform to the ActivityPub standard. Each of these servers pushes content out to the Fediverse and wider internet. The content could be blog posts, microblogs, photos, comments or anything else we as people create on the internet.&lt;/p&gt;

&lt;p&gt;These servers within the Fediverse are subcategorised by the software they run. The software is generally analogous with a "traditional" social media platform. For example, Mastodon focusses on microblogging (think Twitter), Pixelfed is all about social image sharing (think Instagram) and Lemmy hosts communities (think Reddit). You can follow a Lemmy community or Pixelfed account from your Mastodon account too - because they all use the same protocol.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Mastodon?
&lt;/h2&gt;

&lt;p&gt;I've explained how Mastodon is the ActivityPub-compliant software running on a server., but the concept is much greater than that! Because the ActivityPub protocol allows these servers to talk to one another and because Mastodon is free and open source, you don't have to sign up to Mastodon's own server - you can join a community (&lt;em&gt;server&lt;/em&gt; or &lt;em&gt;instance&lt;/em&gt;) of your choice.&lt;/p&gt;

&lt;p&gt;This can be a barrier to entry for those unsure about how Mastodon works, but in practice this architecture helps us build a more resilient and tailored social media platform.&lt;/p&gt;

&lt;p&gt;Because Mastodon is distributed across multiple servers, usernames take the format &lt;code&gt;@[local-username]@[server-domain]&lt;/code&gt;, for example, my username is &lt;a href="https://umbracocommunity.social/@joe"&gt;@joe@umbracocommunity.social&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why does it fit so well with the Umbraco Community?
&lt;/h2&gt;

&lt;p&gt;I've already used the phrases "open source" and "communities" when describing Mastodon, and this is a large reason I believe Mastodon could be a large part of the future Umbraco Community: our ethea align.&lt;/p&gt;

&lt;p&gt;An Umbraco-focusses Mastodon instance allows Umbraco to be the primary focus of an instance with additional Umbraco-related content easier to discover for users. But the way that federation works, means that the common interests of Umbracian's on the Umbraco Mastodon also become discoverable by the community, such as .NET, open source and Lego.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do I join?
&lt;/h2&gt;

&lt;p&gt;So, if you want to become a part of the Fediverse, you first choose a server. It's not the be-all and end-all if you change your mind later, you can move (although your &lt;del&gt;Tweets&lt;/del&gt; posts (or "Toots") don't come with you) your account to a different server at a later date (see below).&lt;/p&gt;

&lt;h3&gt;
  
  
  Which server(s)?
&lt;/h3&gt;

&lt;p&gt;Mastodon instances tend to cater to interests. Although there are generic instances too.&lt;/p&gt;

&lt;p&gt;The more generic and larger your instance, the closer to a Twitter experience you get. But that's not where the power of Mastodon lies, in my opinion you're better off joining a niche.&lt;/p&gt;

&lt;p&gt;Personally, I find &lt;a href="https://umbracocommunity.social"&gt;UmbracoCommunity.social&lt;/a&gt; a fantastic compromise - the community is niche enough to mean the public feed (see "Getting the most out of Umbrastodon") is relevant to me but not so small as to limit it, although as an admin there, I may be biased!&lt;/p&gt;

&lt;h4&gt;
  
  
  Popular interest-specific servers within the Umbraco Community
&lt;/h4&gt;

&lt;p&gt;If a lot of what you do online is techy, these instances may work better for you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://umbracocommunity.social"&gt;UmbracoCommunity.social&lt;/a&gt; is a Mastodon server set up specifically for the Umbraco Community and is hosted by &lt;a href="https://umbracocommunity.social/@steve_gibe"&gt;Steve Temple&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hachyderm.io"&gt;Hachyderm&lt;/a&gt;, pronounced hack-a-derm (that's right, it's a mastodon/pachyderm pun!) is a hugely popular generic-tech instance&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://fosstodon.org"&gt;Fosstodon&lt;/a&gt; is dedicated to open source software&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://infosec.exchange"&gt;Infosec.exchange&lt;/a&gt; for you infosec folk&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://front-end.social"&gt;front-end.social&lt;/a&gt; for you frontenders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also find your own niche by checking the &lt;a href="https://joinmastodon.org/servers"&gt;Mastodon server listing&lt;/a&gt; where you can filter by language, hosting country and interest.&lt;/p&gt;

&lt;h4&gt;
  
  
  Popular generic instances
&lt;/h4&gt;

&lt;p&gt;From the UmbracoCommunity.social statistics, here are the most popular generic instances used by the Umbraco Community:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://mastodon.social/"&gt;Mastodon.social&lt;/a&gt; is the original server operated by Mastodon, its hugely popular and a great place to start if you can't find a niche&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mstdn.social"&gt;mstdn.social&lt;/a&gt; another generic instance with a shorter URL&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://mastodon.green"&gt;Mastodon.Green&lt;/a&gt; a paid-for server who run off renewable energy and plant trees with 20% of the monthly fee&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Host your own
&lt;/h4&gt;

&lt;p&gt;If none of these take your fancy, you can also host your own instance and be in full control of your own data - &lt;a href="https://cultiv.social/@sebastiaan"&gt;Seb has a server just for his account&lt;/a&gt;. &lt;a href="https://masto.host/"&gt;Mastohost&lt;/a&gt; is a simple and affordable way to set up your own instance. Be aware, though, it can get lonely on your own - you lose a lot of discoverability by being on a single-person server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Already a Mastodon/Fediverse user?
&lt;/h2&gt;

&lt;p&gt;If you're already in the Fediverse but want more Umbraco in your feed, here are some options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use your existing Mastodon account and follow whoever you want from UmbracoCommunity.social by &lt;a href="https://umbracocommunity.social/directory"&gt;looking at the directory to find accounts&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create a second Mastodon account on &lt;a href="https://umbracocommunity.social"&gt;UmbracoCommunity.social&lt;/a&gt; if you want to keep your Umbraco Fediverse account separate from your other account&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.joinmastodon.org/user/moving/"&gt;Migrate your account&lt;/a&gt; to &lt;a href="https://umbracocommunity.social"&gt;UmbracoCommunity.social&lt;/a&gt;. Your old account gets redirected, but beware your old posts will stay put.&lt;/li&gt;
&lt;li&gt;Make use of the public feeds on UmbracoCommunity as it’s quite a good mix of Umbraco and .NET devs: &lt;a href="https://umbracocommunity.social/public/local"&gt;the local feed (all posts on UmbracoCommunity instance)&lt;/a&gt; and &lt;a href="https://umbracocommunity.social/public"&gt;the federated feed (all posts from people followed by anybody on the UmbracoCommunity instance)&lt;/a&gt;. Some mastodon clients let you add these feeds into your app too!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Getting the most out of Umbrastodon!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;As above, &lt;a href="https://cultiv.social/@sebastiaan/111062300610264145"&gt;Seb suggests&lt;/a&gt; making full use of the use of the &lt;strong&gt;public feeds&lt;/strong&gt; to find relevant content.&lt;/li&gt;
&lt;li&gt;Make use of a &lt;strong&gt;browser plugin&lt;/strong&gt; (like &lt;a href="https://graze.jaredzimmerman.com/"&gt;Graze for Mastodon&lt;/a&gt;) to make your web browsing experience of Mastodon easier&lt;/li&gt;
&lt;li&gt;Find &lt;strong&gt;apps&lt;/strong&gt; that works for you - I personally like &lt;a href="https://apps.apple.com/app/ice-cubes-for-mastodon/id6444915884"&gt;Ice Cubes on iOS&lt;/a&gt; and &lt;a href="https://elk.zone"&gt;Elk for desktop&lt;/a&gt; but &lt;a href="https://joinmastodon.org/apps"&gt;the app directory has loads of options&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Follow me!&lt;/strong&gt; I'm &lt;a href="https://umbracocommunity.social/@joe"&gt;@joe@umbracocommunity.social&lt;/a&gt; on Mastodon and &lt;a href="https://expl.red/@joe"&gt;@joe@expl.red&lt;/a&gt; on Pixelfed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;See you in the Fediverse!&lt;/p&gt;

</description>
      <category>umbraco</category>
      <category>mastodon</category>
      <category>fediverse</category>
      <category>community</category>
    </item>
    <item>
      <title>Umbracadabra! Defence Against the Dark Arts of Magic Strings in Umbraco</title>
      <dc:creator>Joe Glombek</dc:creator>
      <pubDate>Mon, 06 Dec 2021 09:00:00 +0000</pubDate>
      <link>https://forem.com/joeglombek/umbracadabra-defence-against-the-dark-arts-of-magic-strings-in-umbraco-43k0</link>
      <guid>https://forem.com/joeglombek/umbracadabra-defence-against-the-dark-arts-of-magic-strings-in-umbraco-43k0</guid>
      <description>&lt;p&gt;I'm sure many of us have been told at some point in our careers that "magic strings are bad" but why exactly is that and what could go wrong? And what alternatives are there to improve our code?&lt;/p&gt;

&lt;h2&gt;
  
  
  Why are magic strings so bad?
&lt;/h2&gt;

&lt;p&gt;We use the phrase "magic strings" (and, to a lesser extent, "magic numbers") to refer to a constant string used directly in your code. An example of this that we, as Umbraco developers, may be all too familiar with is &lt;code&gt;Model.GetPropertyValue("bodyText")&lt;/code&gt;. Here, &lt;code&gt;"bodyText"&lt;/code&gt; is the magic string. The text can be used in multiple places (maybe in the meta tags as well as the page body, or on different templates), has to be in this exact format (I can't swap it out with &lt;code&gt;"Can I have the text for the body please?"&lt;/code&gt;, as polite as that is) and refers to an external entity (the Umbraco database via the Umbraco APIs in this case). These things make it a particularly code-smelly example of a magic string that needs replacing.&lt;/p&gt;

&lt;p&gt;Magic strings is a term used to cover multiple scenarios of when a string is used in place of a more robust method.&lt;/p&gt;

&lt;p&gt;Typos: the arch enemy of magic strings. If we're having a particularly productive, Hollywood-hacker-style afternoon, smacking away at those keys, you'd be excused for mis-hitting the odd one.&lt;/p&gt;


&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mR16WnpP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://24days.in/media/tjymsoqs/hacking.gif" alt="Clip from NCIS showing two people typing manically on one keyboard" width="" height=""&gt;


&lt;p&gt;&lt;em&gt;Clip from NCIS showing two people typing manically on one keyboard&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;They can be particularly difficult to spot too: depending on your font, &lt;code&gt;"bodyIext"&lt;/code&gt; could easily go unnoticed. The folks that write our IDE's know this, and will correct us where possible. A string, however, cannot be autocorrected because &lt;em&gt;any&lt;/em&gt; value of string &lt;em&gt;is a valid string&lt;/em&gt;. As far as the IDE knows, you meant to type &lt;code&gt;"bossyTRex"&lt;/code&gt;. These cause runtime errors rather than the easier-to-spot compile-time issues.&lt;/p&gt;

&lt;p&gt;Fat-fingered-ness aside, magic strings can be exclusive to those who speak a different first language or people who have difficulty reading and writing. Even if you speak the same language issues can arise when trying to agree how to spell "colour"!&lt;/p&gt;

&lt;p&gt;Or how about a piece of logic that sets &lt;code&gt;this.ValidationMethod = "none"&lt;/code&gt;. We then later decide we need to change the validation method, but it's not obvious what the other possible values are. Magic strings aren't self-documenting and so we rely on reference documents or "there's a comment that explains how to use it somewhere" or "didn't I put that in the README file". This is far from ideal.&lt;/p&gt;

&lt;p&gt;And if all that wasn't enough, magic strings make it more difficult to replace a value, test your code or change logic on your test environments compared to production. We can do better!&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there such thing as a muggle string?
&lt;/h3&gt;

&lt;p&gt;Are there cases when a string is non-magic? Or perhaps when a magic string is ok? Yes, not all strings are magic strings and not all magic strings are nescessarily bad.&lt;/p&gt;

&lt;p&gt;If you're typing a string value in code, the blog &lt;a href="http://www.douevencode.com/articles/2017-11/magic-strings-not-always-bad/"&gt;do you even code, bro?&lt;/a&gt; has boiled it down to 4 questions you need to ask yourself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Can you reuse this constant?&lt;/li&gt;
&lt;li&gt;Can you easily change a few values at once?&lt;/li&gt;
&lt;li&gt;Does it improve readability?&lt;/li&gt;
&lt;li&gt;Is it part of configuration?&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;This won't cover all scenarios, but it's a good place to get started. If any of your answers to these questions is "yes", it's time to look into alternatives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Did you just casually drop the term "magic numbers" too? I've only just got to grips with magic strings!
&lt;/h3&gt;

&lt;p&gt;Ah, yes. Sorry about that!&lt;/p&gt;

&lt;p&gt;Yes, magic numbers are the lesser talked about sibling of magic strings. But they can cause the same sorts of issues.&lt;/p&gt;

&lt;p&gt;Take this code as an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void PrepareForCheckout() {
    if(Customer.Country == "United Kingdom") {
        FinalValue = Value * 1.175;
    }
}

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

&lt;/div&gt;



&lt;p&gt;It's not immediately obvious what this 1.175 is. You might have picked up that it's the old tax rate in the UK of 17.5%, but it could easily be missed, especially by a non-British developer.&lt;/p&gt;

&lt;p&gt;Now that we know this is the VAT rate, we also know it's wrong. The UK changed their VAT rate to 20% a few years back. Correcting this value could be difficult too - we need to replace all instances, but if it's written as &lt;code&gt;value = value + value * (17.5/100)&lt;/code&gt; (someone has gone about code clarity in an odd way!), a simple find-and-replace won't suffice.&lt;/p&gt;

&lt;p&gt;If, for example, we had a constant of this value somewhere that we reference from everywhere, it would be both clearer what the code was doing &lt;em&gt;and&lt;/em&gt; easier to update.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void PrepareForCheckout() {
    if(Customer.Country == "United Kingdom") {
        FinalValue = Value * UkVatRate;
    }
}

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

&lt;/div&gt;



&lt;p&gt;Now, there are many other tweaks we could make to this code, but I've just solved the one we've been talking about.&lt;/p&gt;

&lt;h2&gt;
  
  
  ModelsBuilder to the rescue
&lt;/h2&gt;

&lt;p&gt;The first example I gave in this article was &lt;code&gt;Model.GetPropertyValue("bodyText")&lt;/code&gt;, which, back in the Umbraco 7-days of 2013, &lt;a href="https://twitter.com/zpqrtbnk"&gt;Stephan Gay aka ZpqrtBnk&lt;/a&gt; identified as a problem and developed the &lt;a href="https://github.com/modelsbuilder/ModelsBuilder.Original"&gt;ModelsBuilder&lt;/a&gt; package. ModelsBuilder is now a part of Umbraco and if you're not using already, you &lt;em&gt;really&lt;/em&gt; should be. It removes the need for magic strings when interacting with IPublishedContent across our Umbraco solutions by generating models for each document type. Dave Woestenborghs wrote an article on &lt;a href="https://24days.in/umbraco-cms/2016/getting-started-with-modelsbuilder/"&gt;Getting started with Umbraco Modelsbuilder&lt;/a&gt; back in 2016 which still holds up well.&lt;/p&gt;

&lt;h2&gt;
  
  
  A &lt;em&gt;constant&lt;/em&gt; problem
&lt;/h2&gt;

&lt;p&gt;I mentioned creating a constant just now. And that's probably one of the simplest methods of avoiding magic strings. Depending on the size and complexity of your project, it can be as simple as pulling your strings up to constant declarations in your class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Cart {
    private const string BodyTextKey = "bodyText";
    private const decimal UkVatRate = 1.175;

    //...
}

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

&lt;/div&gt;



&lt;p&gt;In .NET, constants (&lt;code&gt;const&lt;/code&gt; declarations) are actually pretty efficient - at compile-time, they're not allocated any memory like variables are, so it's equivalent performance-wise to directly using the string in each location. It does, however, help us out a lot pre-compilation by removing the magic strings.&lt;/p&gt;

&lt;p&gt;To make constants reusable across your project you might find it useful to create a &lt;code&gt;Constants.cs&lt;/code&gt; file in your project and stick all your relevant strings in there. This can get pretty cluttered on bigger projects, so you may need to categorise your constants further, grouping them into logical classes and namespaces or adding your constants to related services like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static class VatHelper {
    public const decimal UkVatRate = 1.175;

    //...
}

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

&lt;/div&gt;



&lt;p&gt;In fact, with a helper, we could go even further in case we need to apply VAT to other countries in the future:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static class VatHelper {
    public decimal GetVatRate(string country) {
        switch (country) {
            case Countries.UnitedKingdom: 
                return 1.175;
            default:
                return 1;       
        }
    }
}

//...

public class Cart {
    private const string BodyTextKey = "bodyText";
    private const decimal UkVatRate = 1.175;

    //...

    public void PrepareForCheckout() {
        FinalValue = FinalValue * VatHelper.GetVatRate(Customer.Country);
    }

    //...
}

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

&lt;/div&gt;



&lt;p&gt;(OK, so in most real-world examples the country and it's respective VAT rate would probably both live in a database somewhere, but it works as an example!)&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;em&gt;Enum&lt;/em&gt;-ber of other solutions
&lt;/h2&gt;

&lt;p&gt;Constants are great and all, but they can get a little bit repetitive. Enumerated types (that's enums to you and me) are useful for a finite number of constants that won't change.&lt;/p&gt;

&lt;p&gt;Enums are a great solution to our &lt;code&gt;ValidationMethod&lt;/code&gt; setting we were talking about earlier. We could create an enum with all the possible values and use this enum in place of our strings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public enum ValidationMethod {
    None,
    Required,
    EmailAddress,
    PhoneNumber,
    Numeric
}

//...

this.ValidationMethod = ValidationMethod.None;

//...

switch (field.ValidationMethod) {
    case ValidationMethod.Required:
        return !string.IsNullOrEmpty(field.Value);
        // ...
}

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

&lt;/div&gt;



&lt;p&gt;Enums also work well for statuses:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public enum OrderStatus {
    Draft,
    Paid,
    Pending,
    Shipped,
    RecievedByCustomer
}

//...

Order.Status = OrderStatus.Paid;

//...

if(Order.Status == OrderStatus.Paid) {
    ProcessOrder();
}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Magic numbers and enums
&lt;/h3&gt;

&lt;p&gt;Under the covers, enums actually store integers for each value. In the case of our &lt;code&gt;OrderStatus&lt;/code&gt; enum, &lt;code&gt;Draft&lt;/code&gt; is equivalent to &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;Paid&lt;/code&gt; is &lt;code&gt;1&lt;/code&gt;, &lt;code&gt;Pending&lt;/code&gt; is &lt;code&gt;2&lt;/code&gt;, etc. You can even explicitly set the number applied to each value which can be useful if you need to map a readable name to a number, or if you need to add a value to an existing enum.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public enum OrderStatus {

    /// We want to add a new status at the top,
    /// but also to maintain the mapping of the original enum
    /// so we specify the values

    Cancelled = -1,
    Draft = 0,
    Paid = 1,
    Pending = 2,
    Shipped = 3,
    RecievedByCustomer = 4
}

//...

/// Readable definitions for all possible
/// response codes from the ACME API docs
public enum AcmeApiResponseCodes {
    Ok = 200,
    BadRequest = 400,
    Unauthorized = 401,
    InvalidClientId = 490,
    ExpiredClient = 491
}

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  JSON and enums
&lt;/h3&gt;

&lt;p&gt;As a side effect of the underlying value being an integer, you might notice that by default if you return an enum as a JSON result, you'll end up returning the number rather than the pretty enum.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "orderNumber": 51138461315,
    "status": 2,

    "...": "..."
}

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

&lt;/div&gt;



&lt;p&gt;JSON (and JavaScript too, without some workarounds) don't support enums. So we have two choices here: return the number, or return the string. You've got a few options if you want to convert the enum to and from a string if you'd rather.&lt;/p&gt;

&lt;p&gt;You can set the converter for your individual property with a simple attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Order {

    public long OrderNumber { get; set; }

    [JsonConverter(typeof(JsonStringEnumConverter))]
    public OrderStatus Status { get; set; }

    //...
}

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

&lt;/div&gt;



&lt;p&gt;Alternatively, set the attribute it on the enum definition if you want it to be serialized to a string every time you use it. While we're here, you'll notice you can also customise how the enum is rendered as a string with the &lt;code&gt;EnumMember&lt;/code&gt; attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[JsonConverter(typeof(JsonStringEnumConverter))]  
public enum OrderStatus {
    Draft,
    Paid,

    //...

    [EnumMember(Value = "Recieved by customer")]
    RecievedByCustomer
}

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

&lt;/div&gt;



&lt;p&gt;Or finally, you can set the behaviour globally for all enums by modifying the &lt;code&gt;ConfigureServices&lt;/code&gt; method in &lt;code&gt;Startup.cs&lt;/code&gt;. We need to add &lt;code&gt;AddMvcAndRazor&lt;/code&gt; to get ahold of the MVC config before adjusting the default JSON options.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)
{
    services
        .AddUmbraco(_env, _config)

        // Here's the good stuff

        .AddMvcAndRazor(mvc =&amp;gt;
        {
            mvc.AddJsonOptions(json =&amp;gt;
            {
                json.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
            });
        })

        // That's all, folks!

        .AddBackOffice()
        .AddWebsite()
        .AddComposers()
        .Build();
}

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

&lt;/div&gt;



&lt;p&gt;Your configuration may differ slightly if you're using Umbraco 8 or below (with .NET Framework) or if you're using &lt;code&gt;Newtonsoft.Json&lt;/code&gt; (rather than &lt;code&gt;System.Text.Json&lt;/code&gt;) in your Umbraco 9+/.NET 5+ app, but the principles are the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  Flagged enums
&lt;/h3&gt;

&lt;p&gt;Simple enums work fine for things like statuses, where only one can be true at any one time. But how about where multiple values make sense?&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;ValidationMethod&lt;/code&gt; example from earlier applies here. It may be possible to have a field that needs validating as &lt;code&gt;Required&lt;/code&gt; but also &lt;code&gt;EmailAddress&lt;/code&gt;. With strings, we could have done this as an array and we can do the same with enums if we want...&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// How we might have allowed multiple values with magic strings
field.ValidationMethods = new string[] { "email address", "required" };

// We can do the same when using enums too
field.ValidationMethods = new ValidationMethod[] { ValidationMethod.EmailAddress, ValidationMethod.Required };

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

&lt;/div&gt;



&lt;p&gt;But we can also do one better with flagged enums to allow an enum to have multiple values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Flags]
public enum ValidationMethod {
    None = 0,
    Required = 1,
    EmailAddress = 2,
    PhoneNumber = 4,
    Numeric = 8
}

//...

this.ValidationMethods = ValidationMethod.EmailAddress | ValidationMethod.Required;

//...

if(this.ValidationMethods.HasFlag(ValidationMethod.Required)) {
        return !string.IsNullOrEmpty(field.Value);
}

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

&lt;/div&gt;



&lt;p&gt;In this example, you can see we've added the &lt;code&gt;[Flags]&lt;/code&gt; attribute to the enum and assigned each enum a value - this bit is important. We can then assign multiple values using the "bitwise OR operator" or pipe character (&lt;code&gt;|&lt;/code&gt;) it's the same we use two of in an or statement ( &lt;code&gt;this || that&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;To check if an enum has a flag, we can use the &lt;code&gt;HasFlag&lt;/code&gt; on the enum value. I've had to refactor our switch statement from earlier to use an if statement for each value we want to check for.&lt;/p&gt;

&lt;p&gt;You might notice the integer I've assigned to each number isn't in order. Well, it &lt;em&gt;is&lt;/em&gt; in order, but using a doubling sequence: 1, 2, 4, 8... etc. Each number is double the previous value. This is important because a flagged enum still only stores one integer!&lt;/p&gt;

&lt;p&gt;It works by using bitwise operations (there's that word again) which, simply put, is looking at the individual "bits" (and I mean that in the technical term!) of a binary number and applying an "OR" operation - if any of the bits in that column is 1, it returns a 1, otherwise it returns a 0.&lt;/p&gt;

&lt;p&gt;For those curious, let's look at the numbers in the doubling sequence in binary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
0000 (0)
0001 (1)
0010 (2[\*](#footnote))
0100 (4)
1000 (8)

...etc

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

&lt;/div&gt;



&lt;p&gt;You'll notice, that because they're all powers of 2, each column only ever contains a single 1. Therefore, no matter what combination we make of these in a bitwise OR, we can work out which initial enum values went into creating it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var a = ValidationMethod.EmailAddress | ValidationMethod.Required;
/// That's 1 and 2
///
/// 0001
/// OR 0010
/// -------
/// 0011 (the last two columns have a 1 in the first number OR second number)

var b = ValidationMethod.Required | ValidationMethod.EmailAddress | ValidationMethod.PhoneNumber| ValidationMethod.Numeric;
/// That's 1 and 2
///
/// 0001
/// 0010
/// 0100
/// OR 1000
/// -------
/// 1111

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

&lt;/div&gt;



&lt;p&gt;In both examples above, to check the value has the flag &lt;code&gt;Required&lt;/code&gt;, which is &lt;code&gt;0001&lt;/code&gt;, we simply need to check for a &lt;code&gt;1&lt;/code&gt; in the last column - the &lt;code&gt;HasFlag&lt;/code&gt; method is actually using the bitwise AND flag (&lt;code&gt;&amp;amp;&lt;/code&gt;) under the covers which does this check.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;this.ValidationMethods.HasFlag(ValidationMethod.Required);

// is the same as

(this.ValidationMethods &amp;amp; ValidationMethod.Required) == ValidationMethod.Required;

// is the same as

// Binary literals in C# are prefixed with 0b (C# 7+)
0b0000011 &amp;amp; 0b0000001 == 0b0000001;

/// 0011
/// AND 0001
/// --------
/// 0001 (the last column has a 1 in the first number AND second number)

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

&lt;/div&gt;



&lt;p&gt;Because of this behaviour, we can also add a value for common combinations or all into our enum by adding all the values of the combining values together (adding and bitwise operations provide the same result in this case because they're all powers of two, but not normally!)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Flags]
public enum ValidationMethod {
    // Regular items
    None = 0,
    Required = 1,
    EmailAddress = 2,
    PhoneNumber = 4,
    Numeric = 8,

    //Combinations
    RequiredEmail = 3 // 0001 | 0010 = 0011 or cheat by doing 1 + 2 = 3
    All = 15 // 0001 | 0010 | 0100 | 1000 = 1111 or cheat by doing 1 + 2 + 3 + 4 + 8 = 15
}

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

&lt;/div&gt;



&lt;p&gt;Not that an "All" value makes any sense in this case, but it's good to know!&lt;/p&gt;

&lt;h2&gt;
  
  
  Config your way out of it
&lt;/h2&gt;

&lt;p&gt;One of the questions we asked at the beginning was "is it part of configuration?" This is a good question to ask because it may well change how we deal with it. What is configuration? I like to think of anything that can alter an application's behaviour. This value will have been flagged (in a specification or by yourself) as something that's likely to change - be that in the future or per environment. A URL to an API endpoint is a good example of a configuration variable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it sits outside the control of your application and could conceivably change&lt;/li&gt;
&lt;li&gt;or you may want to point your staging site at a sandbox version of the API.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we're in the land of .NET 5, we can even get rid of some of the magic strings we have historically used to pull values out of config by mapping whole configuration sections to C# objects. I've also used a constant to get the configuration section name, to avoid that as a magic string.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class AcmeConfig
{
    public const string Section = "ACME";

    public string ApiBaseUrl { get; set; }

    //...
}

//...

public class AcmeClient {
    public AcmeClient(IConfiguration configuration) {
        var config = configuration.GetSection(AcmeConfig.Section).Get&amp;lt;AcmeConfig&amp;gt;();

        //...
    }

    //...
}

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Umbracadabra! Magic-less code
&lt;/h2&gt;

&lt;p&gt;Hopefully I've been able to explain a little of why avoiding these magic strings might be necessary and how we can improve upon them. Don't go crazy - there's no need to replace every variable in your code, but its worth thinking about in the future each time you open those double-quotes!&lt;/p&gt;

&lt;p&gt;Happy &lt;code&gt;const&lt;/code&gt;-ing.. and &lt;code&gt;enum&lt;/code&gt;-ing... and Model Building!&lt;/p&gt;

&lt;p&gt;*&lt;a href="https://en.wikipedia.org/wiki/Mathematical_joke#Jokes_with_numeral_bases"&gt;There are 10 types of people in the world: those who understand binary and those who don't.&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why are you being such a git about it?</title>
      <dc:creator>Joe Glombek</dc:creator>
      <pubDate>Tue, 05 Oct 2021 11:00:00 +0000</pubDate>
      <link>https://forem.com/joeglombek/why-are-you-being-such-a-git-about-it-1546</link>
      <guid>https://forem.com/joeglombek/why-are-you-being-such-a-git-about-it-1546</guid>
      <description>&lt;p&gt;Are your git repos a dumping ground for code? I'm really fussy about how people use git - and that's a good thing. We'll take a look at branching strategies, the importance of commit messages and how often should you commit, anyway? Let's investigate how, with 5 simple tips, we can turn a code dump into a glorious archive of software and how this can save time, frustration and money.&lt;/p&gt;

&lt;p&gt;Let's start really simple: what is git? Git is the most popular Source Control Management (SCM) system. It can ensure your code is backed up, versioned and accessible to other developers. Used properly, however, it can be so much more - helping ease complex processes such as release management, feature development and multiple people working concurrently.&lt;/p&gt;

&lt;p&gt;I can, though, be a bit of a git about it: I'm really fussy about how people use git - and that's a good thing. I've worked with a fair few organisations and development teams over the years, and poor git utilisation is a more common issue than you might think. People use git as a dumping ground for code rather than a well-managed archive of software. Today we'll take a look at 5 simple tips which will, with any luck, improve your git practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  0. Source &lt;strong&gt;Control yourselves&lt;/strong&gt;
&lt;/h2&gt;

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

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



&lt;/p&gt;

&lt;p&gt;This isn't one of the 5, but there are seriously some organisations out there not using SCM yet. SCM is &lt;em&gt;not&lt;/em&gt; the same as a backup and if you've emailed some code to a colleague, you're probably doing it wrong!&lt;/p&gt;

&lt;p&gt;For all the reasons I gave previously, SCM is essential for modern day software development.&lt;/p&gt;

&lt;p&gt;Mercurial (hg), Team Foundation Version Control (TFVC) and Subversion (SVN) are all examples of SCMs but Git has really taken over in the software world and is the industry standard - I'd recommend it for that on its own: there's no point teaching your team a SCM system which is (or may become) redundant.&lt;/p&gt;

&lt;p&gt;As for git clients, there are so many out there. Some like to use the command line - and that's great... if you're a git pro! But why overcomplicate? And there are times when being able to visualise the commit history in tree form can be a life-saver even for confident git-users. My favourite tree visualisation (and therefore favourite overall git client) is &lt;a href="https://www.gitkraken.com/invite/dsMBqLEr"&gt;GitKraken (this is a referral link - I want a GitKraken t-shirt!)&lt;/a&gt;. It's free for open source projects, but you'll need to pay for private repositories. I'll be using GitKraken for examples in this article as it's the client I'm most familiar with - but you can use any client you like but I'd strongly recommend not using a stripped-back client such as Visual Studio or GitHub Desktop as you get into more complex git usage and processes. If GitKraken isn't your bag, you may want to investigate &lt;a href="https://git-fork.com/"&gt;Fork (also paid, available for Mac and Windows)&lt;/a&gt;, &lt;a href="http://gitextensions.github.io/"&gt;Git Extensions&lt;/a&gt; or, at the very least, &lt;a href="https://www.hanselman.com/blog/my-ultimate-powershell-prompt-with-oh-my-posh-and-the-windows-terminal"&gt;Oh My Posh and Windows Terminal&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Commit &lt;strong&gt;Messaging is everything&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This &lt;a href="https://xkcd.com/1296/"&gt;xkcd comic&lt;/a&gt; highlights the problem perfectly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xkcd.com/1296/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HoOIhtJk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://imgs.xkcd.com/comics/git_commit.png" alt='XKCD comic: "As a project drags on, my git commit messages get less and less informative." "loop &amp;amp; timing control (14 hours ago), enabled config file parsing (9 hours ago), misc bugfixes (5 hours ago), code additions/edits (4 hours ago), more code (4 hours ago), here have code (4 hours ago), aaaaaaaa (3 hours ago), adkfjslkdfjsdklfj (3 hours ago), my hands are typing words (2 hours ago), haaaaaaaaands (2 hours ago)"' width="439" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'd like to say that was just a joke in a comic strip, but it can be all too real...&lt;/p&gt;

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

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



&lt;/p&gt;

&lt;p&gt;Imagine being in Dennis' situation and:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you've discovered a bug and you can't find the commit where it likely happened&lt;/li&gt;
&lt;li&gt;you see something odd in the codebase, there's no comment so you use a blame/annotate tool to see who changed it and why... but Andy is on holiday and his commit message says "test" 😱&lt;/li&gt;
&lt;li&gt;some piece of code has changed since you last saw it - why? You could revert it back to how you like it but maybe it was changed for a reason? You fire up the blame tool again, "Fixes date formatting issue in Chrome" - better leave it as it is! Saved by a good commit message!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some people will tell you that good commit messages should be written as if answering the question "what does this commit do?" and that's good advice! Starting your commit message with a verb like "Fixes ...", "Reverts ..." or "Integrates ..." is a good practice too.&lt;/p&gt;

&lt;p&gt;But these alone are not enough. "Fixes bugs" or "Reverts broken changes" are still useless. Detail, detail, detail!&lt;/p&gt;

&lt;p&gt;GitKraken (and many other GUI git clients) give you two fields for your commit messages - a title and a description. It's best to keep your title short (GitKraken recommends 72 characters) but you can add even more detail in the description field.&lt;/p&gt;

&lt;p&gt;You can even do this on the command line: &lt;code&gt;git commit -m "Title" -m "Description"&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Fixes date formatting issue in Chrome&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Chrome always assumes the MM/DD format no matter what locale the browser is set to*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;*it doesn't, this is just a made up example&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Reverts new "Paytastic Checkout" checkout flow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Customer has changed their mind and wants to revert to using LegacyCart&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Integrates SMS API&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sending an SMS to customers when their order ships using the "Simple SMS Sender" API&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you have a ticketing system or to-do list, it sometimes helps to include the title of the item in your commit and an ID or link to the initial issue can prove very useful.&lt;/p&gt;

&lt;p&gt;GitKraken (and many other GUI git clients) let you hook up your issue tracker to your git repos so you can automatically stick an issue number into the branch name (and it'll therefore be in the merge commit too!)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X65aL0Wb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/sfnpjmzf/image-20210906122621281.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X65aL0Wb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/sfnpjmzf/image-20210906122621281.png" alt='A screenshot of the GitKraken "Create a new branch for this issue" menu option of the Github Issues integration' width="403" height="247"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Push &lt;strong&gt;Little and often&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I've seen a lot of different tactics when it comes to how often people commit, but the most persuasive argument I've heard is for "little and often". Don't forget git acts as a backup of your work and progress. There's no point &lt;em&gt;only&lt;/em&gt; committing when something is feature complete: what happens if your hard drive packs up overnight? Or you're off sick tomorrow and somebody else is left to pick up your work? It's far more useful to have partially complete work committed than not. Although it's generally good practice to ensure each commit is in a buildable state - it's ok if your work-in-progress (WIP) commits don't build.&lt;/p&gt;

&lt;p&gt;You can also use your tiny commits to help you revert unwanted pieces of functionality, while it can be a real pain to pull small chunks of code out of a bigger commit.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dRJIUB5P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/y1dd12us/little-and-often.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dRJIUB5P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/y1dd12us/little-and-often.png" alt="A git commit tree with commits for &amp;quot;Change colour-scheme to green on red&amp;quot; followed by &amp;quot;Reorder slides&amp;quot; and then &amp;quot;Reverts 'Change colour-scheme to green on red'&amp;quot;" width="592" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perhaps changing the colour-scheme to green text on a red background was a bit much...? It would have been all too easy to bundle "Change colour-scheme to green on red" in with "Reorder slides", but separating these out made it a lot easier to revert one of them at a later date.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. &lt;strong&gt;Squash&lt;/strong&gt; rackets
&lt;/h2&gt;

&lt;p&gt;But don't all these "little and often" commits start to make a &lt;em&gt;racket&lt;/em&gt; after a while? (See what I did there?) That's where squash and amend come in. As I mentioned, I'm a big fan of a WIP (Work -In-Progress) commit at the end of the day. But, come tomorrow morning and I've finished that small segment of work off, I don't want two commits "WIP - Restyle footer" &lt;em&gt;and&lt;/em&gt; "Restyle footer". So I can amend my "WIP" commit to include all changes and rename it to "Restyle footer".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6cPqed_1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/e2ubypam/image-20210906143642617.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6cPqed_1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/e2ubypam/image-20210906143642617.png" alt='A screenshot of the GitKraken "Commit message" pane showing the "Amend" checkbox ticked' width="601" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or in the command line &lt;code&gt;git commit --amend -m "Restyle footer"&lt;/code&gt;. Atlassian has a great tutorial about &lt;a href="https://www.atlassian.com/git/tutorials/rewriting-history"&gt;rewriting git history from the command line&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to combine multiple commits, or you've already committed your second round of changes, you can look into "squashing" the commits.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t18lqTqQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/xsgfva2h/image-20210906145203419.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t18lqTqQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/xsgfva2h/image-20210906145203419.png" alt='Screenshot of GitKraken with multiple commits selected and highlighing the "Squash 3 commits" right-click menu option' width="437" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In GitKraken, this is done by selecting the multiple commits you want to combine, right clicking and selecting "Squash". There are some scenarios when squashing won't be available - in this case you might be best just leaving the history as-is!&lt;/p&gt;

&lt;p&gt;If I'm doing some DIY at home, things can get pretty messy with tools and dirt around the place. Before I go to bed, I might do a quick tidy up but the next day, once I've finished the piece of work, all the tools go away and I vacuum up the mess I made. I'll definitely have it clean and tidy before I let anybody else in the house! Treat your branches the same way. It's OK for them to be a bit messy while you've got things in progress, but as soon as you're finished or ready to merge into a shared branch, you ought to tidy it up - nobody wants to see your messy branch!&lt;/p&gt;

&lt;p&gt;One thing to note, though: don't squash your mistakes! Your mistakes and reworkings tell a story. It could provide valuable explanation to a future developer and documents your mistakes and learnings. Use amend and squash to tidy up, not to sweep under the rug!&lt;/p&gt;

&lt;h2&gt;
  
  
  4. A branching &lt;strong&gt;Strategy is key&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;There are many branching strategies out there and I don't really mind which one you use. My personal favourites are &lt;a href="https://guides.github.com/introduction/flow/"&gt;GitHub flow&lt;/a&gt; and &lt;a href="https://commonflow.org/"&gt;Common Flow&lt;/a&gt; (or a combination of the two) but there are &lt;a href="https://www.gitkraken.com/learn/git/best-practices/git-branch-strategy"&gt;many more&lt;/a&gt;. Generally, these follow the feature-driven development pattern, with a branch for each feature and some notion of the state of a particular release (generally using branches or tags).&lt;/p&gt;

&lt;p&gt;I also like to ensure only one person is committing to any single branch at one time - if two people are working on a feature, break that feature down into sub-features. This is the only way my "messy work-in-progress branch" method works!&lt;/p&gt;

&lt;p&gt;GitHub flow, put very simply involves creating a branch for your feature (mapped to a GitHub issue), adding your commits to that branch and then opening a Pull Request. You discuss and review your code changes with your colleagues before deploying your changes for test. Once everyone is happy, your Pull Request is merged into the &lt;code&gt;main&lt;/code&gt; branch. The &lt;a href="https://guides.github.com/introduction/flow/"&gt;GitHub flow tutorial&lt;/a&gt; goes into a little more detail.&lt;/p&gt;

&lt;p&gt;It's worth noting that if none of these git flows make sense to you, you can take inspiration from them. I don't know of many companies who strictly follow any one particular strategy. So pick one as a baseline and adapt it for your organisation.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. &lt;strong&gt;Rebase and merge&lt;/strong&gt; - the best of both worlds!
&lt;/h2&gt;

&lt;p&gt;Alright, so you've got your branching strategy and you've completed your feature - we're ready to merge!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DUZnbAfn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/jp3lhpfc/messy-commits.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DUZnbAfn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/jp3lhpfc/messy-commits.png" alt="A messy git tree with merges happening all over the place resulting in a tree with branches crossing over each other" width="592" height="849"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But on larger projects with multiple concurrent workflows, you can end up with a real tangle of branches and merges.&lt;/p&gt;

&lt;p&gt;So what other options are there for merging these features?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wEQHKlmP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/313ijj4b/image-20210902111845141.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wEQHKlmP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/313ijj4b/image-20210902111845141.png" alt='The "Rebase and merge" option shown in the merge type dropdown in a GitHub pull request' width="350" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub provides these 3 options on completion of a Pull Request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a merge commit (which creates the mess you see above)&lt;/li&gt;
&lt;li&gt;Squash and merge&lt;/li&gt;
&lt;li&gt;Rebase and merge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, some people like to squash and rebase: your entire feature gets squashed into one commit and plopped straight onto the develop or main branch -it's kind of an extreme alternative to GitHub's "squash and merge". This is very neat and tidy, I'll give you that! However, you lose a lot of the documentation of when, how and why code changes were made. I'd much rather keep this history where we can.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FTpCDYku--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/uujlj4hw/squash-rebase.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FTpCDYku--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/uujlj4hw/squash-rebase.png" alt="A linear git tree with no branches and only one commit for what was previously a whole branch" width="229" height="293"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which leaves us with "Rebase and merge". This option allows us to avoid losing data while keeping the tree clean and tidy so is, of course, my favourite. (If you're using Azure DevOps, you can set this method as the merge type too - they call it a &lt;a href="https://devblogs.microsoft.com/devops/pull-requests-with-rebase/#semi-linear-merge"&gt;"semi-linear merge"&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Rebasing is the act of "replaying" each commit in a branch (our feature branch) on top of the target branch (&lt;code&gt;main&lt;/code&gt; or &lt;code&gt;develop&lt;/code&gt; in this case) as if they were happening at this newer point in time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IjC3TRhA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/jbvbkrou/rebase-merge.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IjC3TRhA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://skrift.io/media/jbvbkrou/rebase-merge.png" alt="A git tree with no crossing branches, each branch making a neat 'D' shape against the main branch" width="668" height="850"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, this method removes the muddle of criss-crossing merges, while maintaining the whole branch structure and all the detail in every commit. Each feature makes a neat "D" shape with the &lt;code&gt;main&lt;/code&gt; or &lt;code&gt;develop&lt;/code&gt; branch, with no crossovers.&lt;/p&gt;

&lt;p&gt;You can also enact this process without a Pull Request utilising the individual tools &lt;code&gt;rebase&lt;/code&gt; your feature onto &lt;code&gt;main&lt;/code&gt; and then &lt;code&gt;merge&lt;/code&gt; your feature into &lt;code&gt;main&lt;/code&gt; in any git client of your choosing.&lt;/p&gt;

&lt;h2&gt;
  
  
  A note on rewriting history
&lt;/h2&gt;

&lt;p&gt;Both tips 4 and 5 do something controversial in the git world: rewriting history. Not "rewriting history" as in the act of whitewashing a historical atrocity, but simply changing what's been pushed to the git repository (AKA history) after its happened (rewriting). Squashing, amending, rebasing and patching are all examples of git history being rewritten.&lt;/p&gt;

&lt;p&gt;And I've just been actively advocating for 3 of these!&lt;/p&gt;

&lt;p&gt;Maintaining your "true history" certainly has its merits: it can be useful for learning and code reviews. It's also impossible to mess up your history if you never tamper with it!&lt;/p&gt;

&lt;p&gt;However, the way I see it is that this shouldn't at the cost of the readability of your repo. I prefer to maintain what I like to call my "&lt;em&gt;feature&lt;/em&gt; history" where the order of our feature development is true, even if we're tweaking the timelines a little of when each feature was developed relative to each other.&lt;/p&gt;

&lt;p&gt;I don't advocate for complete rewriting, just a quick tidy up.&lt;/p&gt;

&lt;p&gt;As for that "risk" I mention when rewriting history, just make sure you've &lt;em&gt;pushed&lt;/em&gt; your repository before you start messing with history. Then double check before your force push.&lt;/p&gt;

&lt;h2&gt;
  
  
  From code dump to stunning archive of software
&lt;/h2&gt;

&lt;p&gt;And that's it. That's our stunning archive of software. We're source controlled with small incremental commits, each having a meaningful and detailed commit message sat comfortably in feature branches with no distracting noise and complicated merges. It reads easily from bottom to top, with no detail hidden or mistakes masked.&lt;/p&gt;

&lt;p&gt;A clean history allows for features to be rolled back easily, while detailed commit messages create a better understanding of a repositories history leading to fewer mistakes and a branching strategy can clarify what code is deployed to which environment at any point in time. It's now plain to see how git discipline can provide benefits to developers, managers and the end client - saving time, frustration and money for all involved in a project.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I moved my website to Umbraco Cloud, this is how I got on</title>
      <dc:creator>Joe Glombek</dc:creator>
      <pubDate>Mon, 21 Dec 2020 05:00:00 +0000</pubDate>
      <link>https://forem.com/rockdove/i-moved-my-website-to-umbraco-cloud-this-is-how-i-got-on-3apl</link>
      <guid>https://forem.com/rockdove/i-moved-my-website-to-umbraco-cloud-this-is-how-i-got-on-3apl</guid>
      <description>&lt;p&gt;One weekend. One website. One rebuild.&lt;/p&gt;

&lt;p&gt;I have a confession to make. Up until this weekend, my website was hosted on Squarespace.&lt;/p&gt;

&lt;p&gt;This may seem counter-intuitive, for a software developer to use a service like Squarespace, but it made a lot of sense at the time. I needed a website fast while I was working full-time and didn't have the time or energy to build a site from scratch.&lt;/p&gt;

&lt;p&gt;I've mentioned in the past how &lt;a href="https://rockdove.uk/blog/integrate-don-t-imitate/"&gt;I'm not opposed to using third-party services where it makes sense&lt;/a&gt;, and this was certainly one of those occasions.&lt;/p&gt;

&lt;p&gt;Squarespace is, however, not without its faults: accessibility is poor and there aren't many ways to improve it; the drag and drop designer is a pain when you want consistency and repetition; and my CV on the Squarespace site never looked quite right on mobile. So, combined with the fact that I'm an Umbraco developer without an Umbraco website, it was time for a change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trial signup
&lt;/h2&gt;

&lt;p&gt;Investing evenings and weekends in building something I do for my day job has never really appealed to me, so I thought I might try out Umbraco Cloud. I like the idea of patch upgrades happening automatically and other upgrades possible without cloning locally. This means that going forwards I have less admin to do to keep my site up &lt;em&gt;and&lt;/em&gt; up-to-date. Using Umbraco Cloud also meant that I'd have more recent practice using Cloud, so I was at least learning something from my endeavour (I haven't used Cloud since it was in preview and called UaaS!)&lt;/p&gt;

&lt;p&gt;Signing up for the trial was fairly easy and promised 14 days to get my site in order before launching and paying for it. I had a repo up in no time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developing locally
&lt;/h2&gt;

&lt;p&gt;Although Cloud allows fully-online development (more on that later), I'm stuck in my ways. So decided to try out developing the Umbraco site locally. Developing locally enables compiled libraries for custom helpers and extension methods and installing packages via Nuget (sorry, Umbraco Packages!) which is all good practice as far as I'm concerned.&lt;/p&gt;

&lt;p&gt;Cloud is built around Git. Any changes you make are committed to Git and this automatically triggers a deployment to the Cloud site. In theory, this means working locally is as simple as cloning the URL Cloud provides and hitting run. But it's not &lt;em&gt;quite&lt;/em&gt; that simple because Cloud runs ASP.NET &lt;em&gt;Websites&lt;/em&gt; rather than their &lt;em&gt;Web Application&lt;/em&gt; counterpart, meaning there is no Visual Studio Solution that's source controlled. Umbraco, therefore, provide UaaS.cmd to help simplify this process.&lt;/p&gt;

&lt;p&gt;Foolishly, I initially only skim-read the &lt;a href="https://our.umbraco.com/documentation/Umbraco-Cloud/Set-Up/Working-With-Visual-Studio/#generate-a-visual-studio-solution"&gt;documentation&lt;/a&gt; here before diving in. But after following the official guidance, this process was actually quite simple.&lt;/p&gt;

&lt;p&gt;Then, after configuring my two (that's how it works!) git repos (and also setting up a mirror for the Umbraco Cloud repo because, although not necessary, I couldn't help feeling it was better practice somehow), I hit the run button...&lt;/p&gt;

&lt;p&gt;Well, that didn't work. It's at this point I'd usually document the steps I went through to get it working properly but, in all honesty, I had no idea what I did to get it happy again. It was a bit of trial and error and likely specific to my setup, so we shan't dwell on this! The important thing is that it's working now!&lt;/p&gt;

&lt;h2&gt;
  
  
  Project setup
&lt;/h2&gt;

&lt;p&gt;Let's take a moment to discuss the setup when developing locally.&lt;/p&gt;

&lt;p&gt;UaaS.cmd sets up two Git repositories, one at the root (that you need to source control yourself) and one in &lt;code&gt;*.Web&lt;/code&gt; (where &lt;code&gt;*&lt;/code&gt; is the name of your project).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;*.Web&lt;/code&gt; contains your Umbraco site as an ASP.NET &lt;em&gt;Website&lt;/em&gt; (not Web Application - there is no &lt;code&gt;.csproj&lt;/code&gt; file).&lt;/p&gt;

&lt;p&gt;The root directory contains the solution file as well as a folder and &lt;code&gt;csproj&lt;/code&gt; file called &lt;code&gt;*.Core&lt;/code&gt; which, according to &lt;a href="https://our.umbraco.com/documentation/Umbraco-Cloud/Set-Up/Working-With-Visual-Studio/#working-with-visual-studio"&gt;the docs&lt;/a&gt;, is where controllers, models, data access and extension methods should ideally live.&lt;/p&gt;

&lt;h3&gt;
  
  
  Models!?
&lt;/h3&gt;

&lt;p&gt;Using ModelsBuilder is a bit of a pain. To get Intellisense working, &lt;a href="https://our.umbraco.com/documentation/Umbraco-Cloud/Set-Up/Working-With-Visual-Studio/#using-modelsbuilder-and-intellisense"&gt;the docs&lt;/a&gt; recommend using ModelsBuilder mode &lt;code&gt;AppData&lt;/code&gt; (classes are generated upon request) or &lt;code&gt;AppDataLive&lt;/code&gt; (classes are generated automatically when models change) and then overriding the path to place them in the &lt;code&gt;App_Code&lt;/code&gt; folder, where they'll get compiled on the fly. This is quite clever. Visual Studio can pick these up automatically as ASP.NET Websites include files automatically (some of the time... it involves a lot of hitting the "Refresh" menu option) and they're compiled dynamically meaning you can change models on Umbraco Cloud (not developing locally) and they'll update dynamically.&lt;/p&gt;

&lt;p&gt;However, this means that the &lt;code&gt;*.Core&lt;/code&gt; project has no access to any ModelsBuilder models, which makes writing some of my common extension methods difficult. Normally I'd create a &lt;code&gt;SiteSettings()&lt;/code&gt; extension method on IPublishedContent to get the settings node but, without access to models, I resorted to a generic method &lt;code&gt;GetSite&amp;lt;Settings&amp;gt;()&lt;/code&gt; where Settings is the model for my Settings node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public static T GetSite&amp;lt;T&amp;gt;(this IPublishedContent page) where T : class, IPublishedContent
{
    return page.Root().FirstChild&amp;lt;T&amp;gt;();
}

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

&lt;/div&gt;



&lt;p&gt;There are other options here but they all have their own downsides. You can the &lt;code&gt;*.Core&lt;/code&gt; project altogether and put all your code in the &lt;code&gt;~/App_Code&lt;/code&gt; folder, but this means you miss out on any compilation ahead of time. You can also &lt;a href="https://our.umbraco.com/forum/umbraco-cloud/83723-modelsbuilder-generate-models-to-umbraco-cloud-core-project"&gt;set your models to be generated within the &lt;code&gt;*.Core&lt;/code&gt; project&lt;/a&gt;, but then you won't be able to utilise the ability to develop on the live site (more on that later). A third option may be (I've not yet tested it) to use the &lt;code&gt;Dll&lt;/code&gt; or &lt;code&gt;LiveDll&lt;/code&gt; ModelsMode (in the &lt;a href="https://github.com/modelsbuilder/ModelsBuilder.Original"&gt;full version of ModelsBuilder&lt;/a&gt;) and reference the generated DLL in your &lt;code&gt;*.Core&lt;/code&gt; project. This allows for development on the live site, but means you'll have to either manually generate models (&lt;code&gt;Dll&lt;/code&gt;) or have site restarts every time you change a document type (&lt;code&gt;LiveDll&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Website vs. Web Application
&lt;/h3&gt;

&lt;p&gt;As indicated above, a website is mildly annoying to have as opposed to a web application. I've always seen applications as more superior, but the only reason I think this would be is because an application can generate DLLs, while websites can only have C# in the &lt;code&gt;App_Code&lt;/code&gt; folder, where it's only compiled on application startup (think of it as the opposite of &lt;a href="https://gunnarpeipman.com/asp-net-mvc-precompiling-views/"&gt;precompiled views&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Being a git about Git
&lt;/h3&gt;

&lt;p&gt;And now, lets get onto the Git setup. This is a little weird. If you want to use Visual Studio to build your Umbraco site, the docs suggest you'll need two git repositories (although if you're feeling brave I'm sure you could use one and then use subtree or submodules and mirror to the Cloud repo... but that's a story for another day!): one for the &lt;code&gt;*.Web&lt;/code&gt; folder, and one for everything else. The &lt;code&gt;*.Web&lt;/code&gt; repo is hosted by Cloud (and is where it deploys from), while you'll need to create your own repo for the rest. Although I'm sure it's unnecessary, I also decided to mirror the Cloud repo because it feels like the right thing to do!&lt;/p&gt;

&lt;p&gt;It's not really an issue, just a mild niggle. I'm sure someone more confident with Git than I could find a nicer way to handle this setup, but this one will do for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Umbraco Deploy
&lt;/h2&gt;

&lt;p&gt;I've heard bad things about it but so far, for me, Umbraco Deploy has just worked. When Umbraco releases Deploy for non-cloud projects, I'm sure I'll have to do a full comparison between Deploy and uSync.Publisher, but for now I'm happy to use Deploy for Cloud and uSync for everything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ability to develop on the live site! 🤠
&lt;/h2&gt;

&lt;p&gt;I've always found the Settings area of Umbraco a bit odd, personally I'd rather do all my development within my IDE not partially in the browser. Working in a CI/CD world, I'd also have to disable the Settings section in any environment except locally.&lt;/p&gt;

&lt;p&gt;But in Cloud, the Settings section makes so much sense for the simple reason that any changes you make on your Cloud environments and committed to the Git repo automatically. This makes my inner "&lt;a href="https://en.wikipedia.org/wiki/Cowboy_coding"&gt;cowboy coder&lt;/a&gt;" very happy. If I need to hotfix a live site, I can! If I want to tweak code from my phone, halfway up a mountain, I can! If I'm too lazy to open up Visual Studio to make a minor change to my personal site, I can!&lt;/p&gt;

&lt;p&gt;Cloud is where Umbraco seems most at home, largely because of this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain configuration... AKA 9 hours of downtime
&lt;/h2&gt;

&lt;p&gt;I assume due to how Umbraco Latch works, domains will need to be configured to point to the Cloud site before an SSL certificate is generated. Unfortunately for existing sites, this means there will be a short moment of downtime while your domain points to a site with an invalid HTTPS certificate. However, in my case, basic authentication was not automatically disabled when I purchased my Cloud license (and by the time I realised it was too late!)&lt;/p&gt;

&lt;p&gt;I decided to leave the setup overnight in the hope the problem would resolve itself with time, which it, unfortunately, did not. Support was, however, very helpful and resolved the issue quickly after I notified them of the issue.&lt;/p&gt;

&lt;p&gt;Azure Web Apps allow domains to be preconfigured (with DNS text records) prior to mapping the domain, which may mean as &lt;a href="https://umbraco.com/blog/the-future-of-umbraco-cloud/"&gt;Umbraco Cloud moves to Web Apps and uses Cloudflare&lt;/a&gt; in place of the existing Latch process for HTTPS, we may see an improvement here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Umbraco cloud issues
&lt;/h2&gt;

&lt;p&gt;I don't think it's unfair to say that Umbraco Cloud has a bit of a reputation when it comes to stability... and not a good one. And so far, I'm not helping that reputation, having already detailed an issue I had with my site not coming out of trial mode.&lt;/p&gt;

&lt;p&gt;I did also experience a short amount of downtime on Saturday night.&lt;/p&gt;

&lt;p&gt;But that's it so far. And support has been great at fixing the issues I have had.&lt;/p&gt;

&lt;p&gt;I also had an issue with a bug in Umbraco Forms, which the support team fixed without having to delve into the database myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The price is right... sometimes
&lt;/h2&gt;

&lt;p&gt;So who is this for? It's a question that's asked again and again. And I wasn't sure until I tried it properly myself.&lt;/p&gt;

&lt;p&gt;I think the answer is, Umbraco Cloud is great for me. My use case is that I have a small low-traffic site which I don't want to have to invest huge swathes of time keeping patched and up to date, but I do want to quickly develop and launch new features.&lt;/p&gt;

&lt;p&gt;It's not ideal for complex custom setups, or sites requiring "four-nines" of uptime. It might also outprice individuals or small charities. But for those in the middle, it seems to suit quite well. I won't be recommending Cloud to every client, but I think I now know who the target market is, and will recommend to those clients going forwards.&lt;/p&gt;

&lt;p&gt;It will be interesting to see how &lt;a href="https://umbraco.com/blog/the-future-of-umbraco-cloud/"&gt;the new planned infrastructure for Cloud&lt;/a&gt; will affect this target demographic and whether we'll see a more stable platform going forwards.&lt;/p&gt;

&lt;p&gt;As for the relatively high cost vs self-hosting, I think this comes down to the quality and speed of the support team. If you consider the month price as a time-saver, it's easily worth it in my opinion.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to set Windows Terminal as GitKraken's default terminal</title>
      <dc:creator>Joe Glombek</dc:creator>
      <pubDate>Fri, 11 Dec 2020 06:34:00 +0000</pubDate>
      <link>https://forem.com/rockdove/how-to-set-windows-terminal-as-gitkraken-s-default-terminal-4geo</link>
      <guid>https://forem.com/rockdove/how-to-set-windows-terminal-as-gitkraken-s-default-terminal-4geo</guid>
      <description>&lt;p&gt;GitKraken allows you to open the current repository in the terminal by hitting Alt + T but by default, this won't be the new Windows Terminal.&lt;/p&gt;

&lt;p&gt;The new Windows Terminal has many benefits over the Command Line or Powershell applications but you won't find Windows Terminal as an option for the default terminal in GitKraken's settings.&lt;/p&gt;

&lt;p&gt;There is a simple fix, however. Open up GitKraken's preferences (File &amp;gt; Preferences) and scroll down to and check "Use Custom Terminal Command" (below "Default Terminal" dropdown). Then, in the "Custom Terminal Command" field that appears above, enter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wt -d %d

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

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;wt&lt;/code&gt; is the command for Windows Terminal, to which we're passing the &lt;code&gt;-d&lt;/code&gt; directory parameter. The value of &lt;code&gt;%d&lt;/code&gt; is then swapped out by GitKraken for the directory of the current repository.&lt;/p&gt;

&lt;p&gt;It's as simple as that!&lt;/p&gt;

&lt;p&gt;At the time of writing, there is a bug in GitKraken which launches the terminal twice when using the File &amp;gt; Open Terminal option, but Alt + T works just fine.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Taking Friendly to the masses</title>
      <dc:creator>Joe Glombek</dc:creator>
      <pubDate>Thu, 10 Dec 2020 08:00:00 +0000</pubDate>
      <link>https://forem.com/joeglombek/taking-friendly-to-the-masses-1ff1</link>
      <guid>https://forem.com/joeglombek/taking-friendly-to-the-masses-1ff1</guid>
      <description>&lt;p&gt;Umbraco is "The Friendly CMS" and, as a community, we aim to be warm and welcoming, greeting everyone we encounter with a Friendly high-five. But how can we inject some of this Friendliness into our work and make the websites we craft as Friendly as possible?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;friendly&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
behaving in a pleasant, kind way towards someone&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To be Friendly to everyone, we need to make sure everyone can use our websites. This simple concept is the whole premise behind, what may initially sound daunting, accessibility. Contrary to popular belief, accessibility isn't all about screen-readers, it's about the usability of your website to anyone, no matter their personal needs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;accessibility&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
the quality or characteristic of something that makes it possible to approach, enter, or use it&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Accessibility of the Umbraco back-office has started to take shape over recent months: in any new Umbraco release, there’s been a whole section of the release notes dedicated to accessibility improvements. This has brought the concept of accessibility to more and more community members, but to some, an accessible website still seems like a distant pipedream - at best a low priority ticket on a backlog and at worst dismissed in the planning stages.&lt;/p&gt;

&lt;p&gt;But I’m here to challenge that and show you how building a more accessible site is easier than you might think, whether you're a developer, designer or working in management, sales and delivery.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility as a priority
&lt;/h2&gt;

&lt;p&gt;Of course, time and budget dedicated to making your website as accessible as possible is the best option and there are many reasons to do so, morally and financially.&lt;/p&gt;

&lt;p&gt;We think of the web as open-access and a level playing field giving everyone access to the same information. And it is. For the most part. Building accessible websites is a very simple way to open up information and services to more people, ensuring people are not unfairly restricted by their circumstances.&lt;/p&gt;

&lt;p&gt;It’s also important to remember that these are customers. Just as a shopkeeper wouldn’t put a barrier across their entrance only serving those who could jump it, why should a website put up these virtual hurdles for a percentage of potential customers?&lt;/p&gt;

&lt;p&gt;I’m sure you’re all aware of &lt;a href="https://www.bbc.co.uk/news/technology-46894463"&gt;the Domino's Pizza lawsuit that hit the US Supreme Court last year&lt;/a&gt;, but other big names like &lt;a href="https://thenextweb.com/tech/2020/06/24/why-your-websites-lack-of-accessibility-options-is-opening-you-up-to-lawsuits/"&gt;Nike, PornHub and Beyonce also got taken to court in America&lt;/a&gt; with other countries catching on. Web accessibility will soon be a must-have for all big corporations and any website built today should be taking this seriously.&lt;/p&gt;

&lt;h2&gt;
  
  
  It’s just UX
&lt;/h2&gt;

&lt;p&gt;User experience (that’s UX to those in the know) designers pride themselves in designing great experiences for users (I guess the clue is in the name!) rather than something that simply looks good.&lt;/p&gt;

&lt;p&gt;No surprises here, that this way of thinking generally includes those with access issues. As the word “accessibility” implies, this kind of UX doesn’t exclusively help those with specific needs - it’ll help everyone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7hYlXyIz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://community.codenewbie.org/remoteimages/uploads/articles/zdwdo67cla0q7fppsozg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7hYlXyIz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://community.codenewbie.org/remoteimages/uploads/articles/zdwdo67cla0q7fppsozg.jpg" alt="A man using his phone with glaring sunlight behind him, obscuring his face and reflecting off his phone" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any user of a shiny phone screen on a bright sunny day will appreciate high contrast ratios between text and the background, while any person who’s had an exhausting day will appreciate concise language and clear actions. Not to mention the 1 in 8 men who are colourblind (myself included) and the huge proportion of us who will develop motor, sight or hearing-related issues in later life.&lt;/p&gt;

&lt;p&gt;Accessibility is vital for some and useful for everyone. Accessibility is a part of UX, so let’s be sure to embrace it and hold it in as high regard as visual appearance.&lt;/p&gt;

&lt;p&gt;As a designer, thinking about how a user might interact with your design is a part of the job and accessibility fits right in with the other best practices you’re already following. There’s nothing extra here except a few additional things to think about and the more accessible designs you produce, the easier it becomes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coding is key
&lt;/h2&gt;

&lt;p&gt;As developers, the way we code our sites makes all the difference. Even if there's no special budget set aside or we've received a design that hasn't fully considered accessibility (or there's no design at all!), we can still make all the difference.&lt;/p&gt;

&lt;p&gt;It's not that different from coding without considering accessibility: just as we support browsers by writing valid markup, we can support as many people as possible by writing valid, semantic markup. The key to accessibility for developers is that actually, most HTML we write is probably accessible already. HTML renders in an easy to read and understand way and if we’re using the right semantic markup, it goes a long way to being understood by screen-readers too. It’s good practice to use the right elements for the right things: a nav for all navigation areas; main for the primary content of your site; header, footer and section elements for splitting up the page; and by using headings correctly*.&lt;/p&gt;

&lt;p&gt;The trouble comes with JavaScript and CSS.&lt;/p&gt;

&lt;p&gt;When styling, a good indication of breaking some bad practice is if you set a style to none or inherit. Browsers almost always have a reason for styling something a certain way, and if you’re undoing that it could make it harder to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessible accessibility tips
&lt;/h2&gt;

&lt;p&gt;For you designers, developers and testers reading this, here are some of my top tips for starting on your accessibility journey. There is a lot more to learn out there (&lt;a href="https://24days.in/umbraco-cms/2015/a-web-for-everyone/"&gt;Jeffrey and Jorgen's article from 2015 is a good place to look for expanding your knowledge next&lt;/a&gt;) but this is a good place to get started.&lt;/p&gt;

&lt;p&gt;I have 3 golden rules for styling accessibly.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Let me &lt;em&gt;outline&lt;/em&gt; this for you
&lt;/h3&gt;

&lt;p&gt;An outline is the browsers’ default way of showing focus - by removing this, it might make navigating your site by keyboard impossible! Consider changing the outline colour rather than removing it completely, or use some other clear styling to highlight focus.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Which &lt;em&gt;links&lt;/em&gt; nicely onto...
&lt;/h3&gt;

&lt;p&gt;By removing the colour and underline from a link, you make it less clear that the text is actually a link! Even changing a link from blue to any other colour can make navigation confusing to some users.&lt;/p&gt;

&lt;p&gt;If you’re trying to make your link look like a button, you might confuse people even more.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Things that look like things they are not
&lt;/h3&gt;

&lt;p&gt;Using elements for things they are not is another red flag. Using a link as a button or button as a link means the user doesn’t get the functionality they expect from that kind of element - links navigate you to somewhere else, while a button interacts with the current page. A checkbox is a form field, not &lt;a href="https://css-tricks.com/the-checkbox-hack/"&gt;a toggle for a menu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It’s not necessarily wrong to use an element for something different, but it is a warning sign. So if you are, you should be sure to try using the component with a screen-reader (I recommend using &lt;a href="https://www.nvaccess.org/about-nvda/"&gt;NVDA&lt;/a&gt; over Windows Narrator - it's free and very popular) and only using keyboard navigation. If something is unclear or doesn't function as expected, use ARIA attributes and JavaScript to correct any confusing behaviour.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/glombek/embed/MWeMbev?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Don't &lt;em&gt;label&lt;/em&gt; me a cynic
&lt;/h3&gt;

&lt;p&gt;Moving on from styling, another really quick tip to make your site accessible is to label things. If an input has no label, or a section has no heading, consider adding one that's “&lt;a href="https://css-tricks.com/inclusively-hidden/"&gt;visually hidden&lt;/a&gt;” or through aria-label. Similarly, if you have an icon with no text, it’s generally worth adding some text to help people understand its meaning (&lt;a href="https://vanseodesign.com/web-design/hamburger-icon-debate/"&gt;it might not be as obvious as you think&lt;/a&gt;), but if your design prohibits this, aria-label it!&lt;/p&gt;

&lt;p&gt;Conversely, an icon that has no semantic meaning, can be aria-hidden so that it’s not read out by a screen-reader. An example of this would be an icon with a label next to it - the icon adds no additional meaning to the label, so a screen-reader doesn’t need to read it out.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Alternative&lt;/em&gt; thinking
&lt;/h3&gt;

&lt;p&gt;Alternative text (alt attribute) on images have a couple of really handy uses. Firstly, if your image can't be loaded for whatever reason, it is replaced by the alt text to give an idea of the context it was meant to provide. Secondly, alt text can provide an audible description of the image for blind users and more clarity to a partially sighted user.&lt;/p&gt;

&lt;h3&gt;
  
  
  *A note on headings
&lt;/h3&gt;

&lt;p&gt;Although it’s valid HTML to use an h1 per section, some screen-readers (as well as search engines) struggle to understand the structure of the content like this so it’s still considered best practice to use one h1 element per page.&lt;/p&gt;

&lt;h2&gt;
  
  
  In inconclusive conclusion
&lt;/h2&gt;

&lt;p&gt;These are just a few pointers to start you on your accessibility journey. I'm by no means an expert and this is by no means all there is to know but I am keen to make my sites as accessible as possible and learning more every day, which I hope I have managed to rub off on you too! Don't hesitate to &lt;a href="https://twitter.com/JoeGlombek"&gt;reach out to me&lt;/a&gt; if you have any accessibility queries or get involved with the &lt;a href="https://community.umbraco.com/community-teams/the-accessibility-team/"&gt;Accessibility Team&lt;/a&gt;, we're all quite Friendly.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Easily open uSync Sync-Pack files</title>
      <dc:creator>Joe Glombek</dc:creator>
      <pubDate>Tue, 16 Jun 2020 11:38:03 +0000</pubDate>
      <link>https://forem.com/rockdove/easily-open-usync-sync-pack-files-af2</link>
      <guid>https://forem.com/rockdove/easily-open-usync-sync-pack-files-af2</guid>
      <description>&lt;p&gt;uSync Sync-Pack files (with the .uSync extension) are simply ZIP files and can be viewed in any ZIP viewer, including the one built into Windows.&lt;/p&gt;

&lt;p&gt;One option is to rename your Sync-Pack to have a .zip extension and then open it as you would any compressed folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fWfplePx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/e7d4z0yyyygtrhusbfaz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fWfplePx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/e7d4z0yyyygtrhusbfaz.png" alt="A screenshot of a Sync-Pack file" width="116" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The other option, however, which is very useful if you’re looking inside uSync files more often, is to let Windows know that the .uSync file is a ZIP file and to treat it as such.&lt;/p&gt;

&lt;p&gt;There’s no point-and-click setting for this like there is for associating a filetype with a program, because we’re doing something subtly different: telling Windows this file &lt;em&gt;is&lt;/em&gt; a ZIP file.&lt;/p&gt;

&lt;p&gt;All you need to do, though, is open a command prompt as administrator and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;assoc .uSync=CompressedFolder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vSdMXCMb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/2rrvcr2y1z28la0qntqh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vSdMXCMb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/2rrvcr2y1z28la0qntqh.png" alt="Screenshot of Command Prompt with the above command entered" width="487" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>umbraco</category>
      <category>usync</category>
      <category>zip</category>
    </item>
    <item>
      <title>Integrate, don't imitate - when an API beats rolling your own</title>
      <dc:creator>Joe Glombek</dc:creator>
      <pubDate>Wed, 06 May 2020 22:14:30 +0000</pubDate>
      <link>https://forem.com/rockdove/integrate-don-t-imitate-when-an-api-beats-rolling-your-own-1on8</link>
      <guid>https://forem.com/rockdove/integrate-don-t-imitate-when-an-api-beats-rolling-your-own-1on8</guid>
      <description>&lt;p&gt;It wasn’t long ago that every agency and freelancer had their own custom CMS they’d use for client projects. We decided that was a bad idea. But we’ll often be seen writing custom code within that standardised CMS. Are we making the same mistakes again?&lt;/p&gt;




&lt;p&gt;This blog accompanies my talk at the &lt;a href="https://www.meetup.com/Thames-Valley-Umbraco-User-Group"&gt;Thames Valley Umbraco User Group&lt;/a&gt; on 30 April 2020. I also have &lt;a href="https://www.beautiful.ai/player/-M7qx4D9k4IkrxrkBFvn"&gt;the slides for my talk&lt;/a&gt; available.&lt;/p&gt;




&lt;p&gt;Let’s start with a couple of scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenario 1: John the roller coaster enthusiast
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CkURdgOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/f0jt6go5bkoofqnwd836.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CkURdgOy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/f0jt6go5bkoofqnwd836.jpeg" alt="Man standing in front of a roller coaster" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Meet John. He’s a rollercoaster enthusiast and he’s decided that he wants to ride a roller coaster at least once a week. He’s got a good budget and money is no object.&lt;/p&gt;

&lt;p&gt;How could we solve his problem?&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: Build a roller coaster in John’s back garden
&lt;/h3&gt;

&lt;p&gt;We could recommend to John that we build a roller coaster in his back garden. This could be quite fun and he could ride the roller coaster as often as he liked, with no need to queue. But on the downside, the estimated cost of this solution is £2.5 million to £25 million (&lt;a href="https://www.bbc.co.uk/news/technology-24553630"&gt;source: BBC&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 2: Go to a theme park
&lt;/h3&gt;

&lt;p&gt;Alternatively, we could just recommend that he goes to his local theme park. He’d have his choice of various rides with no build-time, planning permission, health and safety, insurance, etc.&lt;/p&gt;

&lt;p&gt;As for cost, a “premium season pass” at a well known theme park costs £85 (notice the lack of the word “million” as a suffix), plus the cost of fuel (which, no matter how far you’re travelling is negligible, again due to the lack of the “million” suffix).&lt;/p&gt;

&lt;p&gt;I’ll let you decide which option to pitch to John.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenario 2: National Bushcraft Association website
&lt;/h2&gt;

&lt;p&gt;Some of you may know about the time I lived in the woods for 6 months and taught wilderness survival skills to school children. So, I've created a scenario around the fictional National Bushcraft Association, a membership organisation for bushcraft instructors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VC6t3BRv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/niuip5gxy50kjmy8k7wv.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VC6t3BRv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/niuip5gxy50kjmy8k7wv.jpeg" alt="Bushcraft tools including an axe and knife resting on a tree stump" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Members pay an annual fee to gain benefits such as networking, client referrals, news sharing capabilities and the obligatory newsletter. They want a Content Management System (CMS) with member management functionality to manage membership fees, expiry of unpaid memberships and mass mailing.&lt;/p&gt;

&lt;p&gt;So the obvious solution?&lt;/p&gt;

&lt;p&gt;Umbraco! That’s my go-to CMS, and I love working with it. Of course simply being my favourite CMS doesn’t justify the choice on its own, Umbraco is open source with an enthusiastic community meaning its free and actively developed. Umbraco will easily cover the requirement the Bushcraft Association has for content management. It also has a highly extensible membership management system.&lt;/p&gt;

&lt;p&gt;The membership management functionality in Umbraco by default, however, is comparatively basic. So we’d need to build custom functionality to allow sending newsletters, membership payment and expiring members who haven’t paid.&lt;/p&gt;

&lt;p&gt;But wait! Isn’t this the theme park scenario all over again; are we building a roller coaster? And if so, what are our other (“season pass”) options here?&lt;/p&gt;

&lt;p&gt;As for membership management, there are dozens of pre-built systems available that have this down to a tee, and many of them have an API we could integrate with. A third party system would handle the membership fees, expiry and renewal reminders in the requirements, but also take GDPR off our hands and give us extra functionality to, for example, allow members to manage their own details and upgrade their membership tier as they need to, without phoning up the office team.&lt;/p&gt;

&lt;p&gt;Similarly, a newsletter sending platform would handle sending newsletters and managing subscriptions and unsubscriptions as required while also handling GDPR and providing the Bushcraft Association with analytics.&lt;/p&gt;

&lt;p&gt;In this scenario, I think building a basic CMS site and integrating with some third party services is the clear winner.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem solver mindset?
&lt;/h2&gt;

&lt;p&gt;But where does this “backyard roller coaster” attitude in developers come from?&lt;/p&gt;

&lt;p&gt;Personally, I think it’s due to the problem solver in us. We’re in this career because we like to solve problems and when someone gives us a brief we like to find an “ideal” solution, built exactly the way we think it should work.&lt;/p&gt;

&lt;p&gt;As well as this, as a premium service provider, we might feel it’s our duty to build everything bespoke rather than “cheating” by using other people’s work.&lt;/p&gt;

&lt;p&gt;It seems to take some maturity as a developer to realise we’re not taking the easy way out by using other people’s work, but standing on the shoulders of giants.&lt;/p&gt;

&lt;p&gt;We’re all too keen to use open source packages to speed up development and provide our users with a better experience, so why not complete services too?&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of integration
&lt;/h2&gt;

&lt;p&gt;For us developers, integrating makes life less repetitive, I get to spend more time writing new code rather than making poor imitations.Being honest, I just find building integrations more fun; I don't get too excited about another document type or building another news page. Writing more in depth C# is more interesting to me!&lt;/p&gt;

&lt;p&gt;But how do we sell an integration to higher ups, project managers or the client?&lt;/p&gt;

&lt;h3&gt;
  
  
  Over-delivery and extra features
&lt;/h3&gt;

&lt;p&gt;Integrating with more complete systems can result in over-delivery. Third party systems likely have more features built into them over the years than you could do with the budget, the client’s going to get an industry-standard application, rather than the bare minimum.&lt;/p&gt;

&lt;p&gt;Not to mention the fact that the client may get extra features “for free” as the third party developer continues to improve their application over time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Less scope creep
&lt;/h3&gt;

&lt;p&gt;Since a client is buying into an existing system, chances are they can trial that system before they commit to using it. Since the client knows exactly what they’re getting and has already taken part of the system for a test drive, the requirements are less likely to change, reducing scope creep.&lt;/p&gt;

&lt;h3&gt;
  
  
  Less support
&lt;/h3&gt;

&lt;p&gt;Since you’re building less, it means you handle less of the support after launch. There can be positives to this for the client too such as a reduced retainer cost and perhaps a better response rate than your team could provide. This also means that the client is less reliant on you or your company in the future, which could go a long way towards easing their minds!&lt;/p&gt;

&lt;h3&gt;
  
  
  A solid platform
&lt;/h3&gt;

&lt;p&gt;By buying into an existing ecosystem, some of your application has been built and tested already.&lt;/p&gt;

&lt;h2&gt;
  
  
  A balancing act
&lt;/h2&gt;

&lt;p&gt;Of course, it’s not always as simple as integrating. If nobody built their own roller coasters, there wouldn't be a theme park to buy an annual pass for!&lt;/p&gt;

&lt;p&gt;It wasn’t long ago that every agency and freelancer had their own custom CMS they’d use for client projects. We decided that was a bad idea. But equally, not every website should be built with Wix, Squarespace or Shopify. There’s often a trade off between bespoke and prebuilt. Every project needs an evaluation. Integration may not always be the answer, but it should always be considered.&lt;/p&gt;

</description>
      <category>umbraco</category>
      <category>integration</category>
      <category>value</category>
      <category>casestudy</category>
    </item>
  </channel>
</rss>
