Steve Fenton https://www.stevefenton.co.uk Sat, 28 Mar 2020 22:45:43 +0000 en-GB hourly 1 https://wordpress.org/?v=5.3.2 https://www.stevefenton.co.uk/wp-content/uploads/2017/06/cropped-wheel-32x32.png Steve Fenton https://www.stevefenton.co.uk 32 32 140638488 .NET Core Entity Framework Migrations https://www.stevefenton.co.uk/2020/03/net-core-entity-framework-migrations/ Sat, 28 Mar 2020 21:37:15 +0000 https://www.stevefenton.co.uk/?p=8010 When you don’t want to script out your own database, Entity Framework Core has your back. When you change your database context or the models it uses, you can use a couple of commands to create and update your database to keep it in sync with your model. These examples run in the Package Manager […]

The journal .NET Core Entity Framework Migrations was first published at Steve Fenton.

]]>
When you don’t want to script out your own database, Entity Framework Core has your back. When you change your database context or the models it uses, you can use a couple of commands to create and update your database to keep it in sync with your model. These examples run in the Package Manager console (and if you have trouble running them, check the end of this post).

Your package manager console can be found in Visual Studio using Tools -> NuGet Package Manager -> Package Manager Console.

Package Manager Location

What Will Be Included

To make it into a migration, you need a model class to represent the table. You also need the property on the database context class.

Example model.

[Table("Content")]
public class Content
    : IDataModel
{
    public long Id { get; set; }

    public string Title { get; set; }

    public string CreatedBy { get; set; }
}

Example database context, with a DbSet of the model type.

public class ApplicationDbContext
    : IdentityDbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    public DbSet<Content> Contents { get; set; }
}

Create the Initial Version

To create the first migration file, run the dotnet ef migrations add command, and name the migration “InitialCreate”:

dotnet ef migrations add InitialCreate

You will find some new files in your project, named using a date-stamp and the name of your version. For example 20200328212129_InitialCreate.cs. You can view the file and see what it does, it will all look pretty familiar. There is an “Up” method and a “Down” method. This allows you to apply or reverse the migration.

To apply all migrations and get the database into the up-to-date state, run:

PM> dotnet ef database update
Done.

Applying Changes

Each time you have changes you want to push into the database, you run the ef migrations add command with an appropriate name. In the example below, the “Container” table is going to be added…

PM> dotnet ef migrations add AddContainers
Done. To undo this action, use 'ef migrations remove'

And you make it happen using the same command as before:

PM> dotnet ef database update
Done.

The common pattern is ef migrations add [name] -> ef database update.

Undo! Removing a Migration

If you made a mistake in adding a migration, you can remove it using this command:

PM> dotnet ef migrations remove
Removing migration '20200328212010_AddContainers'.
Reverting model snapshot.
Done.

Troubleshooting

The most likely error you’ll encounter is “Could not execute because the specified command or file was not found”.

When this happens, you just need to add the following to your .csproj file:

  <ItemGroup>
    <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.3" />
  </ItemGroup>

The journal .NET Core Entity Framework Migrations was first published at Steve Fenton.

]]>
8010
Removing Special Characters and Diacritic Marks in C# https://www.stevefenton.co.uk/2020/03/removing-special-characters-and-diacritic-marks-in-c/ Thu, 26 Mar 2020 13:18:16 +0000 https://www.stevefenton.co.uk/?p=7989 I did this trick in JavaScript to remove diacritic marks a while back and the need to perform a similar transformation in C# came up this week. The following method simplifies strings such as “façade” into simple string like “façade”. private static string Simplify(string input) { string normalizedString = input.Normalize(NormalizationForm.FormD); StringBuilder stringBuilder = new StringBuilder(); […]

The journal Removing Special Characters and Diacritic Marks in C# was first published at Steve Fenton.

]]>
I did this trick in JavaScript to remove diacritic marks a while back and the need to perform a similar transformation in C# came up this week.

The following method simplifies strings such as “façade” into simple string like “façade”.

private static string Simplify(string input) 
{
    string normalizedString = input.Normalize(NormalizationForm.FormD);
  
    StringBuilder stringBuilder = new StringBuilder();

    foreach (char c in normalizedString)
    {
        UnicodeCategory unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
      
        if (unicodeCategory != UnicodeCategory.NonSpacingMark)
        {
            stringBuilder.Append(c);
        }
    }

    return stringBuilder.ToString().Normalize(NormalizationForm.FormC);
}

The journal Removing Special Characters and Diacritic Marks in C# was first published at Steve Fenton.

]]>
7989
Microsoft Teams – What Microsoft Taught Me This Week https://www.stevefenton.co.uk/2020/03/microsoft-teams-what-microsoft-taught-me-this-week/ Tue, 17 Mar 2020 18:07:56 +0000 https://www.stevefenton.co.uk/?p=7890 After my day job this week I’m attending the Virtual MVP Summit that Microsoft are running. The event is normally held in-person, but due to the current events it was switched to 100% online with attendees and presenters all joining sessions from home using Microsoft Teams. When you stick 150 people into an online video […]

The journal Microsoft Teams – What Microsoft Taught Me This Week was first published at Steve Fenton.

]]>
After my day job this week I’m attending the Virtual MVP Summit that Microsoft are running. The event is normally held in-person, but due to the current events it was switched to 100% online with attendees and presenters all joining sessions from home using Microsoft Teams. When you stick 150 people into an online video call, you get to test the edges of technology, but there are some neat tricks that I have learned by watching the experts in action.

There are differences between making a one-to-one call, a team call, and a massive call such as the MVP Summit sessions that spanned the globe with loads of attendees. You’ll hopefully be able to judge when a piece of advice applies.

Measure Time in Minutes

When booking a quick meeting, define it as a quick meeting. Old work habits make people book 30 minute chunks, but try booking a ten minute call instead… stay focussed and make it end on time. Building this habit makes a clear statement that calls do not need to be 30 minutes, or an hour. We all got stuff to do!

Start Early

If you own the meeting or call, start it early. For the MVP Summit, calls were opened up at least thirty-minutes before the session with a PowerPoint title slide up on screen share. This means people can join before the start time and confirm they are in the right place. This also allows the session to start on time as people are already “in their seats” when the clock ticks over into meeting time!

Join on Mute

This is one that Teams will suggest for you once there are a few people already on the call, but I have now installed this as my default. When you join any call, join on mute. It’s the online equivalent of slinking through the doors and slipping into one of the seats on the back row. It doesn’t disturb the presenters or audience.

Use Video

Yeah, I know. Almost nothing in the world is as horrible as that little mirror-box that reflects back your face from the worst possible angle. However, the quality of your interaction as human beings is improved beyond measure by being able to see the other humans on the call. We all look the same on these webcams so we just need to suck it up and before we know it, we’ll be over the novelty and we can get on with the job. This doesn’t apply in calls with a hundred users!

Hide Balloons

You have probably seen the team ads with the chap joining nonchalantly from outside a hipster café. His team get distracted by balloons in the background, so he used the background-blur feature to reduce the distractions. The real reason this feature exists is because the reflective surfaces behind you will show embarrassing images of people who think they aren’t in front of the camera. Like the crew in this Sex and the City episode…

Crew Visible in TV Reflection

You can easily toggle this on and off using Ctrl + Shift + P from anywhere in the team window. (Kudos Lee Englestone).

Push to Talk

Because we are all working from home right now, there is going to be background noise. Although I have family in the house, the main background noise is my cat drinking from a tap. He likes it fresh. Because of this, I stay on mute and use the space bar to drop in and out of audio. If you hit the mute button, the space bar will toggle it, making Teams work like a walkie-talkie. Roger and out.

You can also use the keyboard shortcut Ctrl + Shift + M to toggle the microphone from anywhere in the team window. (Kudos Lee Englestone).

Screen Casting

Obviously you want to avoid embarrassing toaster messages while presenting, so close down all your other messaging apps. Don’t chance it! If you are going to be live-sharing a single app, make sure you just share that single app. It stops any information leaking. If you are going to be switching between two or more apps, clean up a second monitor (remove all non-presentable apps, task bar, etc) and share the whole monitor. Having to stop sharing app one, then start sharing app two, then repeating… ain’t fun in a live call.

Use Chat

Meeting chat allows you to drop notes, questions, and links into a chat associated with the call. This can be seen by everyone and is a good way to make a note without interrupting the people speaking, or to share something that you would otherwise spell out loud, slowly, several times. When you are on a massive call, you would think co-ordinating who is speaking would be tough, but it’s not… nobody speaks. We are all sat trembling with terror at the thought we might not be muted, so we say nothing. Chat saves us from this fear.

Pair-Presenting

If you are running a presentation, meeting chat will be closed by default and it won’t pop up alerts; because it would distract you from your flow. To solve this, having a second presenter who monitors the meeting chat and curates the questions to pose to the presenter at a good time.

Tag Your Questions

When you are asking a question in meeting chat, start it with “Question:”. It helps the presenters spot questions amongst all the comments and other noise. When there are over a hundred people on a call this helps a great deal.

Your Tips

Do you have any tips for team calls that you want to share? Let me know!

The journal Microsoft Teams – What Microsoft Taught Me This Week was first published at Steve Fenton.

]]>
7890
Easy API Testing with REST Client Extension for Visual Studio Code https://www.stevefenton.co.uk/2020/03/easy-api-testing-with-rest-client-extension-for-visual-studio-code/ Mon, 16 Mar 2020 19:02:17 +0000 https://www.stevefenton.co.uk/?p=7881 Visual Studio Code is becoming my go-to tool for automating stuff. It’s lightweight, it’s a joy to use, and it seems to be able to do pretty much everything ever thanks to a vibrant plugin marketplace. If you test APIs, you might be using an API testing tool of some kind, such as Postman. With […]

The journal Easy API Testing with REST Client Extension for Visual Studio Code was first published at Steve Fenton.

]]>
Visual Studio Code is becoming my go-to tool for automating stuff. It’s lightweight, it’s a joy to use, and it seems to be able to do pretty much everything ever thanks to a vibrant plugin marketplace. If you test APIs, you might be using an API testing tool of some kind, such as Postman. With Visual Studio Code, though, you can do some really nice API testing with simple text files using the REST Client extension.

Once you install the REST Client Extension, you just open a file (you can call it sample.http) and type a simple request:

GET https://www.example.com/ HTTP 1.1

The extension will add a “Send Request” option above the request. When you click this, it will send the request and show you the response in another editor pane.

VSCode REST Client

This is super-simple. The file is readable and can easily be shared with your team. You can also save the full response, or the response body into a file.

More Complex Example

Let’s look at a more complex example so we can see variables, extracting variables from the response, and chained requests.

Variables can be declared using @variable = value. You can define these and re-use them throughout your file.

You can also pull values from the responses to store in a variable, as long as you name the request. You name the request using the special comment # @name = myrequest before the request. You can then use this name to read back values, for example @token = {{myrequest.response.body.access_token}}.

Finally, you can chain requests by separating them with ###.

Let’s put it all together in order to get an auth token from an API and use it to query some values.

@user = SuperTed
@password = SecretMagicWord
@pageSize = 10

# @name login
POST https://www.example.com/api/cosmicdust/oauth/token HTTP/1.1
content-type: application/x-www-form-urlencoded
Authorization: Basic apiuser:apipassword

grant_type=password
&username={{user}}
&password={{password}}

@token = {{login.response.body.access_token}}

###

GET https://www.example.com/api/cosmicdust/episodes?limit={{pageSize}}&page=1 HTTP/1.1
Authorization: Bearer {{token}}

We start off creating some variables for the values that will change frequently. That way they are at the top of the file and we won’t accidentally ruin a request with a bad edit.

Then we name our login request, using # @name login.

We make our POST to the login API, padding content-type and authorization headers. The body of the request follows (and should match the content type you said you would give).

Then we pull the access token out of the response and store it in a variable.

The ### separates our requests, then we make the next request using the token we kept hold of. The UI will underline this when you haven’t yet obtained an access token to remind you to get it first.

Summary

The best thing about the REST Client extension is that you can easily see all of the request configuration and you can share it (without the sensitive parts) easily with your team, for example via source control.

Go and grab the extension from the marketplace.

The journal Easy API Testing with REST Client Extension for Visual Studio Code was first published at Steve Fenton.

]]>
7881
The Universal Truth of Collections https://www.stevefenton.co.uk/2020/03/the-universal-truth-of-collections/ Thu, 12 Mar 2020 20:29:00 +0000 https://www.stevefenton.co.uk/?p=7842 The BBC has been running a series called Secrets of the Museum, which features a behind the scenes look at the Victoria and Albert Museum in London. The longer I watched this fascinating show, the more it revealed one of the universal truths of humanity; it’s propensity to collect things and it’s inability to limit […]

The journal The Universal Truth of Collections was first published at Steve Fenton.

]]>
The BBC has been running a series called Secrets of the Museum, which features a behind the scenes look at the Victoria and Albert Museum in London. The longer I watched this fascinating show, the more it revealed one of the universal truths of humanity; it’s propensity to collect things and it’s inability to limit such collections to a sustainable size.

In the case of the V&A, the vast collection is a portal into the past. The items are each uniquely fascinating, but there is a common theme that emerges from the rows upon rows of historic objects; they simply cannot be kept in perfect condition. The collection has increased beyond a size the team of experts could possibly hope to preserve. Some of the items may not have been seen by the current team. Although many of the objects that come out of storage can be carefully restored, some of the items will decay and be lost forever. It’s inevitable that this will happen with a collection at this scale.

Now, I work in the software industry and the applicability of this problem to software products is striking. At some point in the lifecycle of a software product, the collection of features reaches the tipping point that means it can no longer be sustained. Some features will be “brought out of storage” and then carefully restored into working condition, but some will never be seen by the current team of experts and will inevitably decay and be lost forever.

Unless we limit the size of the collection, decay cannot be avoided.

So, how do we impose some form of limit? Firstly, you need to be acutely aware of your long-term investment in each and every feature you develop. To do this, you need to independently measure “collecting time” and “restoration time”. This will tell you the current ratio between these two competing demands, but more importantly you’ll discover the trajectory of restoration time.

Using this information, you can design how you will manage the growing restoration burden. There are many strategies in common use, from scaling to outsourcing, but the most effective technique is to avoid adding to the collection and retire features with low use. You can only do this if you know which features are seldom used, so you need to measure feature usage.

You may be tempted to keep a feature that isn’t in common use because you don’t need to “restore” it… but no feature is ever complete. Customers, competitors, and law-makers will make sure of that. That old feature that nobody in your current team has ever seen could be hit by a legislative change that means the expensive restoration project you hoped to avoid eats your roadmap.

Unlike the V&A, you can’t expect some wealthy benefactor to rescue you from a costly maintenance task. Only you can manage this problem and you have to start early.

The journal The Universal Truth of Collections was first published at Steve Fenton.

]]>
7842
Import IIS Log Files to SQL Server with Web Log Importer https://www.stevefenton.co.uk/2020/03/import-iis-log-files-to-sql-server-with-web-log-importer/ Tue, 10 Mar 2020 16:52:01 +0000 https://www.stevefenton.co.uk/?p=7806 In the past I have used Log Parser Studio to run SQL style queries against IIS logs, but it can take a fair bit of time to do this. Sometimes you just want to run a quick SQL query against the log data that IIS has collected. SQL Server is a super quick way of […]

The journal Import IIS Log Files to SQL Server with Web Log Importer was first published at Steve Fenton.

]]>
In the past I have used Log Parser Studio to run SQL style queries against IIS logs, but it can take a fair bit of time to do this. Sometimes you just want to run a quick SQL query against the log data that IIS has collected. SQL Server is a super quick way of running queries to discover what is going on in your log files, but you need to import your IIS log files first to be able to take advantage of the speed and familiarity of your SQL queries.

This calls for a quick .net Core Console App, which I’ve written and placed on GitHub, called Web Log Importer.

How Does it Work

Web Log Importer will take a bunch of files that you place in a folder and prepare them for import. There are a few lines that need to be dropped out and we want to combine them into a single file to pass to SQL.

Once the file is ready, we use SQL bulk import to fill a table with the log entries.

All of this is done by running the console app.

How Fast / Efficient Is It

Using a sample from a web server with one day of traffic, the whole process took under eleven seconds. This imported 274,434 log entries from 19 files, approximately 90 MB of source data.

Elapsed time 10875 ms

During a debug run, the memory and CPU used by the application is low/stable.

Web Log Importer Diagnostics

Because the data is created from scratch during the process, SQL index fragmentation will always be zero.

DatabaseName    TableName           IndexName    IndexType          AverageFragmentationPercent
WebLogs         [dbo].[LogEntry]    cci          CLUSTERED INDEX    0

Running SQL Queries Over IIS Log Files

Now the data has been imported, you can just run plain-old, super-quick, lovely SQL queries to see what’s going on.

Here’s a complete example that creates a league table of client IP addresses ranked by number of log entries. It filters the logs by date, and time.

SELECT
    [c_ip],
    COUNT(1)
FROM
    LogEntry
WHERE
    [date] = '2020-03-10'
AND
    [time] BETWEEN '12:20' AND '12:40'
GROUP BY
    [c_ip]
ORDER BY
    COUNT(1) DESC

As the date and time are split between different columns, you can query them independently… i.e. you can look across the 4pm to 5pm time without choosing a date to see early-evening trends across multiple dates, and you can use “date =” to select a single day (which you can’t do when there is a time component to the date).

Column Names

Because you already know IIS log files, and you already know SQL, I’ve tried not to fiddle too much with things.

The column names reflect the headers within standard IIS log files, although I’ve incorporated the X-Forwarded-For header, which is a pretty common addition these days.

Where a header contains a hyphen - it has to be an underscore in the table _; so c-ip becomes c_ip.

The IIS log files follow a convention where “s-” is a server value, “c-” is a client value. Where things are passed from client to server, you’ll see “cs-” and when the reverse is true you’ll see “sc-“. For example, the query string is passed by the client and used by the server, so it’s cs-uri-query and the response code is passed from the server and used by the client, so it’s sc-status.

Why It’s Useful

The benefits of running SQL queries against your data are pretty obvious, but there are also benefits to the loading process. Because it will merge and load IIS log files, you can drop in logs from several different servers and have them all loaded into a single view. If you have a web farm, you can quickly get a view across all your web farm servers using this tool.

Although other tools are available, this is a simple and neat way to pull in data into a familiar tool to analyse it fast.

Full instructions on how to set up a small database and run the tool are in the README file on GitHub.

The journal Import IIS Log Files to SQL Server with Web Log Importer was first published at Steve Fenton.

]]>
7806
Avoid Expensive innerHTML Manipulation with insertAdjacentHTML https://www.stevefenton.co.uk/2020/02/avoid-manipulating-innerhtml-with-insertadjacenthtml/ Sat, 29 Feb 2020 15:45:07 +0000 https://www.stevefenton.co.uk/?p=7669 It is pretty well known these days that fiddling with innerHTML is terribly inefficient. It triggers serialization, and it can result in invalid markup. Nevertheless, you’ll still find this being done in many applications. elem.innerHTML = elem.innerHTML + '<a href="https://www.example.com">Visit Example Dot Com</a>'; // or elem.innerHTML += '<a href="https://www.example.com">Visit Example Dot Com</a>'; You can avoid […]

The journal Avoid Expensive innerHTML Manipulation with insertAdjacentHTML was first published at Steve Fenton.

]]>
It is pretty well known these days that fiddling with innerHTML is terribly inefficient. It triggers serialization, and it can result in invalid markup. Nevertheless, you’ll still find this being done in many applications.

elem.innerHTML = elem.innerHTML + '<a href="https://www.example.com">Visit Example Dot Com</a>';

// or

elem.innerHTML += '<a href="https://www.example.com">Visit Example Dot Com</a>';

You can avoid many of the downsides to this approach using insertAdjacentHTML. Here’s a quick example that is equivalant to the previous operation, but without serialization or potential runiation.

elem.insertAdjacentHTML('beforeend', '<a href="https://www.example.com">Visit Example Dot Com</a>');

That first parameter needs a little explanation. It just allows you to place your new HTML in one of four locations:

beforebegin
Immediately before the element
afterbegin
Immediately inside the element
beforeend
Immediately before the closing tag of the element
afterend
Immediately after the closing tag of the element

So, if we take this HTML:

<div id="example">
    <div>Existing Element Content</div>
</div>

And we run all of the possible variations, as shown below:

const elem = document.getElementById('example');

elem.insertAdjacentHTML('beforebegin', '<div>Before Begin</div>');

elem.insertAdjacentHTML('afterbegin', '<div>After Begin</div>');

elem.insertAdjacentHTML('beforeend', '<div>Before End</div>');

elem.insertAdjacentHTML('afterend', '<div>After End</div>');

We end up with the following HTML:

<div>Before Begin</div>
<div id="example">
  <div>After Begin</div>
  <div>Existing Element Content</div>
  <div>Before End</div>
</div>
<div>After End</div>

The journal Avoid Expensive innerHTML Manipulation with insertAdjacentHTML was first published at Steve Fenton.

]]>
7669
HTML Challenge: Toggle Switch vs Checkbox https://www.stevefenton.co.uk/2020/02/html-challenge-toggle-switch-vs-checkbox/ Sun, 16 Feb 2020 19:39:45 +0000 https://www.stevefenton.co.uk/?p=7517 The toggle switch has very suddenly become a ubiquitous feature of web user interfaces. You can’t hardly fill in an HTML form these days without finding one; especially as 99% of forms we now fill in are concerned with “cookie consent”. Why isn’t the toggle switch a first-class citizen of HTML, you may ask… to […]

The journal HTML Challenge: Toggle Switch vs Checkbox was first published at Steve Fenton.

]]>
The toggle switch has very suddenly become a ubiquitous feature of web user interfaces. You can’t hardly fill in an HTML form these days without finding one; especially as 99% of forms we now fill in are concerned with “cookie consent”. Why isn’t the toggle switch a first-class citizen of HTML, you may ask… to which the only reply is that it kind-of-is and it’s called a checkbox.

So, should the humble checkbox be supplanted by a slidey-toggle switch? Let’s find out.

Visuals

Let’s take a look at the toggle switch control:

Toggle Switch Control

And the checkbox:

Checkbox Control

Both of these user interface elements sever the same purpose. They select on of two states. You can call it on and off, ticked and un-ticked, or yes and no.

User Perspective

Although both of these controls are seemingly identical in purpose, I uncovered an “it made me think” moment when looking at an example. The example was “on” when the switch was on the left and this felt wrong somehow. The creator must have thought this was the intuitive direction for [on – off], but a strange intuition told me [off – on] was more natural.

To find out, I asked The Internet via a poll and found out that things were mostly in favour of the latter.

92.3 % of users say "on" is on the right

92.3% of respondents said that “on” was on the right.

This might be enough to make you conclude your experiment and fix your decision. It’s well past the point of a majority… but is that enough? Not for me. I’m about to implement this control on a web estate that gets well-over eight million visitors a year. Accepting a 7.7% failure rate would mean over 600,000 people being confused. Small percentages on big numbers can matter a great deal, as we discovered when we thought about making websites work without JavaScript.

To plan a course of action, we need to know how well a toggle switch performs relative to a checkbox; so I asked The Internet again.

100% of people consider a ticked checkbox to be "on".

100% of respondents said that “on” is ticked.

By using a checkbox instead of a toggle switch, I help over 600,000 users. When you consider that there are left-to-right and right-to-left languages, which might make the toggle even more confusing – we could be on to something with checkboxes.

Technical Perspective

The toggle switch was clearly worse than a checkbox when it comes to usability. Not everyone understood what state means “on”. We could add text-labels, instructions, or colours to try and assist users; but we could do this with a checkbox too. A toggle that turns from red to green doesn’t work in all cultures, or for colour-blind users, or for non-visual users.

While we’re on the subject, what other features of a toggle switch might be a problem? Well, it turns out that what you can do very well in two elements (an input and a label) is rather tricky to do well with a toggle. To make a toggle switch fully accessible, you need a reasonable chunk of HTML and CSS, with a little JavaScript to ensure it properly works for everyone. Making your own HTML form controls is a significant challenge.

Our solution was five-elements, a function, and a loop around a DOM query to add event handlers. We also needed four CSS blocks. It was a significant investment, but your screen-reader would handle it correctly and you could use a multitude of input devices to toggle it.

Visual Stimulation

Toggle switches tickle that same visual stimulation itch that causes so many people to use pie charts, even though they are bad. As of 2020, I have a full three pages on the subject of pie charts and similar visual stimulants if you want to find out more about that issue.

The question is, why do we need to make form elements more appealing? It doesn’t make them easier to understand or easier to use, so who exactly is the trend of toggles serving? Perhaps it is just another case of someone trying to copy something they found on their mobile phone.

Android Toggle Switch

And so…

Before you decide to seek a toggle switch implementation online, beware of charging lemming-like towards what seems to be clearly the wrong solution. Not only will a group of users find the control confusing, if you implement it poorly you will effectively exclude a whole host of users who don’t happen to have the same set of abilities you do.

Form controls are not an area that benefit much from novelty. Boring and predictable forms are just easier to use. That’s not to say you can’t style up your form elements beautifully to make the experience even better; just think it through before you chuck out all the years of thought that have gone into creating globally-recognisable widgets that work for everyone.

The journal HTML Challenge: Toggle Switch vs Checkbox was first published at Steve Fenton.

]]>
7517
Set a Minimum Font Size https://www.stevefenton.co.uk/2020/02/set-a-minimum-font-size/ Fri, 14 Feb 2020 16:04:22 +0000 https://www.stevefenton.co.uk/?p=7478 This is just a little script I needed to use to increase text size conditionally. It only increases text below a minimum size and leaves everything else. (function () { var minFontSize = function () { $(".content-zone *").each(function () { var $this = $(this); if (parseInt($this.css("fontSize"), 10) < 16) { $this.css({ "font-size": "16px" }); } […]

The journal Set a Minimum Font Size was first published at Steve Fenton.

]]>
This is just a little script I needed to use to increase text size conditionally. It only increases text below a minimum size and leaves everything else.

(function () {
    var minFontSize = function () {
        $(".content-zone *").each(function () {
            var $this = $(this);
            if (parseInt($this.css("fontSize"), 10) < 16) {
                $this.css({ "font-size": "16px" });
            }
        });
    };

    $(document).ready(minFontSize);
    $(document).ajaxComplete(minFontSize);
})();

Before Image

Text Size Before

After Image

Text Size After

You can see that the span element is the same size before and after, but all the tiny text has been increased to the minimum size.

The journal Set a Minimum Font Size was first published at Steve Fenton.

]]>
7478
Can You Average Averages in Your Analytics? https://www.stevefenton.co.uk/2020/02/can-you-average-averages-in-your-analytics/ Fri, 14 Feb 2020 07:57:53 +0000 https://www.stevefenton.co.uk/?p=7468 There is a common question that crops up in analytics, which is can you average your averages. The short answer is no, but a longer explanation is probably needed. Whether you have grouped your data by month, or region, or some other facet – each average you see is based on a different number of […]

The journal Can You Average Averages in Your Analytics? was first published at Steve Fenton.

]]>
There is a common question that crops up in analytics, which is can you average your averages. The short answer is no, but a longer explanation is probably needed.

Whether you have grouped your data by month, or region, or some other facet – each average you see is based on a different number of data points. You might have an average of 10 based on 10,000 individual data items and an average of 2 based on a single data point. If you attempt to create an “average of averages”, the single data point will disproportionately affect the outcome. The average of 10,000 data items basically gets valued at the same rate as the average of the single data point. The “average of averages” would be 6, but the correct average of all values would be 10.

This may still be unclear, so let’s kick of an example and explore some data.

Simple Averages

We’re going to use two sets of numbers, let’s imagine these are test scores for two coffee shops, where customers can score the coffee out of 100.

Metro Coffee has a great central location and collects scores from 21 customers over the course of the first day.

12, 3, 23, 32, 34, 76, 6, 23, 2, 23, 75, 23, 24, 34, 46, 34, 74, 8, 7, 96, 64

If we add up all these scores and divide the result by the number of customers, we get an average score-per-customer of 34 for Metro Coffee. There’s room for improvement.

Alley Beans is off the beaten track, so only collects scores from 4 customers on the first day.

76, 6, 23, 2

Adding these numbers up and dividing the total by 4 gives Alley Beans an average score of 27. Even worse than Metro Coffee.

Average of Averages

If you wanted to see an average customer score across all coffee shops, you might be tempted to sum the two averages and divide them by 2. For example….

(34 + 27) ÷ 2 = 30

So, the average score is 30 right? Nope. It seems intuitive to do this, but it gives you the wrong answer. The 4 customers at Alley Beans have a disproportionate influence on the result. The small Alley group has the same “whomp” as the group of 34 customers at Metro Coffee. If this were an election, each individual Alley customer would have more than five times the voting power of a Metro customer! When it comes to an election this might be acceptable; but we’re talking about coffee here – so this is serious.

How do we resolve this imbalance?

Original Numbers

If you have all of the original scores, you can get an accurate average by totalling up all the scores and dividing the total by the number of scores submitted. This is basically the same process we used to calculated the original numbers.

12, 3, 23, 32, 34, 76, 6, 23, 2, 23, 75, 23, 24, 34, 46, 34, 74, 8, 7, 96, 64, 76, 6, 23, 2

Adding them all up, and dividing the total by 25 gives us an average of 33. That’s a significant difference to our original attempt, which yielded 30.

But what if you don’t have the original numbers?

Weighted Averages

If you don’t have all of the original values, you need to ensure you averages are accompanied by an n. An n is just the count of the values that made up the average in the first place. This allows us to pass around lots of small pairings of average and the count of values, but still calculate accurate averages of the averages!

Here’s an example:

Metro Alley
Average 32 27
n 21 (n1) 4 (n2)
Proportion 0.84 (n1 ÷ sum of n) 0.16 (n2 ÷ sum of n)
Result (Average X Proportion) 29 4

If we sum up the results (29 + 4) we get our weighted average, which is 33. That’s the same as if we had all the original values. The benefit of this system is that we don’t need to pass all of the original data, just the count and average.

Here is diagram that shows all my workings for the above the numbers, feel free to try this out for yourself in Excel, a calculator, or even an abacus.

Average of Averages

Summary

Attempting to average existing averages without knowing the number of values contained in each value leads to statistical errors. Either use the original values or keep hold of the number of values included in the average in order to keep your numbers accurate.

The journal Can You Average Averages in Your Analytics? was first published at Steve Fenton.

]]>
7468