Sunday 17 October 2021

Picking a Better Data Store


I like Entity Framework.  It's like arriving at Hogwarts and trying out your wand for the first time .  Sometimes you wave it, and it transforms your rat into a perfect water goblet.  Other times it just blows up in your face, and you have to spend the rest of your high school years trying to master the correct incantation.

The question is, "Why do you have to have magic to transform your code into SQL?"  I used to say for unit testing, but if I want to test my units (whatever a unit is), I could just run them against an in-memory database.  Why do we need to transform a rat into a water goblet, when we could just go out and buy a water goblet, and keep our pet rat?  A rat is not a water goblet, neither is my Linq code TSQL, nor is my aggregate a table.

I use Entity Framework for two reasons: because it's fun, and to show off.  You could say that it makes the code more interesting.  It reminds me of AutoMapper... a library that automatically copies data from one object to another, if the property names match.  If they don't... you can extend your mapping to cater for it.

This is boring:

A.X = B.X;
A.Y = B.Z;

This is cool:

AutoMapperCadabra(A, B);
// TADA!

However, one is easy to debug, and one is not.  That could be a bumper sticker, "Magic... it's not easy to debug!"

Anyway... what was the point of this blog again?  Ah yes... picking a better data store.  What if there was no need for magic?  What if you could just put your aggregate in a database?

And that's why we use document databases.  But there's more to it:

Document databases are typically designed to scale horizontally, splitting the data up in shards on separate nodes.  A relational database typically requires either vertical scaling, or to replicate the entire database to multiple read nodes.

In a document database your aggregate is read and written sequentially... everything for your aggregate is in the same place.  It's not necessary to find bits and pieces all over the hard drive and bundle them together.

But... relational databases have their place.  You can index almost any piece of data, find it, and discover everything it's related to.  Want to find out something complex, like all the brands of wands used to create water goblets where the rat tail was still protruding from the water goblet?  You can!  Not so quick with a document database, unless you read everything.

They also have a schema, meaning that the format of every row is consistent.  This could be important, knowing that whenever you load a record, it it will be in the expected structure.

So, it depends what you need.  You could always dump your changes into a couple of queues and have multiple consumers build up different kinds of data stores, if you really want to.

Tuesday 27 July 2021

SOLID

Nerdy Monk with Kittens

SOLID
, YAGNI and DRY are acronyms commonly used to describe good programming practices.

DRY is not WET

DRY
is my favourite: Don't Repeat Yourself... instead of writing the same code twice, wrap it up in a function and put it somewhere where it can be easily found and re-used.  This also means if you have to fix a problem, or improve your code, you'll only have to make your change once.

I tend to take DRY to the extreme, by writing little tools, either in PowerShell, or Python, or a little desktop app that takes care of any monotonous task that I might have. The tasks are usually things to do with my dev environment, like automatically powering up useful AWS resources when I login to Windows, and adjusting settings in JetBrains' Rider, so that it only has to compile the bare minimum it needs in order for me to debug the code I'm working on. Other tools I've written include swapping in and out fake and real libraries that my code connects to, so that I can debug under a variety of conditions. These tools not only save time, but allow me to focus on what I enjoy, and what really matters.

DROP is WET

I'd love to invent my own acronym here, DROP: Don't Repeat Other People.

Whenever writing your own generic code, there should be a few things that come to mind... Why has no-one else written this before? Oh, maybe they have. Is there a NuGet package I can reuse? Because, really, if it's generic, and your code is better than any other open source library out there, perhaps you should be either creating, or contributing to open source.

YAGNI... unless it's a kitten!



YAGNI means You Ain't Gonna Need It.  The theory is that your code will be simpler if you delete (or don't write) code that you may need in the future.  It also means you don't have to test it.








SOLID is five principles:

Chaos from multiple responsibilities

1. Single Responsibility: 

A class should only have one responsibility.

Example:  A Person class should not contain code that ensures the email address is in a correct, standard email address format.  Email validation is generic and should go elsewhere.

2. Open / Closed Principle:

Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.

To quote Robert C. Martin (Uncle Bob): 

When a single change to a program results in a cascade of changes to dependent modules, that program exhibits the undesirable attributes that we have come to associate with “bad” design. The program becomes fragile, rigid, unpredictable and unreusable. The open-closed principle attacks this in a very straightforward way. It says that you should design modules that never change. When requirements change, you extend the behavior of such modules by adding new code, not by changing old code that already works.[1]

This means, if you have created a class that is being used, don't make changes unless you're fixing bugs.  Inherit from it instead, and make the changes there. Of course all the cool kids are preferring composition over inheritance these days, so adding a property that's an object is fine, but work with abstractions. When I do this, I might use an interface like IContainX, and then implement a new interface IContainY. That way, your object can be extended with any existing code being referred to (X) remaining unchanged.

If you used TDD properly to build the class, and you're not actually changing the behaviour... You can make performance improvements as long as your original tests pass.

3.  Liskov Substitution Principle:

Objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.

So, if the Tesla class inherits from the Car class, you might not want to have a method Car.FillUpWithPetrol(), or you should simply not create a Tesla class inheriting from the Car class.

4.  Interface Segregation Principle:

Many client-specific interfaces are better than one general-purpose interface.

The reasons:
  • Because any implementation should ideally implement every member.  When testing, and creating fakes, mocks or stubs, we don't want to have to care about whether or not a member is implemented if it's not related to the test.
  • Unnecessary complexity (See my blog post on reducing complexity).  Not everyone who flies in a plane wants to see all the controls in the cockpit of a Boeing 747.  All they may need is a button to call the flight attendant.

5.  Dependency inversion principle:

Depend upon abstractions, rather than concretions.

This is often done using dependency injection. It's a way of loosely coupling objects. You don't solder wires from a lamp into a wall socket... you create interfaces, which both the lamp and source of electricity can use.

The way SOLID's used is a bit funny.  I say it's funny, because when I interview someone they usually remember SINGLE RESPONSIBILITY and waffle through the rest. Yup, we're only human. I've heard the word SOLID used a few times, when the speaker's intention was to refer to single responsibility. I don't think it really helps to ask about it at interviews, directly. It's possible that a good answer just shows that the person's attended many interviews. Perhaps a better test would be to offer some code, and ask what the interviewee would change about it. Although, when I've done that in the past, I tend to get a lot of silence... so who knows?

References:

How to reduce complexity and know everything.

Quality We have a great QA. His code is like a Rolex. You look at his gherkin, and smile.  It says what it's testing, in plain English, ...