News for hackers. Stuff that matters.
Re:Node.js 16 Available Now by sa46 on Tuesday April 20, 2021 @05:24PM (#26881928)
> huge, enormous, gargantuan benefits

Would you mind enumerating them? I have an idea of what they are but curious about other perspectives.

My sense is that code sharing is not that common between a Typescript frontend and backend. You mostly need generated request/response data types but I don't think there's that much shared behavior because you can't import any of your backend-y logic (database, auth, external APIs) transitively into your frontend.

I think primary gain is what you've hinted at: 1 ecosystem and it's easier to onboard fullstack devs.

Re:Node.js 16 Available Now by jitl on Tuesday April 20, 2021 @05:52PM (#26882298)
Notion shares a large amount of code between the front-end and back-end. We have many algorithms, collections, helpers, etc that we share. Here's an example, we have a shared loadPageChunk function that takes a cursor and a loader implementation, then traverses our data graph to gather the data needed to render part of a page.

    // shared code - implement the algorithm
    export async function loadPageChunk(
     args: LoadPageChunkArgs,
     loadRecordValue: loadRecordValueFn
    ) {
      // ...
    }
    
    // client code - use the algorithm, provide client-specific IO
    // eg on Android we'd use Sqlite.
    const records = await loadPageChunk(cursor, SqliteService.loadRecordValue)
    
    // Server code - same, but use the server's data stores.
    // Behind the scenes, these loaders batch, etc
    const records = await loadPageChunk(cursor, useCache ? CacheService.loadRecordValue : PostgresService.loadRecordValue)
Even if we only shared types, there's a significant benefit. We try to push as much logic into the type system as we can; for example we use discriminating unions to define different groups of related types. Eg, we have a union type called ContentBlock that has all the specific block types that can have children, `Page | Text | Column | ...`, sharing this type and its helper functions like `isContentBlock(block: BlockValue): block is ContentBlock` means both our front-end and back-end code rely/expect/enforce the same invariants.
Re:Node.js 16 Available Now by hn_throwaway_99 on Wednesday April 21, 2021 @04:54PM (#26895328)
One example: input validation logic is something that is nice to run in the front end (for performance and immediate responsiveness to users) but that you also need to run in the back end for correctness.

Previously I've done this with 2 implementations (JS on frontend and Java on backend), but then keeping the logic in-sync is a nightmare. With a single language you can just share the library.

You are correct, though, the biggest benefit I see is not sharing code, but making it trivially easy for a front-end dev to add a small piece of backend code that they need without needing a back-end dev to do it, and vice versa. It just makes the overall team much more productive because there is very little "waiting on the back/front-end" to do it.

Oftentimes we'll have either team write up the schema for a new endpoint using the GraphQL schema definition language, then from that we autogenerate the TypeScript types, then usually the front-end team creates a simple mock in the backend so that they can fully implement the UI, meanwhile the backend team works concurrently on the real implementation. This process allows for much more parallel productivity than if, when something is broken or needed from the other team, you just have to submit a ticket and wait.