On Software Engineering https://blog.gaisford.me.uk/ On Software Engineering 2022 Mon, 21 Feb 2022 09:22:42 GMT Mon, 21 Feb 2022 09:22:42 GMT Developer Insomnia https://blog.gaisford.me.uk/posts/insomnia <p>Watching the documentary, <a href="https://www.bbc.co.uk/iplayer/episode/p09qkrq8/daisy-maskell-insomnia-and-me">Daisy Maskell, "Insomnia and Me"</a> I felt anxious. As she described the things that made her unable to sleep and she stared out at a swing in her garden, I got it. I had that same feeling she described as she looked out of her window. She poignantly decribed it as an "inability to switch off".</p> https://blog.gaisford.me.uk/posts/insomnia Sun, 20 Feb 2022 00:00:00 GMT <p>Watching the documentary, <a href="https://www.bbc.co.uk/iplayer/episode/p09qkrq8/daisy-maskell-insomnia-and-me">Daisy Maskell, &quot;Insomnia and Me&quot;</a> I felt anxious. As she described the things that made her unable to sleep and she stared out at a swing in her garden, I got it. I had that same feeling she described as she looked out of her window. She poignantly decribed it as an &quot;inability to switch off&quot;.</p> <p>Of course it's not just a swing blowing in the wind. It prompts so much more thought. As you lie in bed at night determined to get a good nights sleep, your mind fixes on the swing from earlier that day and has other ideas about you sleeping. It wants to know more.</p> <p>Why is it swinging? Is it just the wind? What's causing that wind? The weather? Weather forcaster. Forcasting. The future. My mate Dan. A-Level results day. A Mini car. The same can my daughter wants. Her school. Did we pick the right school for her? Should we move school? Move house? Our gardens good though. Must fix the shed roof. Apex roof? No. Slope it towards the front. Collect more rainwater that way.......</p> <p>And on it goes. And on. And on.</p> <p>All from one swing.</p> <p>On nights like this, I go to bed at the same time, having followed the same routine as the day before when I drifted off in 10 short minutes. No caffine. Exercise. No phones after 9pm. All the things I can think to help me sleep I'd done the day before and today.</p> <p>But tonight.... my mind can't rest. It generally follows a period of stress somewhere in the day, or preceeding days. That stress brings anxiety about needing to cope. Needing to feel like you are on top of things.</p> <p>And what I've come to realise is that, for me, it's mainly about control. . Having had a stressfull, or sometimes just busy day. My mind.... or more accurately..... I .... want to play thorough tomorrow's scenarios so that what ever I'm confronted by I'll be prepared. In control.</p> <p>As a computer nerd, this logical thinking makes sense. However, what I'm coming to realise is that all this planning and thinking is counter productive. The time spent determining all tomorrow's potential outcomes leaves me so exhausted that the following day I'm unable, or unwilling to overcome the simplest of challenges.</p> <p>I appreciate there is of course a delicious irony to all this, yet still my mind won't listen to reason.</p> <p>Right now, my current strategy is to remember this irony as I lie in bed struggling to sleep. And while it does help, it is no miracle cure. What will help more is probably worrying less about tomorrow. But that is a much bigger challenge.</p> Terraform and Hybrid Connections for Azure App Services https://blog.gaisford.me.uk/posts/terraform-hybrid-connections <p>I use Terraform to create all infrastructure in Azure at work. It's a fantastic tool, and one which has saved a lot of time. However, there is always a lot to learn, and with that comes gotchas that you want to avoid in future. So to save future-me some Googling in a few months, here are the most time consuming gotchas I encountered on a recent project while trying to create hybrid connections for app services in Azure using Terraform.</p> https://blog.gaisford.me.uk/posts/terraform-hybrid-connections Sat, 03 Oct 2020 00:00:00 GMT <p>I use Terraform to create all infrastructure in Azure at work. It's a fantastic tool, and one which has saved a lot of time. However, there is always a lot to learn, and with that comes gotchas that you want to avoid in future. So to save future-me some Googling in a few months, here are the most time consuming gotchas I encountered on a recent project while trying to create hybrid connections for app services in Azure using Terraform.</p> <h2 id="lesson-1-always-use-a-hostname-not-an-ip-address">Lesson 1: Always use a hostname - not an IP address</h2> <p>Ok, so this one is not strictly a Terraform issue, but one to watch for nonetheless. After creating all three elements in Azure and connecting the hybrid connection in Azure to an internal resource using Hybrid Connection Manager, eveything appeared to be connected, but I was getting an error message</p> <p><code> Err Connection refused</code></p> <p>My error was attempting to use the IP address of our intenral resource, instead of the hostname. Hybrid connections will try and resolve the IP address using DNS, and consequently look to the internet rather than an internal network to resolve this.</p> <h2 id="lesson-2-always-use-lowercase-url">Lesson 2: Always use lowercase URL</h2> <p>Again, not strictly a hybrid connection issue, this was caused by my use of a hostname <code>http://xxx-123-ukQConnect:1234</code>. Notice the <code>QC</code> part there? Well I didn't for about 2 days! This would likely not have been an issue for most setups, but I am using Linkux containers in Azure to talk to the hybrid connection. Linux will be quite upset if you attempt to use casing in your URLs.</p> <h2 id="lesson-3-there-are-some-things-terraform-just-cant-do.yet">Lesson 3: There are some things Terraform just can't do.... yet!</h2> <p>TL:DR - Terraform does not create the resources you need to create a working hybrid connection for your web app in Azure.</p> <p>The first thing to note is when creating a hybrid connection for app service, you need to create three resources</p> <ol> <li>Azure relay</li> <li>Azure Hybrid Connection</li> <li>Azure App Service Hybrid Connection</li> </ol> <p>The default script provided in the <a href="https://www.terraform.io/docs/providers/azurerm/r/app_service_hybrid_connection.html">docs</a> creates these three elements, but once they have been provisioned in your resource group and configured, they will not connect to your interal resource.</p> <p>In my investigation, deleting the Azure app service hybrid connection and then recreating it with the same settings using the Azure Portal fixed my connection issues.</p> <p>When terraform creates the hybrid connection it uses the default SAS (Shared Access Signature) keys created on the relay called <code>RootManageSharedAccessKey</code> However, when the Azure Portal creates an app service hybrid connection it creates two new SAS keys at the hybrid connection level and uses those.</p> <p>Two SAS keys are created</p> <ul> <li><code>defaultListener</code></li> <li><code>defaultSender</code></li> </ul> <p>In the app service hybrid connection, the <code>defaultListener</code> key is set in the Gateway Connection String, so the value looks something like this</p> <p>`Endpoint=sb://<em>yourrelayname</em>.servicebus.windows.net/;SharedAccessKeyName=defaultListener;SharedAccessKey=<em>Generated SAS key value</em>=;EntityPath=<em>your hybrid connection name</em></p> <p>This is important as when the hybrid connection tries to talk to resources sat behind it, it uses TLS 1.2 for security and it's shared access signature (SAS) keys for authentication and authorization.</p> <p>To this end, I'm not sure if anyone has ever managed to get a hybrid connection working in Azure having scripted it using Terraform.</p> <p>This is not meant to be a dig at Terraform or the team behind it. I think its an amazing tool, which has allowed our team to get further than we though possible with IAC, I'm sure the feature will eventually be added, indeed a better developer would file a bug report and submit a PR against it.... 🤔 Perhaps, an update of the documentation would also work?</p> <p>The approach we have ended up with is adding the relay and it's hybrid connection using Terraform, and then updating the project's readme to manually create the app service hybrid connection using the Azure portal for now.</p> Installing SSL Certificates in IIS https://blog.gaisford.me.uk/posts/sslcert <p>For many years I've never really understood SSL certificates. Sure I get why we need them, but why do I need one when developing on my local machine. But things came to a head last week when I needed to replicate a bug in production that we weren't seeing locally.</p> https://blog.gaisford.me.uk/posts/sslcert Sat, 14 Mar 2020 00:00:00 GMT <p>For many years I've never really understood SSL certificates. Sure I get why we need them, but why do I need one when developing on my local machine. But things came to a head last week when I needed to replicate a bug in production that we weren't seeing locally.</p> <h2 id="steps-to-replicate">Steps to replicate</h2> <ol> <li>Navigate to the checkout page.</li> <li>Enter a credit card number (use a test one stored in Chrome)</li> </ol> <h3 id="expected-behaviour">Expected behaviour</h3> <ul> <li>Browser displays card number, expiry date and CVC</li> </ul> <h3 id="actual-behaviour">Actual behaviour</h3> <ul> <li>Browser only displays card number</li> </ul> <p>Without going in to too much detail, some javascript wasn't firing when the browser pulled the card details from its secure store. We had javascript running <code>onclick</code> <code>ontab</code> <code>onblur</code> on pretty much every event except this one.</p> <p>Browsers will not offer to use a card it has stored unless running on SSL with a trusted certificate.</p> <p>So I needed an SSL certificate, but not one, six. I am working on a white labelled site which runs on many URLs. So I created a Powershell script.</p> <p>This script will....</p> <ul> <li>create an SSL certificate</li> <li>save it to disk</li> <li>add it to your personal certificate store on your local machine</li> <li>create HTTPS bindings in IIS using the certificate</li> </ul> <p>Now, this much I had figured out before. I had created on and told IIS to use it when serving my local site, yet still honking warnings were displayed by my browser. The bit that finally clicked for me was when I realised as this is local dev my machine is both creator and consumer (server and client) of the certificate. So, although my server (IIS) was correctly serving the cert, my browser had to be forced to trust the cert (as this was only a locally created cert).</p> <p>Once I had added the certificate to the browsers trusted certificate store I finally had a green, secure site on local.mysite.com.</p> <p><a href="https://github.com/JamesGaisford/iis-ssl-cert">The full script is available over on GitHub</a>. If it saves you a few minutes, drop a note in the comments to let me know.</p> Honesty in tech https://blog.gaisford.me.uk/posts/tech-and-magic <p>I am a massive fan of podcasts. I first started listening to them back in 2009 on my commute to work. It was so valuable to me to have the opportunity to learn whilst driving. Gaining back 'lost time'. <a href="https://www.hanselminutes.com/archives">Hanselminutes</a> was my gateway drug to tech podcasts. It remains consistently brilliant after ~720 episodes. If you're interested in technology, go subscribe, I'll wait.</p> https://blog.gaisford.me.uk/posts/tech-and-magic Sun, 08 Mar 2020 00:00:00 GMT <p>I am a massive fan of podcasts. I first started listening to them back in 2009 on my commute to work. It was so valuable to me to have the opportunity to learn whilst driving. Gaining back 'lost time'. <a href="https://www.hanselminutes.com/archives">Hanselminutes</a> was my gateway drug to tech podcasts. It remains consistently brilliant after ~720 episodes. If you're interested in technology, go subscribe, I'll wait.</p> <p>Back at the end of last year I discovered the BBC podcast <a href="https://www.bbc.co.uk/programmes/p07nklnm">The Missing Cryptonqueen</a>. It tells the story of an entrepreneur who created her own crypto currency. Without wanting to give too much away (spoilers!), the currency was a smokescreen for an old-fashioned pyramid selling scheme.</p> <p>What was different about this scam was the scale of the scam. She made <em>billions</em> (no, that's not a typo) of dollars selling people a dream. But technology wasn't what people were buying in to here, the dream for sale was making money. Technology was just the magician's misdirection.</p> <p>The series got me thinking about the fine line between technology and magic. Arthur C. Clarke said &quot;Any sufficiently advanced technology is indistinguishable from magic.&quot; And it's true. Think back to the first time you saw a smartphone, or a videocall. You probably couldn't believe what you were seeing. If you had not been in the same room with it, touched it, you wouldn't have believed it was real.</p> <p>But with software and a lot of the concepts surrounding it, you can't do these things. You can touch nosql or see a cryto currency. You can't be in the same room as a Kubernetes cluster. These things are conceptual by their very nature.</p> <p>However the difference between technology and magic is that technology is magic that becomes real. These things that twenty years ago may have seemed fantastical, like being able to know the exact location of your friend where ever they are in the world are now commonplace. And therein lines the rub. Because the fantastical become real it is easy to deceive people. Even those with a lot of knowledge about technology.</p> <p>However I believe what ever level you are at as a technologist, from straight out of college to Senior Vice President, we all have a responsibility to be clear, open and honest with those with less understanding. With a greater understanding of anything comes responsibility.</p> <p>As tempting as it may seem to be liberal with the truth, like when your boss asks you tomorrow for an estimate on when that story is going to be done, honesty always pays back many times over. It could also seem like a good idea to oversell a particular technology or tool because you are curious to use it in the latest product you are building, but again, being honest and genuine with your motives, and your team, will stand you in better stead.</p> <p>So, go use your better understanding of technology to help others, to explain the concepts, so they too understand them just a bit little more. Share your knowledge with everyone. And I mean everyone. Yes, even that family member who asks you again to explain why Duo is appearing next to all the contacts in his phone. Share my friends. ❤</p> Blazor Glory! https://blog.gaisford.me.uk/posts/blazor-experiment <p>Over the pun yet? Me neither! While we wait for the myrth to subside, I'll share the lessons I learned building my first Blazor Server app. But first, some context. I've just finished a small side project at work which was off the radar, meaning I had my choice of technology. Having recently returned from <a href="https://developerdeveloperdeveloper.com/">DDD Reading 2019</a> where <a href="https://twitter.com/crad77">Marco De Sanctis</a> gave a brilliant talk on Building Single Page apps with Blazor and ASP.Net Core 3.0, I was inspired!</p> https://blog.gaisford.me.uk/posts/blazor-experiment Thu, 12 Dec 2019 00:00:00 GMT <p>Over the pun yet? Me neither! While we wait for the myrth to subside, I'll share the lessons I learned building my first Blazor Server app. But first, some context. I've just finished a small side project at work which was off the radar, meaning I had my choice of technology. Having recently returned from <a href="https://developerdeveloperdeveloper.com/">DDD Reading 2019</a> where <a href="https://twitter.com/crad77">Marco De Sanctis</a> gave a brilliant talk on Building Single Page apps with Blazor and ASP.Net Core 3.0, I was inspired!</p> <h2 id="charity-advent-calendar">🎄🎄 Charity Advent Calendar 🎄🎄</h2> <p>The brief was to quickly build an Advent Calendar which only employees could play. The calendar runs each year, but this year in an effort to get more players, I created a digital version. It needed to store guesses, display a leaderboard and display content from a database.</p> <p>The talk at DDD showcase how simple creating this kind of thing was using Blazor. I started with the single page template that ships with Blazor. I added <a href="https://www.matblazor.com/">MatBlazor</a>, which gave me a boat-load of Material styled Blazor components to work with. This made the UI super-simple to build. I was off to a flyer.</p> <h2 id="authentication">Authentication</h2> <p>The site is running in Azure and needed to only be accessible by employees. I was aware of &quot;turn-key&quot; authentication in Azure, but wondered what the Blazor story would be. After enabling authentication of the App Service in Azure, I added the following to the <code>startup.cs</code> file in the root</p> <pre><code>services.AddAuthentication(AzureADDefaults.AuthenticationScheme) .AddAzureAD(options =&gt; Configuration.Bind(&quot;AzureAd&quot;, options)); services.AddControllersWithViews(options =&gt; { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(policy)); }); </code></pre> <p>Adding an <code>azureAD</code> section to the <code>appsettings.json</code> with the following was all the code needed;</p> <pre><code> &quot;AzureAd&quot;: { &quot;Instance&quot;: &quot;https://login.microsoftonline.com/&quot;, &quot;Domain&quot;: &quot;youraddomainname&quot;, &quot;TenantId&quot;: &quot;the id of your tenant&quot;, &quot;ClientId&quot;: &quot;the id of the client registered in your ad&quot;, &quot;CallbackPath&quot;: &quot;/signin-oidc&quot; }, </code></pre> <p>With these two snippets of code, my Blazor app was ready to authenticate with our AD. This provided the authentication and basic user information to use in the calendar.</p> <p>Having integrated Angular apps in to the very same AD with a lot of blood, sweat, tears and dev tantrums, I was amazed how simple this was to implement, not to mention how &quot;It Just Worked&quot; ™</p> <h2 id="efcore-and-blazor-server">EFCore and Blazor Server</h2> <p>Of course it wasn't all plain sailing. I used EF Core to talk to SQL Server, which caused a number of issues. In hindsight, Dapper or something a little more lightweight would have been a better option here. The main issue I had was my lack of understanding of how Blazor works with it's &quot;server&quot;.</p> <p>Blazor Server persists a connection to connected clients using SignalR. So, as EFCore gets entities from the database, it tracks them to allow changes to be persisted back to the database. The Advent calendar allowed players to guess what was behind each door. They could also update their guesses. As players updated their guess EFCore began a battle with itself and the state persisted by Blazor. As soon as a tracked entity was updated the output window in Visual Studio began to spew update and select statements for the edited guess. It took a while to figure it out, but ultimately the fix was simple. For queries that presented data back to the user I needed to add, <code>AsNoTracking()</code> to the queries. So</p> <p><code>context.Guesses.ToList();</code></p> <p>becomes</p> <p><code>context.Guesses.AsNoTracking().ToList();</code></p> <p>This prevented EFCore tracking the state of entities. As soon as they left the database EFCore 'forgot' about them.</p> <h2 id="burning-money-for-charity">Burning Money for Charity</h2> <p>As this was a charity advent calendar, it was more important than ever to keep the Azure costs to a minimum. While investigating the options for the db (SQL Server to allow for simple internal reporting) I stumbled upon Azure's new Serverless option. It looked perfect. To quote the docs</p> <blockquote class="blockquote"> <p>&quot;Azure SQL Database serverless is a new compute tier that optimises price-performance and simplifies performance management for databases with intermittent, unpredictable usage. Serverless automatically scales compute for single databases based on workload demand and bills for compute used per second.&quot;</p> </blockquote> <p>As demand for the app was expected to be low and intermittent, this looked like the option for me.</p> <p>However, in the first 4 days, hosting costs for the db alone were £20 with the end of month cost predicted to be around £300! I scaled down to a cheapest 'Basic' tier (2GB &amp; 5DTUs) and the cost has barely moved in the proceeding 8 days!</p> <p>I'm not quite sure why this ended up being so expensive. I suspect it was something to do with SignalR holding open a connection to the db and incurring additional cost that way.</p> <p>Either that or I have misunderstood the concept of serverless and intermittent use.</p> <p>Of course it could be that the Advent calendar was an underground hit, which I'm secretly pleased to say it was 😊.</p> <p>Blazor server was super simple to get started with. If you have a background with Razor or Razor Pages you will feel at home here. I think once this moves to the browser with the Blazor WebAssembly (coming soon), Angluar and the other JS frameworks will have some significant competition.</p> Too much help? https://blog.gaisford.me.uk/posts/too-much-help <p>A mentee and I were grabbing our regular Friday morning overpriced flat white and discussing asking for help and how we generate ideas as a team when he said something that struck me.....</p> https://blog.gaisford.me.uk/posts/too-much-help Wed, 28 Aug 2019 00:00:00 GMT <p>A mentee and I were grabbing our regular Friday morning overpriced flat white and discussing asking for help and how we generate ideas as a team when he said something that struck me.....</p> <p><em><strong>&quot;As soon as you speak, that's the idea we go with.&quot;</strong></em></p> <p>As the technical lead on the team I had until this point assumed speaking up and offering suggestions was always helpful. A smattering of natural arrogance makes me think my ideas are great. Certainly the ones that make it to my mouth!</p> <p>This lead to a bit of a realisation that perhaps keeping quiet is the best way to help others discover things, not always leaping in with an idea or suggestion.</p> <p>Since that flat white, I'm trying to sit back in meetings and let other suggestions come out, consider those and speak up if I have a better idea. In pair programming / debugging situations, I'm trying to let people discover for themselves, rather than just give them the answer. When people do ask directly for help I ask questions like;</p> <ul> <li>What have you tried so far?</li> <li>At what point did your code break?</li> <li>What do you think caused it to break?</li> </ul> <p>The intention with these kind of questions is to have them leading the conversation, working through the problem in a methodical, analytical way, with the intention of starting to acquire some core engineering skills.</p> <p>Finally, if none of these things work, remember it's also ok to say no to helping someone. It might take them longer, they may make more mistakes whilst finding the solution, but sometimes the journey is as important as the destination.</p> 5 tips for mentoring software developers https://blog.gaisford.me.uk/posts/mentoring <p>Mentorship comes in many shapes and sizes. It could be informal, as you gain experience in your team and become the go-to person for particular areas of the system you are working on. Perhaps you are asked to introduce these areas of the system to all new starters. This is mentoring. It could be more formal, as part of a wider scheme within your organisation. Whatever shape it takes if you are;</p> https://blog.gaisford.me.uk/posts/mentoring Fri, 07 Jun 2019 00:00:00 GMT <p>Mentorship comes in many shapes and sizes. It could be informal, as you gain experience in your team and become the go-to person for particular areas of the system you are working on. Perhaps you are asked to introduce these areas of the system to all new starters. This is mentoring. It could be more formal, as part of a wider scheme within your organisation. Whatever shape it takes if you are;</p> <ul> <li>offering support and guidance to colleagues</li> <li>on technical or non technical matters</li> <li>because you have more experience</li> </ul> <h3 id="you-are-a-mentor">You are a mentor!</h3> <p>prag I've had the fortune to mentor a number of colleagues in my time, and below are five of the key things I've learned along the way. Hopefully they will help you if you are mentoring someone.</p> <ol> <li><p>Make time for your mentee <strong>This is 100% THE most important point on this list</strong>. Your time is precious. We get that, but that is why it is such a valuable thing to offer to your mentee. If you can't make time, perhaps rethink if you are the best person on your team to be mentoring. The more time you can devote to your mentee, the more valued they will feel. It's a given your mentee is feeling a degree of imposter syndrome. I still feel it on an almost daily basis. They may be scared to ask you for help. Take time to ask if they are ok. If they repeatedly say yes, probe a little further with open questions. Offer your help. Offer it again. And again. You'll eventually wear them down ;)</p> </li> <li><p>Work through some code together. If they have written some code to implement a feature, go through it with them - kind of like a pre-code-review code review. The process of them explaining the code to you will tell you a lot about how much they understand what they have done. This will also give you a fairly clear idea of where there strengths and weaknesses are. This gives you an idea of where to focus your efforts to help them improve.</p> </li> <li><p>Be clear on your expectations of them. If you are expecting them to present back their work to you on a regular basis, make this clear. Set a schedule that is concrete to give them something to work to. Give them a deadline. Wooley suggestions like &quot;show me when your ready&quot; introduce ambiguity for both parties and should be avoided.</p> </li> <li><p>Keep tabs on those soft skills</p> <p>The best engineers are not always those that know most about the language or framework. Computer science will only get you so far in this industry! The best engineers are able to compromise, are pragmatic and are able to influence and organise their team to work more collaboratively towards achieving success. So, help them to hone those skills. I still swear by <a href="https://www.amazon.co.uk/Pragmatic-Programmer-Andrew-Hunt/dp/020161622X">The Pragmatic Programmer</a> as a great introduction to these non-computer-science skills that will set your mentee on the right path.</p> </li> <li><p>Lead by example</p> <p>It's easy to offer advice, but as Robyn S said back in 1993, &quot;Actions speak louder than words!&quot; The best way to demonstrate the wisdom of your suggestions to your mentee is to follow them yourself. If you have development standards, be sure you are following them to the letter. You must live and breath them. If you espose the virtues of repairing broken windows in software, make sure you are tidying and repairing in your contributions to the code.</p> </li> <li><p>Set your ears to listen</p> <p>What would a top 5 be without a sixth point! Make sure you listen to your mentee. Sure, you have an idea of what you think they want to achieve or where they want to go, but is it really what they want? What are they telling you? Fully listen when they are talking to you. While they are talking, don't worry about how you are going to respond. Wait until they finish speaking. Then think. Then speak. Don't jump in and cut them off mid sentance. Wait until they have finished speaking. Then think. Then speak!</p> </li> </ol> <p>Hopfully one or all of those help you as you are mentoring those in your organisation. If you have any tips to add to the list, put them in the comments below.</p> Using Azure Blob Storage to host this blog https://blog.gaisford.me.uk/posts/wyam-blog <p>Originally this blog was hosted in Blogger, which I used between 2008 and 2012. It then fell in to disrepair until I ported it to an Umbraco site running on Azure, where I spent six months building the site and about ten minutes writing posts for that version of the blog. Add to that the suprisingly expensive hosting costs and it's easy to see why I lost interest again after another six months.</p> https://blog.gaisford.me.uk/posts/wyam-blog Mon, 27 May 2019 00:00:00 GMT <h3 id="why-move">Why move?</h3> <p>Originally this blog was hosted in Blogger, which I used between 2008 and 2012. It then fell in to disrepair until I ported it to an Umbraco site running on Azure, where I spent six months building the site and about ten minutes writing posts for that version of the blog. Add to that the suprisingly expensive hosting costs and it's easy to see why I lost interest again after another six months.</p> <p>So, this time I wanted a platform that was going to be reliable, free, hastle free to build, and require no coding when I created new posts.</p> <h3 id="enter-wyam">Enter Wyam</h3> <p>I first heard about Wyam when <a href="https://www.hanselman.com/blog/ExploringWyamANETStaticSiteContentGenerator.aspx">Scott Hanselman wrote about it</a> a few years back. <a href="https://wyam.io">Wyam</a> is a static site generator, but has so many more potential uses. Using Wyam inbuilt 'recipie' for a blog allows me to author markdown files and have them turned it to the shineyness you see before you now with minimal effort.</p> <h3 id="dev-setup">Dev setup</h3> <p>Installation was a breeze. Firstly I installed Wyam as a global dotnet tool</p> <p><code>dotnet tool install -g Wyam.Tool</code></p> <p>With the tool installed, I then uses it to create the blog</p> <p><code>wyam --recipe Blog --theme stellar</code></p> <p>This ran a series of pipelines which ultimately created a set of css and html files in an <code>/output</code> folder based on content I created in an <code>/input</code> folder.</p> <p>Following the official docs and other blogs I came unstuck at a number of points. Mainly this was my fault for not reading these articles correctly, but I thought the most helpful thing I could do would be to share teh <code>config.wyam</code> file that I used for this site, because if you've ended up here you are likely stuck as well.</p> <hr /> <h3 id="pro-tip">👨‍🏫 Pro Tip</h3> <p>Not sure how config.wyam should be set up. Head on over to the <a href="https://github.com/Wyamio/Wyam/">GitHub</a>. site. There's loads of <a href="https://github.com/Wyamio/Wyam/tree/develop/examples">examples.</a></p> <hr /> <h3 id="config.wyam">config.wyam</h3> <p>Here is my final config file...</p> <pre><code>System.Globalization.CultureInfo.DefaultThreadCurrentCulture = System.Globalization.CultureInfo.CreateSpecificCulture(&quot;en-GB&quot;); #recipe Blog #t Stellar Settings[&quot;host&quot;] = &quot;www.gaisford.me.uk&quot;; Settings[Keys.LinksUseHttps] = true; Settings[BlogKeys.Title] = &quot;On Software Engineering&quot;; Settings[BlogKeys.Intro] = &quot;My name is James. I am a Software Dev ✔ | Tech Lead ✔ | Devops Evangelist ✔ | Infrequent Speaker ✔ | DIY Master ❌&quot;; Settings[BlogKeys.Description] = &quot;On Software Engineering&quot;; Settings[BlogKeys.IgnoreFolders] = &quot;drafts&quot;; Settings[Keys.DateTimeInputCulture] = &quot;en-GB&quot;; </code></pre> <p>Most of the settings are fairly descriptive, but there's a few things to point out here...</p> <p>Wyam has a number of settings defined in it's config file, which are split by keys generic to all Wyam builds (Keys) and those specific to the blog recipe (BlogKeys).</p> <h4 id="settingskeys">Settings[Keys]</h4> <p><code>Settings[&quot;host&quot;]</code> is used when generating links in your HTML, so it needs to match the URL of the site your hosting on.</p> <h4 id="settingsblogkeys">Settings[BlogKeys]</h4> <p><code>Settings[BlogKeys.IgnoreFolders]</code> allows certain folders to be ignored when Wyam is creating the blog. This allows me to create draft posts which don't end up on the live site until I move them in to the posts folder.</p> <p>The path (or paths) in this setting are relative to the <code>input</code> folder. In my case the <code>drafts</code> folder which I ask Wyam to ignore is at <code>/input/drafts</code>.</p> <p><code>Settings[Keys.DateTimeInputCulture]</code> I had a bit of trouble getting posts to generate in my first nine or ten attempts. I was getting a message &quot; ../ghostscript.md error while reading published date for feed&quot;</p> <p>I eventually figured out that by setting the DateTimeInputCulture explicitly and DefaultThreadCurrentCulture I was able to use the published date to the standard UK format of DD/MM/YYYY.</p> <hr /> <h3 id="pro-tip-1">👨‍🏫 Pro Tip</h3> <p>Not sure how or where the settings are used in the blog recipe. Take a look at the GitHub page for the theme your blog is using. In my case, it's the <a href="https://github.com/arebee/wyam-theme-stellar">Stellar theme</a>.</p> <hr /> <h3 id="front-matter-aka-post-metadata">Front matter aka post metadata</h3> <p>Front matter is a concept that allows you to add additional data describing your post to the same document as the main post. Front matter is added to the top of the post and is used throughout the recipe.</p> <p>The <a href="https://wyam.io/docs/concepts/metadata">docs here</a> relate more to the use of Front matter in Wyam as a concept rather than specifically to the blog recipe, so that threw me off a little. If in doubt, consult GitHub to see where the recipe uses the Front matter.</p> <p>Below shows the front matter contained in this post</p> <pre><code class="language-Title:">Published: 22/5/2019 Lead: This blog is now hosted in Azure for free using Blob Storage and a CDN with a free SSL cert. There were a number of bumps in the road and this post highlights the issues with getting started with Wyam - which was used to build the site. Tags: - Azure - Wyam --- </code></pre> <p>Worth noting is the following;</p> <ol> <li>Date format in the <code>Published</code> property must match that set in your config.wyam.</li> <li>Lead: is used by the recipe to show an overview of your post in the Archive, on the front page of the site, and on the top of the page for the post itself.</li> <li>Tags: used to tag the post, but the format is as above for more that one tag, but can also be like this for a single tag - <code>Tags: SQL Server</code></li> </ol> <p>And that's about it. The site is up and running on Azure, with the workflow I was hoping for. It's hosted in blob storage with SSL (post soon?) and it's also set it up with CD using Azure Devops (post soon!), so feeling pretty please with myself.</p> Umbraco Preview - Are my changes live or not? https://blog.gaisford.me.uk/posts/umbraco-preview <p>This post is based on the following Umbraco setup.</p> https://blog.gaisford.me.uk/posts/umbraco-preview Mon, 14 Sep 2015 00:00:00 GMT <p>This post is based on the following Umbraco setup.</p> <ul> <li>Umbraco v7.2</li> <li>Azure Sql Server - Web Edition</li> </ul> <p><strong>Background</strong></p> <p>Preview in Umbraco lets you quickly see how your page will look on different devices. It allows content editors to switch between different devices previews and see how their content will display on a number of common device sized before making their changes live. Recently I had a client raise a few concerns about how the preview functionality worked and so this post is for all those who have to do the same in the future.</p> <p><strong>Where's my preview button?</strong></p> <p>The first problem the client had was not being able to see a preview button on their newly created pages. In order to preview content, the content must first be saved. Once saved (but not necessarily published) the preview button will appear in Umbraco.</p> <p><strong>Is it live or not!</strong></p> <p>When a content editor clicks preview they are able to see what the website will look like before it is published and available to all website members. Umbraco does this by setting a cookie in the user’s browser which is persisted until they log out of the CMS. This caused great confusion with my client who was concerned the preview functionality was broken. They had made changes and previewed them in the cms. They had then visited the main site as a member, while still logged in to the CMS. As the preview cookie had not been cleared they could see their unpublished changes on the live site. Of course the changes were not live, and once they logged out of Umbraco, normal service was resumed. However, we now always advise....</p> <p>Once content editors have finished previewing content, they should always logout of Umbraco to ensure they are seeing live content rather than preview content.</p> Talking with tech leads James Gaisford https://blog.gaisford.me.uk/posts/tech-leads <p>At the end of last year I was offered the role of Head of development at my company. Having been a reluctant senior developer, I was a little reluctant to take the role, but after some careful consideration I accepted the offer. As with previous career challenges, I sought advice and guidance from the internet. But the best steer came from an unlikely source - a tweet from Martin Fowler</p> https://blog.gaisford.me.uk/posts/tech-leads Tue, 14 Jul 2015 00:00:00 GMT <p>At the end of last year I was offered the role of Head of development at my company. Having been a reluctant senior developer, I was a little reluctant to take the role, but after some careful consideration I accepted the offer. As with previous career challenges, I sought advice and guidance from the internet. But the best steer came from an unlikely source - a tweet from Martin Fowler</p> <p>.&#64;wilpannell The book on being a tech lead is by &#64;patkua <a href="https://t.co/BoyWVS6F0e">https://t.co/BoyWVS6F0e</a></p> <p>— Martin Fowler (&#64;martinfowler) December 20, 2014</p> <p>The book referred to in the tweet is called &quot;Talking with tech leads&quot; and it is a must read for all developers thrust into the strange and unfamiliar world of leading a technical team. The book takes the form of interviews with a number of tech leads, asking a core set of questions particularly around significant challenges faced and how they balance the technical and non-technical worlds.</p> <p>So, after my first six months as a tech lead, I present my answers to those same core questions asked in the book.</p> <p><em>What should a Tech Lead focus on and why?</em></p> <p>Solving problems without coding. As a developer your core skill is to be able to solve problems by coding. This is a skill that has been honed over many years. It is very tempting as a developer, new to the tech lead role, to offer only code based solutions to customer problems, but stop. and think if there could be a non-code based solution to the problem presented. Pushing back on client requirements? Negotiating with project managers to get additional resource? Scrutinizing client requirement documents? Writing tight functional specifications. All of these and other non-code based solutions can come to your rescue. Expand you toolbox.</p> <p><em>What has been your biggest challenge as a Tech Lead?</em></p> <p>Don't over-commit.... and delegate. With a new role comes a lot of new responsibility. This means a lot more work. Depending on the set up in your company, there may be an expectation that you still perform some or all of your previous role's responsibilities as well. You will be asked to do a lot, but don't be afraid to push back, to say no. You may have a team to whom you can delegate some of your work to. Don't be afraid to use them. No one will think you are incapable, slacking off, or being lazy. In fact, if the team is good, they will relish the challenge.... just don't over do it.</p> <p><em>Any time-management tips?</em></p> <p>Get in early. Process emails. Work out a plan of attack for the day. Create a simple list using a pen and paper - I know, it's pretty revolutionary - in priority order to work through. Close the inbox. Cross through items on your list. Its amazing how that simple process can help feel like you are &quot;winning&quot; t the day. Decline any meetings invites that aren't relevant. And for those meetings you have to go to, make sure there is an agenda with a clear purpose, and any actions noted.</p> <p><em>How do you strike the right balance between writing code and dealing with other issues?</em></p> <p>This is really tough. The thing that makes this easier, is knowing you have a team of people who are as good, if not better, than you at coding. So, there is no need to worry that the code will get written. Of course you should always try and devote at least some time in your week to writing code, but nothing that will take longer than a day and nothing that would jeopardise the project if you had to drop it.... which you most likely will.</p> Using GhostScriptSharp to create pdf thumbnails https://blog.gaisford.me.uk/posts/ghostscript <p>It sounds like a simple task. Creating thumbnails of uploaded files for display in a repeating list. The project I am working on uses Kentico CMS, which provides the majority of this functionality out of the box. However, it did not create thumbnails for pdf files. The interim solution was to display the default pdf file icon. This worked for the first few weeks after which it became clear that the majority of the uploaded documents were pdf's. This made for a very uniteresting screen, so the decision was made to find a component or service to create pdf thumbnails.</p> https://blog.gaisford.me.uk/posts/ghostscript Wed, 03 Aug 2011 00:00:00 GMT <p>It sounds like a simple task. Creating thumbnails of uploaded files for display in a repeating list. The project I am working on uses Kentico CMS, which provides the majority of this functionality out of the box. However, it did not create thumbnails for pdf files. The interim solution was to display the default pdf file icon. This worked for the first few weeks after which it became clear that the majority of the uploaded documents were pdf's. This made for a very uniteresting screen, so the decision was made to find a component or service to create pdf thumbnails.</p> <p>After a little research I decided on GhostscriptSharp, a C# wrapper for the GhostScript library. Installed, up and running, and simple solution implemented beautifully on localhost within a couple of hours. And so to the Staging staging server.... a very different server. This did not take hours or sadly days, but a couple of weeks (albeit of on and off development) to get working.</p> <p>I am now going to outline the major time-sinks I encountered when getting GhostscriptSharp working on a remote staging server;</p> <p>Firstly, you do not need to install GhostScript on the server which your code is running. This is something that was not 100% clear from the documentation. I was also hampered by the suggestion from several other blog posts that this was indeed a prerequisite for getting GhostScriptSharp up and running. For me, this was simply not the case. Your application will only require the correct version (I'll come to this later!) of the GhostScript dll in it's bin folder.</p> <p>The next problem I encountered was the following error message;</p> <p><code>Message: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B) Stack Trace: at GhostscriptSharp.GhostscriptWrapper.CreateAPIInstance(IntPtr&amp;amp; pinstance, IntPtr caller_handle)</code></p> <p>My working solution was developed on a 64-bit machine. I was deploying to a 32bit machine. There are two versions of GhostScript a 64 bit and a 32 bit version (can you see where I'm going here?).</p> <p>So, if you see this error message with your GhostScript application, check you are using the correct version of the dll.</p> <p>Correct dll in the bin folder. Show me the pdf thumbnails.</p> <p>No?</p> <p>Another error message was now being displayed by my application. This one said;</p> <p><code>Unable to load DLL 'gsdll32.dll': The specified module could not be found.</code></p> <p>This error message was caused by insufficient permissions on the bin folder. To overcome this I had to grant read &amp; write permissions for the application pool identity on the /bin folder to enable it to access the dll.</p> <p>Another error message bites the dust, surely now.... thumbnails? No. Though now my application was up and running, so no more asp.net error messages, just application error messages. This one said;</p> <p><code>Ghostscript 100 error</code></p> <p>As it so often does, Stackoverflow came to the rescue. As well as granting read and write permissions on the bin folder, I also had to grant read and write permissions on the /files folder (the folder my thumbnails were being written to). This allowed the GhostScript dll to write thumbnails to the specified location.</p> <p>And with that final change, the application sprang in to life and several hundred thumbnails were written to disk. Ah, the taste of victory.</p> <p>In summary, writing the GhostScriptSharp code was a really simple process. Getting it to run on a production server was a slightly more involved process, but I would definitely use it again on other projects with the configuration knowledge I now have in the bank.</p> Continual learning & getting involved https://blog.gaisford.me.uk/posts/getting-involved <p>The Dean's speech at my graduation ceremony professed that this would not be the end of my learning, but in fact the beginning. Learning is a lifelong process. It was an interesting speech and one that has rung very true in my career as a developer. If you are not continually learning then you will quickly become stale as a developer, not only in terms of the code you are writing, but the tools and processes you are using to write it.</p> https://blog.gaisford.me.uk/posts/getting-involved Mon, 15 Jun 2009 00:00:00 GMT <p>The Dean's speech at my graduation ceremony professed that this would not be the end of my learning, but in fact the beginning. Learning is a lifelong process. It was an interesting speech and one that has rung very true in my career as a developer. If you are not continually learning then you will quickly become stale as a developer, not only in terms of the code you are writing, but the tools and processes you are using to write it.</p> <p>Since starting as a junior developer I have had a bit of an infiriority complex wher it comes to other developers. So after <a href="http://codebetter.com/jeremymiller/2009/05/05/revitalizing-a-technical-career/">seeing a post by Jeremy Miller on CodeBetter</a> I was inspired to do more than the odd hour of book reading that I had previously been kidding myself was enough to improve as a developer.</p> <p>As part of my quest to become a better developer I have done the following;</p> <ul> <li><p>Begun blogging - if you're reading this, you'll know all about it.</p> </li> <li><p>Started an out-of-work-hours side project</p> </li> <li><p>Attended community developer days (see below)</p> </li> <li><p>Begun contributing to StackOverflow</p> </li> <li><p>Subscribed to number of podcasts other than just Hansleminutes</p> </li> <li><p>Begun investigating MS Certification - Longer term goal.</p> </li> </ul> <h2 id="community-events">Community events</h2> <p>One of the most productive things I have done recently to learn more is attend <a href="https://dddsouthwest.com/">DDD SouthWest</a> a free community developer event. It was an excellent event, not only in terms of the content of the presentations, but also the organisation of the day. Combine this with the fact that it was all free - even the delicious food - and its difficult to understand why there were any empty seats - ok it was on a Saturday!</p> <p>The sessions I attended were;</p> <ul> <li><p>Embracing a new world – dynamic languages and .Net - Ben Hall</p> </li> <li><p>Get Going With jQuery - George Adamson</p> </li> <li><p>Real-world MVC architecture - Steve Sanderson</p> </li> <li><p>What’s New In C# 4? - Guy Smith-Ferrier</p> </li> </ul> <p>Here is the full agenda which gives a brief overview of all the sessions that ran on the day as well as source code and slides.</p> <p>During lunch there were a series of grok talks. Grok talks are 10 minute micro-presentations on a particular subject. Two of the ones that stuck with me were;</p> <ul> <li><p>10 tips for speeding up sql server by Jon Reade (SqlServerClub.com)</p> </li> <li><p>A talk on the fututre of developing .net for mobile devices (A developer whos name escapes me)</p> </li> </ul> <p>I have been inspired to get ore involved in my local community developer events. There are lots of good ones in the Bristol / Bath area on whose mailing lists I have lurked for the past few years / months. Its time to de-lurk and get involved. Here are a few of the groups I plan to infiltrate over the coming months.</p> <ul> <li><p>BathCamp</p> </li> <li><p>The .NET Developer Network</p> </li> <li><p>Underscore</p> </li> </ul> Sql Server - Get most recent item from a table using sub-select https://blog.gaisford.me.uk/posts/sql-server-subselect <p>Recently I needed to create a kinda complex sql query to get the most recent note that had been added to a case in an internal application at work. This is something I come across infrequently enough to forget it every time I want to do it so I thought I would post it as it may be of some use to others (and me next time I need it!)</p> https://blog.gaisford.me.uk/posts/sql-server-subselect Fri, 08 May 2009 00:00:00 GMT <p>Recently I needed to create a kinda complex sql query to get the most recent note that had been added to a case in an internal application at work. This is something I come across infrequently enough to forget it every time I want to do it so I thought I would post it as it may be of some use to others (and me next time I need it!)</p> <p>The requirement: We need to get the latest case note entry made by a user not the system. Data required is date, time, user ID, subject and content fields.</p> <p>The database structure:</p> <h2 id="case-table">Case Table</h2> <table> <tr> <th>Column name</th> <th>Type</th> </tr> <tr> <td>Id (PK)</td> <td>int</td> </tr> <tr> <td>CreateDateTime</td> <td>datetime</td> </tr> <tr> <td>CaseId (FK)</td> <td>varchar(50)</td> </tr> <tr> <td>CreateOperator</td> <td>varchar(50)</td> </tr> <tr> <td>NoteTitle</td> <td>varchar(100)</td> </tr> <tr> <td>NoteContent</td> <td>text</td> </tr> <tr> <td>Service</td> <td>varchar(50)</td> </tr> <tr> <td>Service</td> <td>varchar(50)</td> </tr> </table> <h2 id="service-table">Service Table</h2> <table> <tr> <th>Column name</th> <th>Type</th> </tr> <tr> <td>Id (PK)</td> <td>int</td> </tr> <tr> <td>CaseId (FK)</td> <td>varchar(50)</td> </tr> <tr> <td>Status</td> <td>varchar(100)</td> </tr> </table> <h2 id="the-solution">The solution</h2> <p>It appears fairly straightforward at first glance. Just join across the three tables using primary keys and foreign keys. The complication comes in that we only want to see the most recently added note on a case.</p> <p>So, I used a sub-select to get the most recently created note ( max(CreateDateTime) ) and compare it to the CreateDateTime in the original select statement. It’s probably easier to look at the sql……</p> <p><code>DECLARE &#64;Service varchar(20) SET &#64;Service = ‘MyServiceName’ </code></p> <p><code>SELECT attach.Service, attach.CreateDateTime, attach.pxLinkedRefFrom, work.Id, attach.NoteTitle, attach.NoteContent, idx.Status FROM myCaseTable work JOIN myNoteTable attach ON work.Id = attach.CaseId LEFT OUTER JOIN myServiceTable idx ON idx.CaseId = attach.CaseId WHERE attach.CreateDateTime = (</code></p> <p><code>SELECT MAX(CreateDateTime) FROM myNoteTable attach2 WHERE attach2.CaseId = attach.CaseId AND attach2.CreateOperator &amp;lt;&amp;gt; 'System' AND attach2.Service = &#64;service) </code></p> <p>Any feedback, especially more performant ways of achieving the same thing task welcome.</p>