Author: claresudbery

Martin Fowler webinar, new Refactoring book

Martin Fowler webinar, new Refactoring book

These may well be the notiest notes I’ve ever published, but just in case they’re of any use to anyone… if nothing else they may whet your appetite for the new edition of Martin Fowler’s Refactoring book.

I confess I never read it first time round (not on purpose, just there are so many books in the world and so little time…), so I’m looking forward to reading it this time. It hasn’t come out yet in the UK but should be some time in the next few weeks. Mine is already on order [drums fingers impatiently].

So anyway, Martin did a webinar today on the topic of his new book, and here are my notes:

Refactoring should be done via small changes

  • v small semantics-preserving changes
  • So small they’re not worth doing on their own
  • String together small changes to make a big change

When adding new functionality:

  • Alternate between refactoring and adding functionality
  • Often it’s easier to add new functionality if you refactor first
  • Balance between adding new functionality and refactoring – it’s a matter of judgement

V1 of Martin’s Refactoring book vs v2

  • Some things that were included in the first book he decided not to include I the second
    • Eg Unidirectional vs bidirectional – not important
  • Some things he thought were too trivial for the first book, he has now changed his mind about and included
    • Eg moving statements within a function
  • Most notable changes = no longer centrally object-oriented
    • “Extract function” used throughout instead of extract method
    • One of the refactorings is around the choice between OO and non-OO
    • The most visible thing here is the choice of language (javascript)
    • But language is not necessarily relevant anyway
  • OO vs functional
    • He doesn’t see that as a huge shift
    • OO should still have functional elements – referentially transparent
    • They are overlapping paradigms, not distinct

Favourite refactorings?

  • “Split phase”
    • Hunk of computation which can sensibly be divided into two phases with a data structure communicating between them
    • Eg parsing – separate the tokenising out – deal with a series of tokens instead of a stream of text
    • But if you split a loop, what if you are introducing performance problems? See below…

Performance and refactoring

  • Split loop is something people often worry about because it will run the loop through twice
  • Most of the time it doesn’t matter – a push for clarity will not change the performance of the code
  • Most of the time by refactoring you open up an opportunity for performance improvements you would never have noticed otherwise
  • Then again you should run performance tests frequently
  • Not necessarily with every build, but every day or two
  • But most micro-changes have no impact on performance
  • You will only find real performance impact by performance testing

Recommendations for other books?

Refactoring architecture:

  • Always have to ask, how do you make the smallest possible change?
  • Eg extracting a data-intensive microservice from a larger system
  • Most of the moves are happening within the monolith BEFORE you start firing up the external system
  • Then you move stuff in really small pieces
  • Things that change for similar reasons should be together – you need to see the relationship between them

Branching / trunk-based development

  • Develop on a branch and merge at the end, with branch being long-lived – days, weeks or months
    • Still a really common pattern
  • But if something has been refactored, you don’t find out until you merge – this can blow up on you
    • It means you become scared to refactor! There’s a disincentive.
  • Continuous integration: Integrate with each other fully at regular intervals – at least once a day
  • Every day you receive everyone else’s code changes and push your own changes back
  • Removes the big painful merge problem – not saving up for a big horrible crunch
  • Adage of Apollo – it hurts if you do it more often (?)
    • Sorry, I wrote this down but I’ve since Googled it and I don’t really know what it’s about – I may have misheard!
  • Open source development:
    • Actually this CAN be a good place to use branches, because everyone working separately and you can’t guarantee all changes should be merged
  • People call it trunk-based development but “continuous integration” is a better name because that’s what it’s really about
  • People worry about continuous integration but it’s less painful than they think
    • If you do integration every day it becomes easier and less painful until you stop even noticing

Responsibility

  • Keep code base in healthy state
  • If not you are stealing from colleagues, clients and employers!
  • But no point saying you should do it for moral reasons, that won’t motivate people to do it
  • It’s economic: Want to get more changes out more quickly
  • It’s professional: We’re being paid to produce features rapidly
  • It’s not up to managers or business: They don’t know how to keep code healthy – that’s what they pay us to do

Refactoring and design patterns – are they incompatible?

  • With a lot of patterns, you shouldn’t introduce them right away cos they’re not appropriate and you don’t require the full strength of them yet, particularly the more complicated ones
  • Introduce patterns as a result of refactoring: Refactor towards them
  • This was recognised by the original Design Patterns authors (Gamma, Helm, Johnson, Vlissides)
  • Also Josh Kerievsky: Refactoring to Patterns

Code smells

  • Code smell of the week!
    • “This week we will look at long methods” – whenever we find them we try to refactor them

When not to refactor!

  • Code that is never touched
    • Sitting behind an API, working quite happily, doesn’t need to change – doesn’t matter if it’s a mess!
  • Don’t clean code all in one go – just a little bit more every time you go in
    • Over time that will concentrate your efforts where they are most needed – ie areas modified most frequently

Refactor as a step in the red-green-refactor cycle

  • You should only refactor when tests are green
  • Sometimes that means you have to remove a failing test, refactor, then put the failing test back in again
  • Ralph Johnson, John Brant, Don Roberts wrote the first Smalltalk refactoring book (A refactoring tool for smalltalk?)

If you don’t have tests you can’t refactor?

  • “Probably safe” refactorings? Interesting route to go? Not a great thing for most people to focus on, requires a lot of expertise
  • For most people you should have tests as well – after all, how do you know whether you’re breaking what’s currently there?

Final takeaway:

  • Small steps, commit frequently.
  • Then you can always roll back.
Getting Started with .Net Core, ASP and WebAPI

Getting Started with .Net Core, ASP and WebAPI

I followed this tutorial, which is very good: https://docs.microsoft.com/en-us/aspnet/core/tutorials/web-api-vsc?view=aspnetcore-2.1

There were some gotchas though, so (as always) I made notes:

  • Whenever you add new code you have to stop running and rebuild before you can send successful requests.
  • When you do a POST, the port number is 5001 or 5000: It’s whatever you’re using in the browser for GET requests
  • When you add the Update method, you have to send another POST to create a new Todo item before you can update it. The url is the location field from the response of the POST.
  • When you add the Delete method, use the GET request in the browser to find the Ids of existing items so you know what you can delete. The url is the same as the Update url, with appropriate Id added on. Use the GET request to check whether deletes have worked. Use the POST to add elements you can then delete.
  • When you add a new database context you need to update the dependency injection stuff in Startup.cs and you need to make sure your POCO class has an Id property.

See also the following two posts:

Converting a .Net Standard console app into a .Net Core console app

Converting a .Net Standard console app into a .Net Core console app

If you have a simple .Net console app and you’d like to convert it into a .Net Core app so that you can run it from the command line on any platform (as long as you install .Net Core), here’s what to do:

  • Remove the following files and folders from your project:
    • Bin folder
    • Obj folder
    • Packages folder
    • Properties / Assemblyinfo.cs
    • config
  • Create a new temp folder and run this command in that folder: dotnet new console
    • Take the csproj file created by that command and use it to replace the csproj file in your original project (using the name of the original csproj file).
    • !! If your original csproj file was in a nested folder, the new csproj file will have to be in the root.
      • But your program.cs file can stay where it was.
      • Or you can create a *.sln folder at the root level and add references to any nested csproj files.
        • To create a sln file: dotnet new sln
        • To add a csproj file (in a nested tests folder) to your sln file: dotnet sln add .\tests\tests.csproj
    • Command line: dotnet restore
    • Now you can build and run the new project from the command line: dotnet run
  • Check the old project for packages to include:
    • Look in packages.config
    • For instance, if you see a line that looks like this:
      • <package id=”NUnit” version=”3.11.0″ targetFramework=”net452″ />
    • …you need to run this on the command line: dotnet add package nunit -v 3.11.0
    • !!! If NUnit is one of the packages, you need to do some extra actions – see Adding NUnit tests to a .Net Core console app.
  • Gotchas:
    • You can’t build and run a console app in Visual Studio if the code is in Google Drive. You’ll get a very generic uninformative error – “Unable to start program … refresh the process list”.
    • If you try to add the NUnit package manually, you may get errors. Follow the actions in Adding NUnit tests to a .Net Core console app to fix.
      • Otherwise you may get the following errors:
      • 1) “Unable to find tests” Fix this with the following command (check version – this was Oct 2018): dotnet add package Microsoft.NET.Test.Sdk -v 15.7.2
      • 2) “Program has more than one entry point defined”. This is fixed by adding the following sub-element to a <PropertyGroup> element in your csproj file:
      • 3) “No test is available”. Fix this by adding the NUnit3TestAdapter package (at time of writing – Oct 2018 – this was version 3.10.0).

See also the following post:

Adding NUnit tests to a .Net Core console app

Adding NUnit tests to a .Net Core console app

(I’ve learnt a lot more since I originally wrote this (for instance, how to debug your tests), so this is an updated version).

This weekend I was part of a team that took part in the annual Hack Manchester hackathon (and we won Best in Show! Yay!). We used .Net Core for our back end code, and we got stuck in the middle of the night trying to add tests to our solution. It turned out the solution was pretty simple, so I’m documenting it here.

Intro

  • To get started with a vanilla ASP.Net Core app + WebAPI: Getting Started with .Net Core, ASP and WebAPI
  • There are two versions below. The one you choose will probably depend on things like deployment pipelines. If you are doing anything other than a quick hack, Version 1 is probably better.
  • To be perfectly honest, the only reason I moved from one to another was because I (mistakenly) thought I couldn’t debug the tests or run them in an IDE unless they were in a separate project. It turned out that the only thing preventing me was that I hadn’t installed the relevant extension (see “Debug the tests / run the tests from an IDE” below).
  • Version 1:
    • Place tests in a separate project/folder
  • Version 2:
    • Keep all the tests in same folder/project as the source. This is quicker / simpler.

Version 1 – keep tests in separate folder/project

  • This version places tests in a separate project / folder. This is probably better if you want a deployment pipeline.
  • NB If your source is currently in your root folder, then you’ll need to move it into a separate folder (eg a src folder). This is easy:
    • Close down any IDEs you have running
    • Create a new src folder
    • If you don’t have a *.sln file, create one by opening the project in Visual Studio or running the command: dotnet new sln
    • Edit your solution file so that your csproj is prefixed by its new folder name
      • For me that meant changing ” TimeTravelApi.csproj” to “src/TimeTravelApi.csproj”
    • Move everything except *.sln into your new src folder
  • Create a separate tests folder in your root folder
  • Navigate to your new tests folder
  • Create the nunit project:
    • There are two ways of doing this.
      • The first way is to run this command: dotnet new “NUnit 3 Test Project”
      • The second way is to manually add three new packages: NUnit, Microsoft.NET.Test.Sdk and NUnit3TestAdapter – see below for how to do this manually.
  • Add a reference to your source project:
    • Run this command (replace “YourProject” with your project name): dotnet add reference ../src/YourProject.csproj
    • If you get an error about “incompatible targeted frameworks” then:
      • Go into your tests.csproj and change the .Net version from 2.0 to 2.1 like this: <TargetFramework>netcoreapp2.1</TargetFramework>
      • Run this command to upgrade the nunit version: dotnet add package nunit -v 3.11.0
      • ! This works in Oct 2018, but it might be different in the future!
    • Add your new tests project to the solution:
      • Navigate back up to your root folder
      • Command: dotnet sln add ./tests/tests.csproj
    • Write and run some tests (see “Write and run some tests” below)

Version 2 – keep tests in same folder/project as source

  • This version keeps all the tests in same folder/project as the source. This is quicker / simpler if you are trying to keep things small and simple.
  • Add the necessary packages:
    • You can run the separate package commands on the command line (see below), but you’re probably better off using the dedicated nunit command.
    • Dedicated nunit command:
      • Command line: dotnet new “NUnit 3 Test Project”
    • Separate commands for each package (check versions – this was written Oct 2018):
      • Command line: dotnet add package nunit -v 3.11.0
      • Command line: dotnet add package Microsoft.NET.Test.Sdk -v 15.7.2
      • Command line: dotnet add package NUnit3TestAdapter -v 3.10.0
    • Add the following sub-element to a <PropertyGroup> element in your csproj file:
      • This: <GenerateProgramFile>false</GenerateProgramFile>
    • Write and run some tests (see “Write and run some tests” below)

Write and run some tests

  • Write some tests
    • At the bottom of this post is a skeleton you can use – it’s all you need for a functioning test
    • Run the tests from the command line: dotnet test -v normal
    • Debug the tests / run the tests from an IDE:
      • In Visual Studio Code:
        • Install the .Net Core Test Explorer extension (from Preferences | Extensions)
          • Mac: in the Code menu
          • Windows: in the File menu
        • Now you will see “Run test” and “Debug test” options above every test.
      • In Visual Studio (Windows):
        • Install the NUnit test adaptor:
          • Tools | Extensions and Updates
          • Select online on the left
          • Search for NUnit
          • Find NUnit 3 Test Adaptor
          • Click Download
          • Close down Visual Studio AND Visual Studio Code
          • You will get a VSIX installer dialog
        • Run the tests:
          • The Test menu gives you options for running tests
          • Then Test | Windows | Test explorer will show you the results
        • Debug tests:
          • Test | Windows | Test explorer: right-click on a test and choose Debug selected tests

A skeleton NUnit test:

using NUnit.Framework;
namespace KiwilandRouteApplication.Tests
{
  [TestFixture]
  public class DummyTests
  {
    [Test]
    public void DemoTest()
    {
      Assert.True(true);
    }
  }
}
Hack Manchester 2018 – The Challenges

Hack Manchester 2018 – The Challenges

I couldn’t find anywhere all the Hack Manchester 2018 challenges / prizes were listed together, so I’m putting them all on one page for easy comparison.

! I’m not sure if they’re all there yet – there might be more to come, so keep an eye on the Hack Manchester site (scroll down to the “THE CHALLENGES” – yellow section just before the schedule).

Follow the links below to find out about the sponsors and see more detail / explanation about the challenges:

WebApp UKBest in Show. (Our team came second for Best in Show last year. Just sayin’.)

MediaBurst: “The most bizarre use of ClockworkSMS!.”

Dunnhumby: “use data to make the consumer experience… less than optimal.

Centre For Biological Timing: “make technology work for our body clocks rather than against them … hack your body clock!

Avecto: “create a digital solution to help protect or inform friends and family of the issues around Cyber Security.

AND Digital: “Can clever tech help turn passenger misery into passenger delight?

GCHQ: “think locally: utilise the fantastic open data sources available about Greater Manchester to improve the safety of the general public.

Screen Shot 2018-10-12 at 14.07.51

Feelin’ Groovy (“Unable to resolve class” or “Configure Groovy SDK”)

Feelin’ Groovy (“Unable to resolve class” or “Configure Groovy SDK”)

I was working with some Groovy scripts in IntelliJ today – a first for me. I came up against a couple of simple getting-started issues… I’m just making notes about them here. There are notes here on two errors I came across: “Unable to resolve class” and “Configure Groovy SDK”.

  1. “Configure Groovy SDK”:
  • On command line:
    • This: brew install groovy
    • Then to run a script: groovy path/to/file.groovy
  • In IntelliJ:
    • Install the groovy plugin
    • Open the folder containing the scripts
    • When it says “Groovy SDK is not configured for module ‘my-module’” or “Configure Groovy SDK”
      • Click the link with the “Configure Groovy SDK” message (top right in IntelliJ)
      • Click Create
      • (Find your Groovy installation:
        • On the command line: brew ls groovy
        • This will give you something like this: /usr/local/Cellar/groovy/2.5.2/bin/groovy
        • Then you need to find your libexec folder – probably at same level as bin folder – in my case it’s here: /usr/local/Cellar/groovy/2.5.2/libexec)
      • Find the libexec folder, select it and click open
      • More here: https://stackoverflow.com/questions/46123890/configuring-groovy-sdk-within-intellij-idea
    • Now you can run a Groovy script by clicking the big green Play button, top right
    • To pass parameters into a script:
      • Top right, click the little down arrow next to the name of the script
      • Click Edit configurations
      • Fill in Program arguments

 

2. “Unable to resolve class” 

  • This can happen when your classes are in a package and you try to run your script from the command line.
  • It will start in the folder the class is in, then from there it will look for a further folder structure – eg if your package is clare.is.cool then it will look for the folder structure clare/is/cool from the path of the groovy script.
  • The solution is to set the classpath on the command line when running the script, and start further back in the directory tree.
    • For instance if your class is here: c:\overall\path\clare\is\cool\MyScript.groovy
    • Then you run it like this: groovy -cp c:\overall\path c:\overall\path\clare\is\cool\MyScript.groovy
    • (or if you have already navigated to c:\overall\path\clare\is\cool, you can just run groovy -cp c:\overall\path MyScript.groovy)

More here: https://stackoverflow.com/questions/45072923/groovy-unable-to-resolve-class

Another Interesting Conference Numbers Problem

Another Interesting Conference Numbers Problem

The other day I posted this problem.

In the process of chatting about it, an associated mathematics problem came up, about permutations and probabilities.

To remind you of the basic problem: We have 450 conference attendees. We have one day of workshops. There are five sessions throughout the day, and five workshops to attend. We want every attendee to attend every workshop. The workshops are being repeated throughout the day: In every session, there are 10 rooms available. There are five workshops, and each workshop is duplicated. So for instance, workshop 1 will be run in rooms A and B, workshop 2 in rooms C and D, etc. They are repeated throughout the day, so one attendee might do them in the order 15423, and another might do 42315.

There will be 45 people in each workshop. The nub of the problem is that the organisers want as much cross-pollenation as possible. People do not get to choose what order they do the workshops: they are told which room to be in at what time. The organisers would like each attendee to meet as many new people as possible in every single session.

So here’s the maths question: What is the minimum average number of repeat people that attendees have to meet in each session? By “repeat people” I mean “people they have already attended a previous session with.”

There is one extra constraint: There is one group of 30 people (labelled “FRIENDS” in the spreadsheet below) that have to be kept together in every session. So they only get 15 people in every session that they may not have met before, ie for them the min value of Repeat People is 30 in every session. This also has an impact on all the other people in the other sessions.

However this is still an interesting problem even without the extra 30-people constraint.

So in session one, Repeat People = 0. In every one of the workshops in session 1, attendees are in a brand new group of people that they have never attended this conference with before.

So what is the minimum average value of Repeat People for session 2? I’m specifying average, because it would be possible to keep things pure for at least one attendee, where they meet 44 new people in every single session. But that would have an adverse effect on everyone else. So I’m aiming for everyone to have roughly the same number of Repeat People per workshop.

I have two theories, one of which I can prove:

  1. Apart from in Session 1, the average Repeat People is definitely greater than zero. You can’t avoid meeting attendees more than once (if you’re spreading the load evenly) (I can prove this one).
  2. The average number of Repeat People will get gradually higher throughout the day. The first solution I came up with maintains a constant number for Repeat People after session 1, but it’s non-optimal (I think).

Here is a way of visualising the problem:

Gina-workshop-empty-2

I’ll be very interested to hear any solutions!

A Solution to the Interesting Conference Numbers Problem

A Solution to the Interesting Conference Numbers Problem

The problem is described here. You could approach the problem as a coding kata, which I’d love to do at some point – I didn’t have the time on this occasion. I ended up just solving it using pen and paper.

My solution is below. It won’t be the only solution, there are probably better ones out there that rely more on randomisation and less on patterns (or just use better patterns).

Don’t scroll down if you want to have a go at it yourself first!

 

 

 

So, I found a solution which works pretty well. I’m pretty pleased with it, and it’s nice and simple and neat.

The participants are split into groups of 15. The FRIENDS are in two groups of 15, both marked “FRIENDS” in the spreadsheet below. All the other groups are non-FRIENDS (well they might be friends, who knows? But they still don’t get to stay together – we’re mean like that).

It does mean that the people move in groups of 15, and they will stay in those groups. Not that they will necessarily know it. Because of the numbers, no matter what you do, they will keep encountering some people repeatedly (the maths of this is a separate problem which I’ve blogged about here). If you shuffle the list and assign the non-FRIENDS to 28 groups of 15, hopefully they will already be mixed up with people they don’t know, so they needn’t be aware that they have been grouped. I’ve labelled the groups B1 to O1 and B2 to O2.

What it does mean is that each group of 15 never encounters another group of 15 twice – they meet a different two groups in every session. So everybody meets 30 new people in every session (I haven’t actually proved this but I’m pretty confident).

(Since I came up with this, I’ve realised I can improve it quite a lot so that people don’t have to stay with exactly the same 15 people – scroll down to the bottom to see this improvement).

So, there are three groups in every session, like this (this is my actual solution):

Gina-Workshop-2

Here’s how I did it:

First, split the non-FRIENDS people into two halves, 225 in each half. The first half has groups B1 to O1, and the second group has B2 to O2.

For now, we will also split the FRIENDS into two groups, A1 and A2 (this was my “Aha” moment, all made possible because of the fact that you have duplicate workshops in each session).

So for each half, we have letters A to O. For the first session, we just spread them across the 5 workshops: ABC in the workshop 1, DEF in workshop 2… etc.

For the second session, the first group in each triplet just shuffles along to the next workshop. So A is now in workshop 2, D is in workshop 3, etc.

We keep doing this all the way down the sessions, for the first group in each triplet.

For the second group in each triplet (B, E, H, K and N), instead of shuffling them on by 1, we shuffle them 2 workshops along. So, B was in workshop 1 in session 1, then we add 2 so they are workshop 3 for session 2, then add 2 again so they are in workshop 5 for session 3, keep going (wrapping around) and they are in workshop 2 for session 4 and workshop 4 for session 5. Do this for all the second groups (B, E, H, K and N).

For the third group in each triplet (C, F, I, L, O), add 3 on each time. So group C has the following workshops: 1, then 4, then 2, then 5, then 3.

Do this for all of those third groups.

This is what you get:

Gina-workshop-diag

Now, at this point you have a problem: Your FRIENDS group have been split into two groups of 15. But ooh! Look! You did the same thing for A1 to O1 as you did for A2 to O2!

A1 and A2 are always in the same workshops at the same time. So you can move A2 into the same workshop as A1, and swap another group out into the spot left blank by A2.

I then renamed both A1 and A2 to “FRIENDS”, and that’s how I arrived at the spreadsheet pasted above.

POST SCRIPT (also see separate maths problem here):

Since I came up with this, I’ve realised I can improve it quite a lot so that people don’t have to stay with exactly the same 15 people:

The “FRIENDS” group mess it up a bit, but in most cases you’ll have parallel groups moving independently in duplicate workshops, eg when group C1 is doing workshop 3, group C2 will be doing the other duplicate of workshop 3.

Well… If each group of 15 was split into two sub groups of 7 and 8, then they could shuffle around and meet each other. Also this could be done dynamically.

So, for instance, you have C1a (7 people), C1b (8 people), C2a (7 people) and C2b (8 people).

In session 2, swap C1b and C2b so now only 7 (or 8) people stay together. Do the same with all groups (except those affected by the “FRIENDS” group).

In session 3, put C1a with C2a and C2b with C2b. This adds up to 14 and 16, so somebody will have to switch sub groups. In sessions 4 and 5 you could split them again, but this time randomly. As long as all the Cs are doing the same workshops, you can split them how you like. Ultimately they will all meet each other so they’ll still have repetition with 15 people overall, but it won’t be the same 15 people in every workshop. And they’ll still get 30 brand new people in every workshop.