Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Something I realized recently is that when I'm hacking on something, I like to brainstorm in terms of data from the very beginning, which means brainstorming in terms of types. Static types aren't just about stability and error-catching, for me. They are their own expressive vocabulary and I feel expressively crippled without them, even when working on a rough draft that will likely get thrown away.

That said I tend to prefer TypeScript over Rust for fast iteration, all else being equal, but I agree with the author that Rust can work quite well even for this usecase. And I would never pick Python for anything beyond 100 lines, if I'm being honest.



If you haven't, you should explore domain-driven design (DDD). It's an explicit idea in that framework that a problem needs a "ubiquitous language" and an identified "bounded context" where the said language is valid.

Like you, when approaching a new problem I like to nail down the terms we are discussing, literally scaffolding classes and types (in C++) as the problem is being discussed. It drives the adoption of unambiguous terms. Then as solutions are discussed the "ubiquitous language" helps clearly identify the interactions between types.


One advantage of using a very open-ended type system like TypeScript's is that you don't have to know as much up-front.

I could declare some type Foo, and that type might end up being:

- A class

- A record type

- A union type

- An intersection type

- A constant

or whatever else. But I can go ahead and start referring to that type in terms of function signatures, etc. Particularly for this kind of sketch-coding, it's really nice to be able to declare a concept and start talking about it before you even know what it is.


Can you explain more? For me, DDD is hard if you don't know or inexperienced on the business field.


Scala also shines for this style of development. Sealed traits and case classes (algebraic data types) are a nice way to express many different types of data models, including polymorphic types and state machines (its surprising how many "hidden" state machines live in your objects via Boolean and Enum fields).

I found this book very helpful in terms of thinking in a more functional type-driven way: https://www.manning.com/books/functional-and-reactive-domain.... It does eventually get into some deeper functional programming concepts but its still a nice read and easy to get into for anyone coming from more traditional object oriented coding.


As much as I love Scala, partly those reasons you just described, it's compilation speed is just too slow for doing prototypes.


For sure, the compilation times can get pretty bad with Scala, although I haven't found it too terrible on smaller prototype projects (I agree its still quite slow compared to some other languages though).

These day's I've been using Bloop (https://scalacenter.github.io/bloop/) which makes Scala compilation super fast. It keeps a hot compiler running in a daemon and takes incremental compilation to a whole new level for Scala, truly a game changer for me.


100% this. I’d go further and say that ts lets you write pseudo code that compiles. I will often mock up all the inputs and outputs for a system without writing any code in a shareable ts playground. It’s like an extraordinarily expressive design doc. If only management could read it...


well, I showed "pseudo code" (no, really python...) at middle management and they not only understood it, but also tuned it.

was fun to show them that that "pseudo code" actually worked


> I like to brainstorm in terms of data from the very beginning, which means brainstorming in terms of types.

It's funny, because I feel the same way, except I gravitate towards Clojure, where data is just data (and you stick it in vectors and hashmaps), and I don't feel the need for static types. At a later point, I may think about adding specs, but for quickly iterating at the REPL while I think about a problem, "plain data" works wonders.


I think the difference is that with types, you have a language based reference which you can talk about (fn x takes type y). This allows you to build the lower functions and check the abstractions at compile time, without having to build the higher levels or even run the program.

With a dynamic language, you need a specific instance of data in order to write your functions, so you typically start from the top function and implement downwards. I think this works well when you have a light layer over some other library or system, but does not work well when you are implementing many layers in your own code.

I think this is what he hints at with:

> When I want to know if my code is working, I actually have to run the Python thing and feed it with data

I like REPLs, but Im experimenting with a type system + running a test on save that exercises the functions Im currently working on. This feels REPL-like as the iteration loop is fast.

It's interesting because I would previously implement something top down from the highest functions, but now I can implement mostly bottom up as the types/compiler gives me the language to define the layers.


For what it's worth, my usual flow is to start sketching top-down, and building bottom-up afterwards, refactoring as I go. I also (ab)use Clojure's argument destructuring and will often just pass a map until I settle on the "correct" API for my code.

Not bashing good types (I do like Haskell, too), just showing an alternative based on the same brainstorming idea the GP had mentioned.


This is big! I call it (others might too, idk) “.d.ts driven development”. Where you start the project by writing a .d.ts file and implement it. Similar to starting with a .h in C. Fun fact this is how xterm.js is structured (the terminal emulator used in vscode and hyper, among other things).


Yeah, there's this notion that with static typing, you have to "get your types right first". In my experience, when I'm prototyping it's often very effective to sketch out my current understanding in the types, and then as I learn - quickly and slowly - where I was mistaken and update the types, the type checker helps me update the code that needs updating to match.

I understand that others' experiences differ.


If the process is rather easy (fast to implement) usually I do the opposite. I implement the process with everything as "any", and when it's working I begin to define the types and fine tune it.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: