Hacker News new | ask | show | jobs
by mike_hearn 499 days ago
A lot of what you're talking about is open source. Here's the extract method refactoring (Version 2):

https://github.com/JetBrains/intellij-community/tree/44a42be...

As you can see it's not that easy. At the core of an IDE is a database that has to incrementally update itself based on real time edits that can arbitrarily break the datasource (code) that the database is modeling, often in highly confusing ways. Refactorings often require sophisticated data analysis in order to not break code themselves, they aren't simple at all.

The LSP architecture complicates things further by introducing an asynchronous data structure synchronization problem between frontend and backend. Jetbrain's architecture is conventional, with analysis and UI running in-process. They can share data directly and use locks for mutual exclusion. The downside of this is that if locking isn't fine grained enough, or if the GC causes stalls, you can get UI hitches and sluggishness. The upside is that it's a pretty dramatic productivity upgrade because you aren't solving all these hard distributed computing problems that the LSP design introduces.

So the question becomes who solves their problems first? Jetbrains and Oracle have done a ton of work in recent years on solving these problems. Java GC pause times have been driven down aggressively, now there are fully pauseless GCs available although I don't know if IDEA uses them yet. GC pauses haven't been visible for me in years at any rate. And Jetbrains have done lots of work over time to reduce the amount of lock contention that can cause UI stalls, to introduce limited amounts of asynchronous replication within the process and so on.

The thing is, when you're in-process you can use the same ideas as in the LSP to reduce UI latency but to whatever extent makes sense or is necessary in a specific context. Nothing stops you tossing in an actor with a queue if you want that, or introducing a lock if a UI stall is in fact preferable to the alternatives (and sometimes it is). But you aren't bound to it all the time. Whereas the LSP design with separate processes and a hard address space separation doesn't allow that. To add anything you need to extend the protocol and handle the possibility of data skew between frontend and backend, which introduces a lot of surface area for bugs, which then drains time that could be spent on fixing refactoring bugs or adding new static analyses. So it's a hard tradeoff and one isn't clearly a winner to the other.