Hacker News new | past | comments | ask | show | jobs | submit login
How we failed, then succeeded, at migrating to TypeScript (heap.io)
69 points by drob on Oct 13, 2019 | hide | past | favorite | 57 comments



I was looking at some of my old repos today. Enjoyed the nostalgia. Lots of CoffeeScript there. I had to switch to ES and then TypeScript because CoffeeScript was abandoned at the time and I was stretched over other projects to be able to help maintain it.

Reading my old code, I was surprised by how clean it looks. How easy it is to digest. There is a certain sense of calm when your brain doesn't have to process all the visual clutter of a C-style syntax. I miss that.

I wish I didn't have to choose between CoffeeScript and TypeScript.

TypeScript first and foremost is about type safety and tooling. Its architecture is largely syntax-agnostic. It operates on the AST, so the parser and code generator can be swapped for a different syntax.

CoffeeScript is all about syntax and does not (and should not) concern itself with most of the semantics.

They could theoretically be used together if TypeScript simply allowed custom parsers/generators/formatters to be plugged in.

This would work with ESLint and other JS tooling as well. I did a POC on that a few years ago [0].

[0] https://github.com/gkz/LiveScript/issues/821#issuecomment-18...


> How easy it is to digest

I’ve not had this experience. I’ve found the ambiguity in coffeescript a maddening adventure in syntax confusion.

- function call syntax doesn’t need parens except if a 0 parameter method

- commas are largely optional both in arrays and function parameters. How do you parse: [f, f(), f a b c]

- implicit returns are a terrible idea.

- the @ syntax refers to either a ‘static’ method or an instance variable depending on the context.

- I have to do a double take for the object literal syntax every time


Don't want to invalidate your experience. For me though, I rarely struggled with ambiguity.

> function call syntax doesn’t need parens except if a 0 parameter method

Function call syntax doesn't require parens so to make multi-line calls punctuation-free. Especially if some args are objects.

> commas are largely optional both in arrays and function parameters. How do you parse: [f, f(), f a b c]

Well commas are not optional.

> implicit returns are a terrible idea

They're especially elegant in writing declarative code. It takes some getting used to though.

> the @ syntax refers to either a ‘static’ method or an instance variable depending on the context.

Agreed.

These are all tradeoffs though. For me, they struck the right balance between ambiguity (very little) and expressiveness.

LiveScript in comparison was much more sugary (which I preferred): https://livescript.net/


Haha, yes. LiveScript should have won. It were awesome times.

Well, guess it's Reason for me now :D


My experience was that I always found my CoffeeScript really easy to read since I was always internally consistent with which opinional bits I used and which bits I ignored.

Reading other people's CoffeeScript on the other hand...


I was very excited about CS when I learned about it, and in my initial tests found it really pleasant to write. However, before committing to using it more, I went and read some other projects written in it. At that point I decided that the reading experience was confusing, and the lack of "visible" syntax elements to guide me drove me nuts.


Don't forget fat arrow vs. thin arrow. If you're not writing Coffeescript 24/7 you start to forget which is which.


You just gave me an idea.. because we've shared a similar experience.

I really miss the elegance of Coffeescript. ES6 is great, Typescript is great, but sometimes I feel like I have to visually parse a lot of static cruft to read the essence of the program.

What if one's editor had a toggle hotkey to hide typescript typings. Maybe you could turn it off to visually parse the program real quick, before turning it back on to edit it.

Hmm...


You're getting in the realm of "projectional editing." It's a fascinating idea: https://news.ycombinator.com/item?id=15534555


Yep. You can take MPS today and implement an AST projection that looks like whatever you want. No parsing involved, impossible to even write syntactically invalid code (since it is not code you're writing, but an AST projection).


I love reading about stuff like this, thanks for sharing. Developer UX still has a lot of room to grow.


Interesting. I sometimes wish to only see the types and get rid of the rest.


What about instead maintaining the type definitions in a separate file, and then having the editor add in the type hinting?


TypeScript is so syntax heavy. But my perspective is that there are costs incurred at time of development and maintenance in return for stability at runtime. And I think the latter is far more important if you're writing production code.

When it comes to experimentation, I love Javascript and Python because of how fast they are to write when you're not thinking hard about types.

Then it's just discipline to know how to promote experiments to production code. TypeScript is beautiful because you can just turn it on and add them in. Same with Python type hints.


If you want the quiet syntax of CoffeeScript and even better type safety than TypeScript, you might be interested in Elm.

https://guide.elm-lang.org/


I love Elm. Never got to use it in production though. Can't afford to get even further from the metal :)


Elm is not compatible with js library or at least it's not seamless.


Yeah well, sometimes js library isn’t compatible with js library either


CS is what happens when you let Ruby devs write JS.

TS is what happens when you let .net devs write JS.

Let's see how that turns out in the long run.


The most depressing thing for me as someone who loves F# is how `.net` is nearly synonymous with C# in most people's minds


I have the feeling Reason has more in common with F# than TypeScript, haha.


> Reading my old code, I was surprised by how clean it looks. How easy it is to digest. There is a certain sense of calm when your brain doesn't have to process all the visual clutter of a C-style syntax. I miss that.

Indeed, Coffeescript is one of the finest languages I wrote in. Consider that 95% of the time we are reading code, what is the win of TS with a linter? The TS codebases I've worked on really hurt my eyes and brain, and that for some stupid website where type safety hardly makes any difference at all. And all those average web developers I've worked with bragging about type safety while the code they are producing is full of wrong constructs, bad naming, dependent on heavy tooling, etc..


> The most important realisation we had going into this renewed effort was that a successful migration has to be centered around people, not just tech.

Key insight. It’s always people first, code is a far distant second. Love Kent Beck’s series on this, so insightful https://medium.com/@kentbeck_7670/software-design-is-human-r...

Great read, Heap team! Thanks for sharing :-D


I routinely bore people with the Abelson quote that programs are written for humans to read and only incidentally for computers to execute.


> It’s always people first, code is a far distant second.

I'm afraid that's kinda political. In order to get the migration successful, hmm.. I assume developers did not have much of a choice, either accept it or leave. You can try to brainwash them by impose your subjective point of view in a friendly way, but in the end it's all about power, that's the untold story.


Typescript seems to be approaching C++ levels of syntax and expressiveness. The main difference seems to be the existing tooling, tutorials, libraries, etc for node.js and others.

But if compiled languages like C++ or Go had as many dedicated libraries for webserver management as JavaScript, would there really be a benefit to using Typescript?


> Typescript seems to be approaching C++ levels of syntax

I've been a bit traumatized by C++ so I can't help but see this as a bad thing.

A lot of the insanity in C++ is because template metaprogramming made a lot of micro-optimizations possible. You can use CRTP to achieve static polymorphism. You can use SFINAE for tag dispatch to choose a different algorithm at compile time. You can even fold entire algorithms down to a constant with constexpr.

This is great if you care about low level control of your code, but this is usually premature optimization in the JS world.

Luckily typescript will be immune to this because the types can't affect runtime at all. So far I haven't seen any truly monstrous generics that are so prevalent in C++.


There's some Typescript type stuff that can probably get close.

https://stackoverflow.com/a/47914631/1924257

https://stackoverflow.com/a/53229857/1924257


I don't agree - the TypeScript code you link is "complicated" because it's modeling complicated types, or implementing higher-order types which need to handle complicated types. And honestly it's not that complicated - an explanation of what RecursivePartial must do maps closely to the type expression ("each key of the partial type is optional, and each value's keys are also recursively so").

This isn't at all close to CRTP or SFINAE, not just because TS/JS lacks the dispatch features necessary, but because in both cases you link it's still just about type declaration. CRTP and SFINAE are both ways to hack the type system to _run_ differently.


Yes, build times of a few seconds instead of minutes. Easier and more robust "write once, run everywhere". Integrating third party libraries in a matter of minutes instead of hours, sometimes days. Generally much faster prototyping capabilities. And so on.


Short build times come with less compile time checking.

You can get cpp programs down to seconds for incremental builds with good management while having compile time checking.


Yes, because you can't run C++ in the client, while some Node libraries can now use the same code for pre-rendering pages on the server or rendering new pages on the client. This gets you the best of both worlds, where a first load or refresh has the page content baked in like a traditional static site, but once it loads you get faster naetvigation and live content updates.

(WASM and WAPI might eventually let you run WASM-compiled C++ in the client, but there's still a lot up in the air for interop purposes there.)


We’re now considering switching from coffeescript to ES6 (or maybe also Typescript). But coffeescript is seeing a bit of a revival, and I’m starting to wonder if we should stick with it?? Tooling seems a bit behind and also lacking things like tree shaking etc (??). But coffeescript is so clean and fun...

Any tips/thoughts??


YMMV, but I’m less worried about “clean and fun” and much more worried about rugged and correct. TypeScript makes it easier to unambiguously express intent both inside an application and when talking to external modules. Some parts of the syntax are unfortunate but I care about that a lot less than I do not having my systems break.

I’d switch and I wouldn’t look back. I did switch my focus of learning and use, albeit from Ruby and Kotlin (which is better than nothing but nominative typing is insufficient IMO) to TypeScript, and it was among the best decisions I’ve made in my professional career.


What do you think about nominal typing vs structural typing? My friends that have been only used to statically typed, nominal programming languages, thinks this is the worst feature of TypeScript.


I don’t hate nominative typing but TypeScript has definitely coached me towards thinking more about data and operations on data. It does a lot to encourage you to move away from the traditional OOP patterns that make most people dunk on Java.

If I had to directly compare the two I think nominative typing is superior only in the case where you have two identically-shaped (down to the property name) classes that have different semantics. I feel like if you are in this situation you should take a very large step back and re-think your decisions.


Why do you say "But coffeescript is seeing a bit of a revival"? Many metrics (such as https://github.com/jashkenas/coffeescript/graphs/contributor...) suggest otherwise...

I've written an enormous amount of code in CoffeeScript since 2013, but have been migrating it to Typescript during the last year, after it became very clear that CoffeeScript is a dead end. One thing that helps a lot with all the braces (instead of whitespace) is using prettier. My editor is heavily integrated with prettier, so with the touch of a key my code is always formatted in some (almost) canonical way.


Depends on your team size. 5+ engineers and need to refactor things? Typescript will make those needs far easier. Tooling support is amazing, for things like autocomplete, module import insertion and sorting, symbol renaming, function extraction, linting capabilities, correctness of code after changing designs.

There’s some learning around how to type things, but not too hard and very worth it. Need at least one teammate / leader who has used c++/java/c#/etc. extensively on large codebases to mentor others.

Teams of one, es6 is fine, typescript setup is probably overkill, especially for an mvp.


Dunno about you, but I do all of the things you mentioned, regularly, on a solo project. My test burden is greatly shrunken (getting rid of all those “did I pass sane args?” tests that one needs between modules) and I have much more confidence that I’m not shipping broken stuff.

I don’t think writing TypeScript actually takes longer once you’re practiced and it eliminates entire categories of error. YMMV, of course, but in 2019 it’s hard for me not to think of a new JavaScript project as somewhat unserious.


I agree, it doesn’t take me personally any longer to write typescript. In fact, it saves me tons of time and endless headaches. I _love_ typescript and use it at work in react and have used it in node for side projects. The benefits are incredible as you mentioned!

I guess it depends on what you’re doing. Setting up the tooling can sometimes be a bit of a pain in combination with other tools which are not designed with typescript in mind from the get go, such as react_on_rails.

If you’re doing a quick mvp in a weekend, I’m still not sure typescript is right. But it really depends on what other tools you are using and how well they integrate. If the mvp works, ya, definitely switch to typescript ASAP. That’s a fine line and really depends on the use case.


For me the scale tips heavily towards type safety and tooling of TypeScript. Then again, I wish we didn't have to choose.


What would you say are the most useful features of coffeescript?


It's one and only useful feature compared to ES/TS is the syntax. Once you get used to it, which doesn't take long, you start to experience that in comparison to say ES6, you:

- Write/edit code faster - Read/understand code easier

People say this is subjective, but my experience with other developers has shown otherwise. I once asked a team of developers to "just go along with CoffeeScript for 2 weeks" instead of arguing its syntactic decisions (they were developers who had only used C-style syntax languages in the past like Java/C++/JavaScript). All of them ended up loving CoffeeScript and staying with it for years.

Mind you, TypeScript was a very different language back then. Once it started adding features like disjoint unions and the tooling matured, I made the switch.


If you've learned to appreciate the elegance, expressive power, readability and overall speed of development of Coffeescript, tell me, are you going to drop that for some virtual type safety that doesn't even exist at runtime? There's no way you'll write a medium to large codebase in TS without the use of 'any' or 'undefined', otherwise you'll get completely stuck. Don't believe the hype.

When you are not writing critical code where lives or huge amounts of money depend on, then I'd say stick to Coffeescript. And when you find a type related bug in your code, fix it and write a test so the bug cannot occur again. Otherwise, first check out Elm, Dart and Livescript. TS is really the last on my list, I've had my share of pain there.


AFAIK, Ruby is the only language that people make other languages look like (CoffeeScript) and JS is the only language that people make look like other languages (CS, TS).

Are there others?

Edit: Well, I guess the JVM would be considered another?


Lisps exist on all the runtimes. LFE (liso flavored Erlang) is a good example.


Don't forget Hy and Clojure (which pop to mind, but I don't intend to be exhaustive).


Yes, we were adding TypeScript code, but we were adding CoffeeScript at a faster rate

So the devs were able to iterate faster with CS than with TS?


Another interpretation would be that a majority still picked Coffeescript out of familiarity and interop issues in their specific codebase. Iteration speed could be comparable or better in Typescript too, we don't know.


Often the reason is as simple as "This file I'm adding to is in coffeescript and I don't want to convert it right now"


[flagged]


Hey, the reason I downvoted you here was that you is that you basically just quoted parts from the article and simply added dismissals or small jabs, but little truly constructive, and were kinda rude in the last paragraph. Judging by your other posts you can do better than the easy way out. Do you have something constructively critical instead?


So tell me what's constructive in your comment? Oh, and downvoting is about the least constructive you can go, I won't downvote you :)

Tell me honestly, what point I made you don't agree on? Try to make your point please.


We've banned this account for breaking the site guidelines. If you don't want to be banned, you're welcome to email hn@ycombinator.com and give us reason to believe that you'll follow the rules in the future.

https://news.ycombinator.com/newsguidelines.html


It would definitely help if you tell me which rule I broke that made you ban this throw away account in the first place. Without that I think it's more convenient for me to create a new account instead of sending an email as you suggest.


Flamewar comments and snark and crossing into personal attack. Example: https://news.ycombinator.com/item?id=21242827.

If you'll commit to not doing those things and to following all the guidelines (most importantly this one: Be kind) when posting here, we'll be happy to unban you.


Thank you for your reply.

My comment was indeed a little edgy, I have my reasons for that. But the intent was not a personal attack, although I now see that some of the words used were indeed on that edge.

I see in the history of your comments that it is not normal for you to ban an account just right away without any warning. I have no clue why you made this exception for me, I see much worse around on HN. My account was never blocked btw, it's still working. Feel free to try to block it again if you wish so, I won't use it anymore anyways.

I truly hoped I was able to shed a light on things many people normally don't see, the intent was positive but apparently I failed to do so rightly. I am human and cannot promise to always be kind. Therefore this better concludes my contribution to HN. Wishing you all the best.


Harsh, but true. I like your point of view. We often get sucked into latest trendy rabbit hole, where there isn’t much actual value delivered to your business/employer, other than feeding your ego and tinkering desires.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: