Posts

Showing posts from 2020

Auto Mapper and Record Types - will they blend?

Image
TL;DR: Yes, they will. Thank you for your time. 😄 Background At Redgate, engineers enjoy a great benefit in that we get are expected to spend 10% of our time to improve on our craft.  Having suffered this week with manually having to copy a bunch of properties from a domain object to its HTTP representation, I decided to spend this week's 10% time to see if I could answer the following questions: Can use AutoMapper to simplify mapping between two types?  Does it also allow me to map between a regular type and a record type? What about the other way around? Can I use this to reduce the maintenance burden in my product? Mapping between two types [automapper fundamentals] To started and get a basic mapping done, created a .NET 5 ASP.NET Web API project, added the below package references and configured automapper : < PackageReference Include ="AutoMapper" Version ="10.1.1" /> < PackageReference Include ="AutoMapper.Extensions.Microsoft.DependencyInj

Three random quotes and a tool

Image
Here are some random quotes I've come across recently and that I need to get off my post-its and into a digital format for prosperity ;) Experts don't follow rules. Rules are there to turn beginners into experts. Is this uncomfortable because it's new, or because I'm doing it wrong? A { Strategy | Project } is a { a process | a workflow } (that is, a collection of small steps) towards a big { Goal | Vision } Oh, here's a tool that I came across to aid in systems thinking!

What are some developer tools (or apps) worth spending money on?

Working for a tooling company at the moment, I am intrigued to learn about which tools and apps are non-negotiable - that you need - to do your work. Some apps comes to mind immediately, being Resharper / Rider SQL Prompt Which tools have you bought for yourself? If you had to,  which ones would you? Which tools do you try to get your company to purchase to make your life as a developer easier? Further, are there tools/apps that you have spent money on in your private life that have markedly made your life better/easier? Personally, I can't recommend YouTube Premium/Red enough, thinking its great value with its automatic save of your Watch Later clips to your tablet, automatic downloading of an offline music playlist to your phone ... very handy!

How an ADR saved the day!

Image
One of the principles we adhere to at my current company, is to write down Architectural Decision Records whenever we make a "larger decision". Recently, having such a record, came in super handy, as we were trying to resolve a licensing issue wherein our library was called from a .NET Core application through a .NET Framework, using a custom communication protocol. It was all very ... convoluted and - more importantly - didn't do what it was supposed to. The fact that no-one from the original team was still with us, didn't make things easier! After tearing our hairs out for quite a while, one of the team members offhandedly asked "shouldn't there be an ADR for this?", prompting us to look into the shared repository. There was! And right in it, it said: Once ************* .Client  starts supporting .NET Standard consumers, we can remove this workaround and fetch the license status from ******** directly. Much easier! Now we could remove a lot of very in

Build your cross-platform, natively executable web app in 3 minutes! #dotnetconf

Image
 Much kudos to John Juback (@jjuback) You'll need Visual Studio Code In a console/terminal window, type mkdir Processes cd Processes dotnet new webapp code . In Processes.csproj, add   <ItemGroup>     <PackageReference       Include="ElectronNET.API"       Version="9.31.2"/>   </ItemGroup> In Program.cs, add   using ElectronNET.API; on line 9                     webBuilder.UseElectron(args);                     webBuilder.UseEnvironment("Development"); on line 24 In Startup.cs, add   using ElectronNET.API; on line 11             if (HybridSupport.IsElectronActive) {                 CreateWindow();             }    on line 56         private async void CreateWindow() {             var window = await Electron.WindowManager.CreateWindowAsync();             window.OnClosed += () => {                 Electron.App.Quit();             };         } on line 61 In Visual Studio Code's terminal window, run dotnet tool install ElectronNET

API versioning with ASP.NET MVC Core and NSwag

Image
We support versioning in theory, but we've never really left v1.0 If this is a quote that resonates with you, read on. Our team added our first v2.0 endpoint in one of our products by doing the following: Removing [ApiVersionNeutral] on the endpoints that we didn't want versioned (as opposed to being available on any version of the API). Configuring ASP.NET to assume neutral if unspecified: services. AddApiVersioning ( o => { o. UseApiBehavior = true ; o. DefaultApiVersion = ApiVersion . Neutral ; o. AssumeDefaultVersionWhenUnspecified = true ; Removing our [ApiVersion("1.0")] on our base controllers Decorating our old methods with [ApiVersion("1.0")] Decorating our new methods with [ApiVersion("2.0")] It took some trial and error, as we presumed that we could just add [ApiVersion("2.0")] on our new stuff and be done with it. This made NSwag registering the endpoints multiple times, ho

Remove local git branches on Windows with PowerShell

Image
There is plenty of tooling and scripts for *nix systems  to delete local branches, but I was struggling to find useful snippets for Windows, so I made one. Remove-LocalBranches is available as a script on GitHub for you to download and modify to your heart's content. It removes non-active branches from a set of directories and is designed to be run as an atomic unit (doesn't accept input). The script is dependent on another utility script I wrote that enters a directory, runs a script block and then returns to where it were. That script is also available on GitHub. So, to answer "how do I remove unused / old local branches", the answer is "Run Remove-LocalBranches.ps1". I hope this is useful :)  Example run:

How to re-tag something in git

I make mistakes. One of the more annoying ones I make, is to push a release with the wrong tag, causing all sorts of issues. Here's how to re-tag things in git: Use git reflog to find the thing you want to re-tag (likely one of the most recent ones) - jot down the number (e.g.  a2a6ebea2 ) Use   git describe  a2a6ebea2  to double check that it points to your misconfigured release (e.g.  releases/ product name / version number ) Get your tag names with ( git for-each-ref --sort='-taggerdate' --format='%(tag),%(taggerdate:iso8601),%(refname),' "refs/tags/releases/**" ) Delete the erroneous tag with git tag --delete tag name Create a new tag with git tag --annotate " new tag name " a2a6ebea2 --message " Version NNNN " Push the deletion of the old tag with git push origin :refs/tags/ old tag name Push the creation of the new tag with git push --tags

Highly Declarable React #dont-make-me-think #hdr

Here's something I recently discovered and that I'm proud of; not because it's technically superior, but instead because it's much easier for the human to deal with. I present to you  H ighly D eclarative R eact     The idea is that your component declare its various states up front, making it easy to reason about function GenerateAuthTokenForm ({isOpen, setIsOpen}: GenerateAuthTokenFormParams ) { ... const [state, dispatch] = useReducer((state: { mode: string }, response: any) => { ... } ... return < SomeContainerElement>      < ShowProgressWhenUserClicksGenerate />      < ShowSuccessAfterTokenCreated />      < ShowInputUiByDefault />      < ShowErrorWhenTokenGenerationFails />      < NotifyWhenUserTriesToCreateNamelessToken />      < ButtonPanel onCancel = {() => setIsOpen( false )} onConfirm = { handleSubmit } />      </ SomeContainerElement > ); } Each element checks the local page state to see if it should re

A guessing game in Rust

If you'd like to learn Rust,  The Book  from Rust's official website, is freely available and quite good. I've gotten to chapter 10ish so farband have adapted the book's guessing game to flex my newfound skills. Here's that game . secret_numbers.rs  defines the  SecretNumber  struct, representing a guessable secret number and  Accuracy , representing how arbitrarily close to the guess a given number is. Some interesting points are the  derived traits automatically provided by the compiler  by decorating the  Accuracy  enum with  #[derive(PartialEq, Eq, Hash)] . PartialEq  and  Eq  implements functionality to compare values and, well - if you don't have it (or your own implementation), the compuler will tell you error[E0277]: can't compare  secret_number::Accuracy  with  secret_number::Accuracy  --> src\secret_number.rs:12:10 | 12 | #[derive(Eq, Hash, Debug)] | ^^ no implementation for  secret_number::Accuracy == secret_number::Accuracy  | = help: the trai

Objectives ... and Key Results

 A colleague of mine ran an open-space session today, wherein we discussed OKRs, a topic that had been presented in a recent conference they'd taken part in. If you've never heard the term OKR before, it's short for Objectives and Key Result and is a useful thinking process for strategic improvement. This is what I learned. When discussing OKRs, it's important to get back to the reason - the why - of an Objective. What are we trying to achieve? Why are we trying to achieve this thing? The Key Results needs to be on the right level, so that teams can act on them. Therefore, OKRs needs to be paired with the power/authority/autonomy to act. For a fictitious bedding store, the manager might say: "I'd like us this improve the sales of beds; you have free reign to come up with ideas to that effect!". His employees might here start to observe which types of customers tend to purchase beds and eventually find out that people trying beds are more likely to purchas

Vagrant failed to initialize at a very early stage ... nil:NilClass

I ran across an issue where most vagrant commands would fail, saying Vagrant failed to initialize at a very early stage: There was an error loading a Vagrantfile. The file being loaded and the error message are shown below. This is usually caused by a syntax error. Path: <provider config: virtualbox> Line number: 45 Message: NoMethodError: undefined method `start_with?' for nil:NilClass Naturally, I begun investigating my local Vagrantfile , but found nothing exciting at line 45 but an array iteration whose array I knew was initialized ...  machines.each do |machine| Eventually, I found a directory in my home directory whose name matched the box_name entry of my machines array: :box_name => ' redacted-company-name / centos-7-oracle12c2 ' Path: C:\Users\Sami.Lamti\.vagrant.d\boxes\ redacted-company-name -VAGRANTSLASH- centos-7-oracle12c2 \2020.02.11\virtualbox\Vagrantfile On line 45 is this file, there was a statement who indeed could cause the above error message

Easing into VIM

Image
The other night, I watched one of Luke Smith 's videos on VIM (embedded below) and got inspired. I've always been keyboard centric and been a fan of taking the time to learn keyboard shortcuts. And although I don't like the idea of abandoning my beautiful IDE for a text editor, I thought that adding some more macros to my life would only make it better. This is what I've played with thus far. Installing the VIM plugin into Visual Studio Code lets me play around with it in controlled doses and let me use my editor as normal in vanilla mode  when Vim comes to much. Vim mode is also supported in many of JetBrains' products , such as Rider . First things first - once you've installed the plugin, to toggle it off , use the command palette and search for toggle vim . And once you've done it that first time, it's right there in recently used . Now when we're operating in a safe environment, let's get some use out of the Vim macros! Things that caught

Renaming tags on GitHub

Image
Our build system had produced a set of tags which we'd like renamed. I first tried to Edit  the tag from the tags page in GitHub, but upon saving, it responded with a server error. This might be temporary and you can stop reading right now... or it might not be. Second off, I tried to follow this advice from Stack Overflow , but that didn't work out either. What I wound up doing was: Get tag names (I used the GitHub tags listing referenced above) Get commit id from git show tag name Delete old tag with git tag -d tag name Apply the new tag with git tag tag name commit id Delete old tags from origin with git push origin --delete tag name Upload to GitHub with git push --tags Oh, don't forget to let your colleagues know, so they can update their local copy of the repo with git pull --prune --tags

Renaming your git master branch to main

If you've gotten a certain urge to rename your git master branch to something else, here's how to rename it to main : Select branch git checkout master Rename it git branch -m master main Get latest from your repository  git fetch Remove upstream information git branch --unset-upstream Set a new upstream git branch -u origin/main Let HEAD point to your new branch git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main Hope this helps

Let's just ... build something!

Image
A couple of months back, I had a stroke of inspiration and produced a little video on YouTube to guide someone curious about - but new to - development to build and publish an app just to prove to themselves that they could. The basic premise was that  development doesn’t have to be hard and that we need more developers . It might seem hard to get started and here’s where I enter the scene! I’m here to help you build SOMETHING. Then, it’s up to you to play with that something - dig deeper into topics that interest you and propel yourself in the direction you want to go. I recorded the video in one go and then spent hours cutting out the biggest bloopers. In retrospect, listening to some of the comments I've gotten and also judging from my own video consumption, I should've split the video up into bite-sized segments, rather than having my viewers spend a consecutive 50 minutes with me. Looking at the statistics shows me, in fact, that interest seems to wane after less than th

On creativity, coding and reviews

Code reviews are important, however, the beauty of the code produced is skewed - it's more beautiful to the author of the pull request than the reviewer, leaving the creator in a potentially vulnerable state. As an author, to help you reduce any anxiety you might feel about the process, here are some thought experiments you can try: 1)  Perform the code review as a hand over, with the intention of the reviewer to make the code theirs. You've produced something that you want to give to the larger team. 2) You've produced something for some reason. You are now to present that reason and your solution so that - in the end two people have intricate knowledge of the code, instead of just yourself. As a reviewer, remember to be courteous and thanking your team member for their effort, before you ask for improvements. I've also found it useful to ask questions with regards to desired changes - "is it possible to ... "; "how come you've done ... considering .

It's not about Creation, it's about Mutation

When building systems, we've for decades now tried to lump properties together into cohesive bundles. We've created Customer objects, Order objects; arguing that "well - a system must support Customers, right?" Well, yes - and it's easy to get started that way. The issues with the Customer object, to make a concrete point, is that one model cannot possibly encompass all aspects of a real person or a company - a Customer - that we are trying to model. Furthermore, we often want to track people - potential  customers - before they've bought something (which is arguably the definition: once you buy something from someone or enter a contract that promises that you will, you're not really a customer, are you?). This is all to say, that whereas it's easy to create a Customer class early on in a greenfield project to encompass customers, your professional life will be must better spent if you focus on Mutation rather than Creation: Things that Change together

Test database operations with PowerShell

Microsoft SQL Server  comes pre-installed with with the SQLPS PowerShell module. Among its many CmdLets, you will find Invoke-SqlCmd . Using said CmdLet, you can both run queries and invoke scripts against new and existing databases. Let's pretend that you want to set up a database - BananaRama on your local machine. Just  Invoke-SqlCmd -ServerInstance "localhost" -Query "create database BananaRama" Now, ponder that you have a base script that sets up a schema and a table for a given database. What you will find, is that Invoke-SqlCmd supports Variables that can be injected in your script! Invoke-SqlCmd -ServerInstance "localhost" -Database "BananaRama" -InputFile "MyFancyScript.sql" -Variable "SchemaName=Customer1" In your SQL script you use placeholders inside $(DollarParentheses), e.g. $(SchemaName) : CREATE   SCHEMA  [$(SchemaName)] GO SET   ANSI_NULLS   ON GO SET   QUOTED_IDENTIFIER   ON GO CREATE   TABLE  [$(Schema

How to undo a whole range of commits ... and then fix that problem

1) Find the last commit that worked git log --oneline 2) Revert all commits between the one that worked and wherever you've managed to end up now git revert b32b3fe2e~HEAD --no-commit The no-commit parameter allows you to fix your stuff before ...  3) git add your new changes 4) git commit -m "OK, *this* time I'm *pretty* sure it works!" 5) git push

PowerShell, batching and JSON endpoints

Things I've learned about PowerShell lately Given an array of objects, if you want to batch them up to send only a few of them at a time to an endpoint accepting JSON, you can use Select-Object to skip/take a subset of the array and then use PowerShell's array notion to put the enumerable sequences back into arrays that ConvertTo-Json can accept as input:     $maxBatchSize = 10000     Do {         $batchSize = [Math]::Min($maxBatchSize, $ObjectArray.Length)         $batch = @($ObjectArray | Select-Object -First $batchSize)         $body = @{             Objects  = $batch             AnotherField  = $tagIds.ToArray()             YetAnotherField = @{ }         }         $body = $body | ConvertTo-Json         InvokeApiCall -Uri $url -Method PATCH -Body $body | Out-Null         $ObjectArray = $ObjectArray | Select-Object -Skip $batchSize     }     While ($ObjectArray.Length -ge $maxBatchSize) Without the array notion - @() - above, ConvertTo-Json would co