β€’

tech

Development speed how to

You want an app that's reliable and fast. That is just about the same when it comes to development: reliable and fast, long-term. Here are a few techniques to guarantee you can code fast, bug free, for a long time.


Sandro Maglione

Sandro Maglione

Software

Development speed 🏎️

There is not enough discussion about pushing features fast, and reliably, even as the project keeps growing 🌲

I use a few techniques and principles to keep my speed at the top πŸ”

Here they are πŸ‘‡


Types

That's key number 1.

This is the best time saver (long term). Nail this, and you are fast 🫑

When your app is fully type safe (and I mean fully), you cannot make mistakes.

Even better than that, you cannot broke older features as you add more 🧱

Changing a type signature should create a cascade of compile-time errors (that you can easily fix). Full stack.

Example: OpenApi.

export class GetUserByUsername extends Request.TaggedClass("GetUserByUsername")<
  typeof GetUserByUsername.schema.Type,
  ClientError,
  // πŸ‘‡ Add all the necessary parameters (path/query/body) from the OpenAPI schema
  paths[typeof GetUserByUsername.path]["get"]["parameters"]["path"]
> {
  // πŸ‘‡ The path is type-safe derived from the OpenAPI schema
  static readonly path = "/2.0/users/{username}" satisfies keyof paths;

  // πŸ‘‡ Response schema (can be used for validation)
  static readonly schema = Schema.Struct({
    username: Schema.optional(Schema.String),
    uuid: Schema.optional(Schema.String),
  });
}

I wire API requests to a shared OpenApi schema. As soon as any API change occurs, the app will stop compiling.

Check out "Building a type-safe bridge between client and server" for more on full-stack safety.

A few other examples:

  • Change an XState event, and get compile-time errors where updates become necessary
  • Add a new value to a string literal, and use pattern matching to get compile-time errors
  • Use NonEmptyArray and branded types for strict(er) checks

In summary, you should be able to substitute pnpm run test with pnpm run typecheck (tsc compiler checking for type errors) πŸ’πŸΌβ€β™‚οΈ

Minimal transparent configuration

Tools should make you faster.

How obvious does this sound? Not obvious enough πŸ€·πŸΌβ€β™‚οΈ

I avoid setting up countless lint rules, multiple different compile steps, complex testing, and all. This comes from experience: adding all this configuration, to then either (a) ignore it or (b) remove it 🀯

Instead, I choose tools that are mostly transparent: setting up once, works every time afterwards. Examples:

  • Tailwindcss: initial configuration, and then it just works
  • tsconfig: as strict as possible
  • Vite/Next: (ideally) just pnpm run dev and pnpm run build

Avoid dependencies

Dependencies are like debt: get a feature now, pay the cost later 😬

I reduce my dependency pool to a few core and trusted group:

  • effect: always present, it covers most use cases in a single unified solution
  • xstate: covers all state management necessities (and I mean all)
  • Headless components: never recreate the wheel, I use react-aria-components instead

Outside of these, not much else (frontend). Anything else is 1-time and project-specific. Examples:

  • Stripe (e.g. @stripe/stripe-js)
  • clsx
  • Segment/PostHog
  • openapi-fetch

Repetition, or no repetition

A key skill to learn is when to copy-paste code or when to create an abstraction to avoid repetition πŸ€”

In general, "premature" abstractions will slow you down (both in the moment and long-term).

"Premature"? Rule of thumb: copy-paste the first time, consider an abstraction after the second copy-paste.

Also, the most "isolated"/specific a feature is, the less you should consider an abstraction:

  • Good abstraction: copy-text machine (generic)
  • Bad abstraction: a machine for a single step in a sign up flow (too specific)

Divide and conquer

Components should not have any business logic inside them πŸ™Œ

Or, more in general, to each its responsibility.

You should always know where a bug may originate πŸ‘€

Did your user get an error when clicking to submit? Most likely a request error.

User stuck during the sign up flow? State management issue.

If all requests are in the same set of files, and all state management is inside state machines, you just fly directly to the problem πŸš€


Remember when effect was "missing documentation"? Ain't no more excuses now, new content is coming out like mushrooms πŸ“ˆ

Meanwhile, effect v4 is taking shape behind the scenes, and it looks delicious πŸ”œ

See you next πŸ‘‹

Start here.

Every week I dive headfirst into a topic, uncovering every hidden nook and shadow, to deliver you the most interesting insights

Not convinced? Well, let me tell you more about it