Little known technique for self-describing code

Published

It is very common to describe your code with comments but they have one big issue. Quickly getting out of date.

One developer creates a code, adds few comments.Second developer changes the code a little bit and forgets about comments.Third developer changes the code and forgets about comments.So on so forth and then... You can no longer trust if the comments are actually valid/accurate.

Here I'd like to explain you one more method that I found useful, reduces amount of necessary comments and it's type-safe.

Monads!

My personal choice for implementation of monads is @sweet-monads as it does not force you to go into full-blown FP programming like fp-ts does.

Returning single entity but sometimes it cannot be found

If a method tries to find something but it might not be found then instead of returning Smth or undefined use Maybe instead. That clearly describes the operation might return an empty result.

In other words we can say:

find article by id and optionally return result

class ArticleRepository {
    findById(id: string): Promise<Maybe<Article>> {
    }
}

Especially useful for environments where strictNullCheck is not enabled for some reason.

Creating an entity but fails once it is a duplicate

If a method creates an entity but that entity violates some constraints then instead of throwing an error return Maybe .

In other words we can say:

create entity and optionally return created entity if that succeeds, if none then there is a duplicate

class ArticleRepository {
    create(input: ArticleCreateInput): Promise<Maybe<Article>> {
        try {
            // make insert to database
            // if succeeds
            return just(newlyCreatedArticle);
        } catch (e) {
            if (e.code === 'UNIQUE_VIOLATION') {
                return none();
            }
            // throw other errors
            throw e;
        }
    }
}

Parse something but parsing is likely to fail

This one is my favorite.

Parsing some input is very likely to fail since simply input might not be valid. How are you going to catch an error for it? Creating new error type? How do you know you've handled all type of errors possible to be thrown by parser?

For all that problems here it comes - Either.

function parseDomain(
    domain: string
): Either<'INVALID_SYNTAX' | 'UNKNOWN_TLD' | 'TOO_LONG', Domain> {

}

In other words we can say:

parse domain and return fail which might one of following strings, if succeeds return Domain object

  • No extra error types
  • No unnecessary try/catch when you don't need it
  • You know upfront what kind of errors to expect
  • If something unexpected happens (regular TypeErrors or smth) then error gets thrown

Other use cases for Either

  • regular data validation - Either<Violations, SanitizedData>
  • RPC operations - Either<RPCError, TResult>
  • Run a task but it might fail - Either<TaskError, TResult>
Łukasz Kużyński - Wookieb
Thoughts, tips about programming and related subjects to make your job easier and more pleasant so you won't burnout quickly.
Copyright © Łukasz Kużyński - Wookieb 2023 • All rights reserved.