Human Capital is Loyalty Capital

Sep 10, 2023

Many people shy away from the phrase “human resources” these days, recognising that referring to people as resources is dehumanising. “Human capital” is another piece of business jargon that some prefer to reach for, rolling out the oft-quoted cliché, “people are our greatest asset”.

Unless you’re a slave owner, it’s just not true.

People are essential essential to your organisation succeeding, but you don’t own them. Don’t manage investment in your people by pretending you do.

What, then it an organisation’s asset? The loyalty, motivation, and trust of your team.

Shepherding the loyalty, motivation, and trust of the members of your team is that essential core. If “human capital” means anything, it doesn’t refer to bums-on-seats, so much as the emotional glue that sticks the two together.

I prefer to think of it as “Loyalty Capital”.

Loyalty Capital is the combined loyalty, motivation, and trust of your team members.

“Loyalty”? Ew!

“Corporate loyalty” is a dirty phrase these days: given the betrayal of loyalty that many companies gave their staff from the 1980s onwards, many find the idea of being loyal to a company inappropriate.

At a personal level, it’s good to avoid being blindly loyal to your place of work. However, in practice, people will often show a some loyalty to their employer.

  • People will be loyal to their team-mates.
  • People will trust leadership enough that they assume that changing jobs won’t fix whatever issue they’re struggling with.
  • If people have been treated well in the past, they will both feel some compulsion to “pay that back” as well as assume that they are likely to be treated well in the future.

Millennials, everyone’s favourite scapegoat generation, get a bad rap for showing a lack of appropriate corporate loyalty. For generations who had parents affected by the “corporate efficiency” moves, it’s unsurprising that corporate loyalty is a contingent proposition.

You can still build up loyalty capital with younger generations (not to mention that millennials are now entering their 40s), it just takes more work – it doesn’t come for free, and it’s not limitless.

Loyalty accounting

Loyalty Capital can be thought of as a “stock” in a stock and flow system. We can do things to build this stock up, and we can do things to deplete this stock. When your Loyalty Capital is high, benefits include:

  • People are more effective, productivity increases.
  • Your reputation outside the company improves through word of mouth and hiring becomes easier.
  • Staff leave less often.

The opposite is true when loyalty is low.

Another effect is that there is less blow-back when bad things happen. If you have run a tight ship and shepherded your Loyalty Capital before the event, such as being forced into making redundancies, it will still be a difficult event. However, it would be much worse if your team were running out of patience with the company’s leadership.

Loyalty will take a hit in times like these – in essence, you’re spending your Loyalty Capital – but having capital available to spend lessens the blow for everyone involved.

Building up loyalty

What can you do to build up your Loyalty Capital? It’s simple, really, but it’s not easy. For example:

  • Have a clear & meaningful mission.
  • Make important decisions in line with the company’s stated values, and hold people to account for operating in accordance with those values.
  • Demonstrate integrity, authenticity, and empathy.
  • Prioritise team members’ needs.

These are things that are easy to say and hard to do, although they’re easier to pull off when you believe in them deeply.

What about the opposite? Poor leadership, generally, will of course wear down your Loyalty Capital, but so will focusing exclusively “on the numbers” when making decisions. For example, if you make a push for efficiency without also prioritising team members’ needs, your Loyalty Capital will take a hit. Maybe it’s a cost worth incurring, but don’t do it blindly.

Over to you

The aim of this post was to introduce Loyalty Capital as a tool to support management decision-making. There's a lot more that I could say about it, but first I'd want to hand over to you.

What do you think? Does it give you a new way of thinking about a situation you’re dealing with? Is it a re-hash of existing ideas that I should read up on? Do you have any ideas that would build upon it?


Why you should try ReScript

Sep 4, 2023

ReScript is a variant of OCaml with a syntax more familiar to JavaScript developers. A couple of years ago I built Forecastel in ReScript + React. More recently I’ve done most of my work in TypeScript, but I really enjoyed putting together a ReScript project.

I don’t recommend that you drop everything and switch your current project to ReScript. However, if you spend a lot of time doing TypeScript development, I think you should give ReScript a try on a small project because it will make you a better TypeScript programmer.

What’s different from TypeScript

ReScript has a sound type system, which means that in a compilable program, the type of every variable can be correctly inferred. To achieve this, it doesn’t attempt to replicate every feature of JavaScript. Instead, it takes the OCaml type system and translates it to JavaScript.

TypeScript, on the other hand, is explicitly a superset of JavaScript and needs a more complex type system to cover that functionality. As a result, TypeScript’s type system is unsound. It’s commonplace in TypeScript code to assert type information to correct small mistakes that the type checker has made.

The soundness of the type system means that there’s no type coercion and no any or unknown types. If the code compiles, you can be much more confident that you won’t see runtime bugs.

(Technically, you can build unsound escape hatches from the type system when you link to non-ReScript code, but this is a more deliberate step than simply tagging a variable as any in TypeScript).

What’s great about it

It’s hard to summarise the benefits of a language in a few short points, but three things that really appeal to me are tagged unions, match expressions, and function chaining.

Tagged unions

TypeScript has “algebraic types’ – the ability to create a union of tuple or record types into arbitary and recursive structure. ReScript goes further with the “tagged union” type, where each item in a union set has an identifer as well as 0 or more arguments. This is an elegant and powerful way of specifying data structures.

For example, this specifies the abstract syntax free for a simple arithmetic expression:

type rec expr =
  | OpAdd(expr, expr)
  | OpSub(expr, expr)
  | OpDiv(expr, expr)
  | OpMul(expr, expr)
  | OpPower(expr, expr)
  | Value(float)

And this specifies the action argument to Redux-style reducer for a simple to-do list. The functionality normally provided by Redux’s “action creators” is essentially a core language feature.

type id = string

type action =
  | Add(string)
  | Complete(id)
  | Modify(id, string)
  | Delete(id)

Match expressions

Match expressions make it very easy to exhaustively and concisely operate on algebraic types. Here’s an example evaluating the expression type above:

let rec eval = (expr: extr) =>
  switch expr {
  | OpAdd(a, b) => eval(a) +. eval(b)
  | OpSub(a, b) => eval(a) -. eval(b)
  | OpDiv(a, b) => eval(a) /. eval(b)
  | OpMul(a, b) => eval(a) *. eval(b)
  | OpPower(a, b) => Js.Math.pow_float(~base=eval(a), ~exp=eval(b))
  | Value(val) => val
  }

You can nest expressions on the left to unpack deeper data-structures, and if you miss any of the possible options, you will get a compile error.

Function chaining

Function chaining via the -> or |> operators makes it really easy to compose small, single-purpose functions to get the result you want. A trivial example would be passing an input string value into a parse function that generated the AST above, and then evaluated it into a result variable:

let result = inputValue->parse->eval

Essentially the -> takes the result of the left-hand expression, and passes it as the first argument of the function on the right.

let a = parse(inputValue)
let result = eval(a)

The |> operator is similar but passes the result as the last argument instead.

What’s frustrating about it

Despite its advantages, and the joy of using it (most of the time), it can be frustrating in ways that you don’t really want from your team’s day-to-day tool. Because of this, and because TypeScript provides enough of the benefits without these frustrations, I don’t necessarily recommend you jump into with with a project supported by a large team.

JSON parsing is painful

A lot of building websites involves parsing JSON structures. ReScript’s sound type system means you won’t be caught out in the middle of your logic by invalid JSON data. However, this does mean that you need code that checks each JSON payload and translates it into ReScript types.

When I worked with it, I ended up with a lot boilerplate for parsing & generating JSON messages for each type. It was, strictly speaking, optional – you can coerce JSON payloads to/from ReScript types outside the type system – but that seemed wrong and loses the benefits of the type system.

In principle, this could be solved with code generators, although I didn’t find anything suitable at the time and I never bothered writing my own one.

Small ecosystem

The ReScript ecosystem is very small. There aren’t a huge number of libraries for ReScript itself, and if you want to pull in a 3rd party JavaScript package, you’ll probably find yourself writing the type-signatures to map library into ReScript yourself. Generally people take the approach of writing type-signatures only for the part of the library that they use, rather than relying on the equivalent of @types packages in TypeScript.

The small ecosystem is made worse by the fact that there was some fracturing of ReScript and sister/former projects Reason & BuckleScript, which means it’s not always obvious how older libraries will fit with the code you’re currently working on.

If you’re dealing with an API with a very large API surface (e.g. WebGL), this can get tedious.

Why will it make you a better TypeScript programmer?

So why try it? Because it will improve your ability to think in types.

By way of analogy, consider unit tests. Many people write unit tests, bashing something out after a feature is done to get the coverage metric above an acceptable percentage. However, advocates of Test-Driven Development know that tests aren’t just something to check you’re code: they’re a way of encouraging you to think more deliberately about your code design, and that the act of writing tests first improves the quality of your code.

So it is with types.

A language like ReScript makes it easier to:

  • elegantly express your types
  • make concise functions that transform between them
  • chain together atomic functions to achieve the functional result you need

Because of this, it’s more natural to think of your application in terms of a set of types that represent important states between them, and functions that transform between these types.

You might call it “Type-Driven Development”. It’s a great companion to Test-Driven Development – transforming between types is very easy to unit test, and a lot of trivial tests are handled by the type-checker.

It’s a useful mentality that you can carry back to your TypeScript code.


Kicking off a new blog

Aug 27, 2023

I've got a new blog! Although I've had a few blogs over the years, I've never been particularly persistent at actually writing in them, and I've had the sminn.ee domain for probably a decade, thinking “I should really set up a blog there at some stage”, without having doing it.

When I was CEO at Silverstripe, “you should start a CEO blog” was something that I agreed to, and failed to follow through on, so many times that it become a running joke at the management team.

But, it's 2023, people are getting tired social media, what better time to start a new blog?

My main motivation for starting a blog is simple: to build a habit of putting my thoughts in writing. I was inspired by my friend Ingo’s motivation to get better about remembering things that he had read each week. He shared this YouTube video of tips. A couple of those suggested that sharing ideas, teaching ideas to others, and writing them down helped with retention.

My plan is to post each Sunday, capturing something that I learned from the week prior. We'll see where this leads, and you're welcome to join me on the journey. Hopefully some of what I write is useful to others, and failing that it will at least help me clarify my thniking.


Don’t breed your own turtles

Aug 27, 2023

What did I learn this week?

I've recently been working on 2 sites with similar codebases: vCXO.directory and Astronort. They're both Vue on the front-end, Express on the back-end, with a simple SQLite database. I have copy-pasted a lot of code between them, and that started to feel sub-optimal. This week, I thought “screw it, I should refactor the 2 sites to have a common library”.

After a collected ~6 hours attempting this over a few days, I decided it was the wrong thing to do and gave up on it.

Tilting at turtles

For many of my solo projects, I’ve taken a much more aggressive stance against pulling in libraries. I’ve wanted to avoid ending up with the “stack of turtles” that so often plagues other projects: dozens of libraries & tools pulled into a project to save time, that in the long-run result in a fiddly & unmaintable mess.

In a project with tighter deadlines and a bigger team of varying skills, experience, and opinions, it's usually easier to take the “sensible” path and make use of more off-the-shelf libraries. Solo projects provide an opportunity to see what I can learn about the benefits & pitfalls of reinventing a lot of small wheels.

As a rule-of-thumb, if it takes less than a day to build, my bet is that the overhead of dealing with someone else’s mental model, and a solution that meets all use-cases, is probably greater than the overhead of building a simpler solution suited precisely for the project I’m working on.

I've pushed this pretty far, building a lot of stuff that I might otherwise not need to, such as simple content editing and authentication systems.

Live long enough to see yourself become the villain

Separating code into a library caused a lot of friction.

First of all, details of the NPM/Vue/Vite ecosystem made running code in a separate package more complicated for many small, tedious reasons. The moment that I table-flipped was when I realised that the Vite plugin that lets me produce type definition files alongside my compiled library was outputing a good fraction of my code with the "any" type.

Compiling a library, producing definition files via a plugin, and dealing with this bug in the plugin were things that I didn't need to think about when all my code was in a repository. Although it's certainly possible to produce well-designed libraries for others to use, there's a lot of work beyond simply making the thing you want to re-use.

But beyond this “accidental complexity”, there were fundamental differences in the 2 sites, even in areas that seemed identical between them. For example:

  • My "generic" forms (log-in, reset password, etc) were styled differently in the 2 sites, where the design of each site led me to lay information out in a slightly different way.

  • Each user database had slightly different fields, for linking to the rest of the data in the system.

Each of these problems could be solved in a library by introducing some appropriate abstractions. But that makes the whole thing more complicated.

In addition, I noticed that on each site, I was finding opportunities to refactor code that was achievable on a single project, but would become a lot harder to coordinate across 2 projects and a shared library.

The sad truth is that in sharing code between, I was recreating the “stack of turtles” problem that I had set out to avoid in the first place! But in this case, I wasn't benefitting from having someone else maintain part of the solution.

It would be a worst-of-both-worlds scenario.

It's like rain on my wedding day

After I dropped the idea of a shared library and went back to working on one of the sites in isolation, copy/pasting some code from the other, the overwhelming feeling was one of relief.

The irony of all of this is that I spent more than a decade working on a complicated reusable open-source web framework. I should have known all this.

Still, more than 20 years in, one of the things I love about software development is that it gives me moments to feel like a stupid beginner learning the basics.