I asked him how he managed to code, and he replied with something that stayed with me: a good programmer should organize software in such a way that every piece of code has a clear and logical place. The organization should be so intuitive that anyone could build a mental model of the structure and navigate it easily, even without seeing it.
It felt like something out of a Yoda or Mr. Miyagi lesson. Skeptical, I asked his colleagues if he was truly able to code or if he was just exaggerating. To my surprise, they told me not only was he capable, but he was the best programmer they had ever worked with. They said no one else came close to writing code as organized as his.
That conversation changed my perspective. Ever since, whenever I’m unsure where to place new code, I don’t think about DDD or any specific methodology. Instead, I try to follow the logic and structure of the project in a way that feels natural and easy to follow later.
Later in life, I met two other blind programmers and heard similar stories about their ability to produce well-organized code.
To bring this back to the original question: I view LSP/IDE features the same way those programmers view "visual aids." Code should be organized according to a clear and logical structure that makes it easy to navigate.
Relying on features like Ctrl+Click to find where things are located worries me. Why? Because it can mask structural flaws in the codebase. If we can't intuitively figure out where something belongs, that’s a sign the codebase lacks structure—and that should motivate us to refactor it.
Not only do I avoid using LSP features, but I’m also opposed to their use. While they can help with navigation, they may prevent developers from experiencing and addressing the underlying structural issues in their code.
LSP by itself will not prevent anything. LSP (using the terminology from OP, but any IDE really) is just a tool like any other which allows you to do things faster. It doesn't matter how organized your code base is, it will never be as fast to find some definition as hitting a keyboard shortcut (please don't use Ctrl+Click, my gosh... learn the keyboard shortcut for things you do often like this). I want to see docs for a function without moving my eyes from the code I am currently writing. I want to be able to jump back and forth between definitions without interrupting my chain of thought, see function definitions inline instead of having to jump to the file it's defined on.
When you have to manually search for files and then Ctrl+F to find functions, lookup docs in a web browser (which I hear is how people who don't use IDEs still do that), or manually run a linter/compiler to see warnings in your code, you're just being really inefficient. I can't understand that at all. Why don't you use automation to help your job when the whole point of your job is automation?
Keeping the code organized is still good advice, but has nothing to do with using an IDE.
Linting features and autocompletes are nice, also autocomplete features are nice to have.
The issue that I pointed mostly resonates with the idea that depending on LSP is the big issue.
I personally use Neovim with minimal stuff, I run lint and tests manually and not automatically, because it feels to me like push notifications taking my attention elsewhere, so I go to fix them later after what my intention is already expressed in code.
But agree and dyisagree that "Keeping the code organized is still good advice, but has nothing to do with using an IDE.". It should not be based on IDE, but an IDE on the hands of an inexperienced dev may lead to some comfort that should not be there.
I reviewed many code written by junior people, and very often I see people adding code in random places that later may let the application to be hard to follow and everything "seems fine" to them.
Other smell is like, but "it is so easy to rename a variables with my IDE" even though I believe that refactoring is nice to be done, but if we keep changing names so often, why don't we read the code that is being edited to understand well its intention and maybe realized that a big chunk of code should be split and the name choice will be completely distinct once proper refactor is made.
My point is not about avoid automation, is about having a dependency on that because the code is not manageable to people anymore, but manageable by automation mostly.
It's inefficient the first time but you quickly build a working memory and a deeper mental model of the code, which becomes even more useful in the future.
Why don't you use automation to help your job when the whole point of your job is automation?
That sort of thinking will get your job automated out of existence.
I want to be clear, I don't think my workflow is the best, most good, better than everyone else's. But it is mine, and it's the one I'm very proficient and productive with. Vim, tmux, and an assortment of command line tools isn't the right workflow for everybody, but I would argue I'm as, if not more, productive than most people I know using that latest fancy IDE tools.
> Why don't you use automation to help your job when the whole point of your job is automation?
Because I don't see that as automation, I see it as things getting in my way. My brain is set in its ways, and when I try to use tab completion or other nice editing things that people like I feel so slow, I feel like the computer is putting blockers in my way, because I know exactly the line I want to write, and popups and tab-complete break that flow for me.
All power to everyone who can handle that and prefer it, but it's not for me.
I spend comparably little time actually writing the code.
If there is an IDE available that works well out of the box, I'll certainly use whatever automation is available. But often it is broken, incomplete, slow, inaccurate, etc. and rather than spend countless hours fine-tuning some automation / LSP workflow that is going to break when I move to a different project anyway, I just deal with whatever features are missing.
This also has the advantage that I can quickly move to other tools, other languages, other computers, other companies, etc. without requiring days of setup and re-accommodation.
I do have a pretty good memory, which is probably a large part of why this is effective for me.
But I find there to be a world of difference between every keypress being processed as I touch the key versus slightly after it.
With enough experience on a given language you just of internalize a lot of the common linter rules.
I use ctrl-space to activate autocomplete when I need it, but I find when it pops up automatically to be maddening.
I’ve been using AI autocomplete more and more, though it’s a real mixed bag between seeming magical and guessing the completely wrong thing.
The fastest definition is the one you never need to look up.
In the absence of "coding aids" like function lookup, people (are forced to) write code that is inherently better-organized and easier to conceptualize.
To each his own. I use the tools depending on the project. Meaning: most greenfield stuff (even at work) and my personal projects, I can handle with just Vim, a handful terminal tabs---where I grep, run linters (which send out OS notifications), and compile---and a web browser. The main dayjob codebase with all its 10+ years of legacy I wouldn't even dare look at without an IDE.
That said, I find the UX of IntelliSense + autocomplete to be extremely distracting (and don't get me started about Copilot). It's just a necessary evil because, distracted as I am with them, I am simply less productive in the dayjob codebase without it.
Hence, really, your Kung Fu is no better than mine, nor vice versa.
Automation is not the point of programming. Think hard about this. It's the most important point. Code/build/hack to create more work for people to do, not less. It's thanatos. People need to unlearn "programming==automation" before it's too late. Everything we do as programmers should be done with "create more work" as a mantra.
If it's really "just a tool", why so defensive?
Sorry. I know I'm a dick. But come on man, don't pretend the effects of crutches doesn't exist. It's silly to try to deny something so obviously observable all day every day, in all possible contexts not just coding.
I work with someone that navigates the tree structure of all our directories every time they need to look for something. It is painfully slow to watch and if you ask me, they produce fairly spaghetti architecture. Some of that could be a lack of familiarity with the idioms of our platform and its available SDKs.
But I ⌘ click all the time as well as quick-open right to the class, variable or function I need to work with, and I feel like I still organize things better. I’m constantly fixing the weirdness and proposing even more things that should be improved.
You might even get a bit of a Conway’s Law effect by committing unnecessarily to a specific, onerous work style.
Counter example: I’m working with LSP dragging codebase where basic code lint takes 45s. My colleague takes a break after each change so that their code navigation starts working again.
Inefficient people are inefficient.
Not using LSPs isn’t guarantee of efficiency just as using LSP isn’t one. Different strokes for different folks - one has to accept consequences though (more automation means less presence, but it’s everyone’s own choice to make).
When people say "just organize your code well", this isn't something that happens perfectly on the first time, it's something that evolves as the codebase grows. IDE features reduce the barrier to reorganizing as we better understand the problem domain or as the solution grows.
My experience is that those who don't take advantage of their tools produce worse output, even if they believe they are producing better output, the organization they've created only works in their mind and not for their teammates or other people who later inherit the project.
It could be applying DDD or some other pattern with that makes sense to the team.
If you are using a framework like Rails, learn well its conventions, follow them and change what your team likes and made it clear to all team members.
Also learn well SOLID principles and OO (of functional programming, or whatever you are using) and make it obvious that your code fits well your choices.
In other words, if some file (class, template, whatever) should have a single responsability, and by that, it should be obvious where that will be placed.
It has more than one responsability? How you can split it? And once it is splitted, it should be obvious where it should belong as well.
from the parent (i am not the parent)
> I try to follow the logic and structure of the project in a way that feels natural and easy to follow later.
in my own experience it applies to everything in a codebase.
what the end state looks like completely depends on the problem domain at hand, and the tools used to solve the problem.
how to make a codebase “intuitive” is learned, not taught. understand the problem domain, understand the tools in use, then refactor, refactor, refactor, refactor until it makes sense.
> I work with someone that navigates the tree structure of all our directories every time they need to look for something
sounds like they have yet to learn how the code modules are organised.
possibly because the modules are not intuitively organised, possibly because there’s a lot of code, possibly because they just don’t care and don’t mind the mental break of mindlessly looking for the right module.
I don't find it onerous at all. I consider it the same kind of responsibility as writing tests and documentation. And I certainly don't think Conway's Law applies, since for my own projects I'm generally creating deep hierarchical call graphs while being the only person in the "organization".
All these IDE+- things may be nice-to-have but most soon become crutches, and then you cannot live without them, and only walk their walk, not yours.
Just turning off syntax coloring freaks recent developers.. even quite good ones.. i observed it.
Then the trend to pollute untyped-languages' codebases with so-called-"typing" noise, because "it would be IDeditor-friendly" (??) . Form over function, yes..
And another observation from many experiences.. any kind of generated code alienates its users, i.e. programmers. Yet to see how current LLM-ical trend scores in this.. As of last interview, "we need software curators, not programmers"
have fun!
There's a bit of "silly flexing" and projecting here but not entirely without merit. At regular intervals I'll actually turn all my IDE features off just to give myself a refresher. I would imagine that if you took away most IDE syntactical sugar, the vast majority of relatively competent devs could adapt in short order to it.
To me it's the equivalent of using an IME to type Chinese, but occasionally I'll just sit down and physically write the characters on pen/paper. Do I need to do it? Not really, but I enjoy how it forces me into a state of uncomfortableness.
> Then the trend to pollute untyped-languages' codebases with so-called-"typing" noise, because "it would be IDeditor-friendly". Form over function
I honestly have zero idea what you're trying to say here. You mean Typescript or using JSDocs to inform type expectations? What exactly is the issue?
These kinds of arguments get "trot out" all the bloody time. Whatever I grew up with was the most ideal - whatever came after is just a crutch.
For that matter, why are you using a high-level language like Javascript or C#? Don't you know that it's a crutch and gets in the way of true programming understanding? You should be using magnetized needles to etch machine code directly onto disk platters.
Because it really does make code much easier to read and there is absolutely no reason whatsoever to not use it.
Yeah, this is going to be extremely controversial: your so-called untyped language actually has types in, and they're important, but only the program can see them at runtime because you've not written them down anywhere.
The real solution to "repeating myself writing down types" is Hindley-Milner inference, which dates back to 1958, and more languages should use it!
... and?
Cars have automatic chokes, power assisted steering, hydraulic brakes, airbags, seatbelts, auto-dimming mirrors, self-running wipers, and it's fine. People argue that driving a stick-shift is more authentic but even they use syncromesh and clutches, they don't complain about how rubber tyres are for wimps and they use cartwheel-style metal bands wrapped around wood. They don't complain about having a differential instead of fixed drive to the axel.
A plain editor relies on terminals displaying multiple lines and updating them, filesystems for storage, an OS, a keyboard, ASCII or equivalent, maybe virtual memory management and TUIs and "then you can't live without them"! (scream emoji). But so what, it's not a problem, nobody seriously programs on punched cards because they don't want to become dependent on screens and keyboards.
You can make a case that artisan craftsman furniture is better quality than Ikea furniture but that's not because the artisan avoids factory machinery and uses hand tools, it's that the artisan spends more time and effort and takes longer (and needs to charge a lot more money). If you want to make the case that the artisan shouldn't use tape-measures, laser levels, power sanders, power saws, dust masks, wood glue, clamps, they should use a pencil behind the ear, a thumb's width and a handsaw because that's how they learn the True Nature of Wood(tm) then maybe you're just posturing and gatekeeping, or have some sort of Amish-style religion.
Calling power tools 'crutches' is so you can imply that people who use them have disabled themselves. Instead it's like saying people who commute 20 miles to work in a car are using the car as a crutch because you can just walk 5 hours each way and that's more real. It's embarassing that people are so desperately trying to claim both "I don't use power tools because power tools are for weak babies and I'm a STRONG MAN" and in the same breath "my editor can do everything an IDE can do, it isn't inferior, it is a power tool!".
> "Just turning off syntax coloring freaks recent developers.. even quite good ones.."
Just turning off thermometer and oven temperature controls freaks recent cooks ... even quite good ones. Are you going to make the case that restaurants would be better if all cooks worked like your grandma with a log fire who had learned the right feel of heat for bread, cake, or roasts? No? Because that's obviously silly? But what if those developers one day in 2025 find themselves on a monochrome screen, with no shades of gray and no underlines or italics and no option to buy an alternative, hah what then?! Isn't that obviously also silly? NB. you didn't remove paragraphs or punctuation or capital letters from your comment, maybe you're just not a good writer and need these assistive crutches?
I do not rejoice with code bases where every file has no logic or code in it but there are hundreds of methods and files with everything spread out. I have no idea how those projects fit together because the actual logic is spread out.
For my personal side project hobby work it's all in one file.
There are two kind of mazes:
- those that are so tangled up that you can't make out any kind of structure.
- those that are so regular that you can't make out any kind of structure.
Ok, so this is work, but:
find . -name '*.cs' -type f -print0 | wc --files0-from=-
1035617 3438912 47446211 total
Not many editors are comfortable with a million line document that's 47MB. And that doesn't include generated code (which I very rarely need to look at, but is right there under F12 if I do)Cargo cult runneth strong on web.
How many programmers have the luxury to organize the code in the way that exactly suit them? most of the time, I work on code I didn't write myself. In the past, I used to try to refactor but I grew tired of having to justify why it's useful. Nowadays, I just deal with the code the best I can, and LSP is a big help.
- The solo programmer’s code : it’s smart, small, straightforward, does what it needs to do and it benefits from being able to fit in the author’s head but it would be a team’s nightmare, hard to add unanticipated features.
- The team’s code : it’s verbose, full of boilerplate, follows strict programming patterns and rules, is easier to modify/add features. Anyone in the team can add or maintain parts but give it to a solo programmer and it would become a nightmare to just maintain.
For a long time in my career, I opposed the two. Being too straightforward and not strict enough in a team setting is often a recipe for disaster in the long term. In the contrary, being too professional in your solo project is often the way to abandon it.
Being able to write those two types of code is an incredible skill - that I mostly don’t have.
It was a startup environment and hectic, but I had total control over everything, more or less.
Just to say that having the luxury of a greenfield start doesn't mean you'll end up with a nice result.
With 6 other devs on the team and 5 apps our team supports there is no way I get code well organized especially when as a senior I have devops stuff to deal with meetings, explaining features to business, checking up support tickets and random stuff happening all the time.
I don’t know the code base and there is no way to keep up.
While I have to dive in and fix shit ASAP or when I get to code review I have to fix some less experienced guy code. Or write part of code when proposing architecture solution, because just telling people “I am right do it my way” does not work until I write piece of code and then they understand.
Language server and ctrl-click is my bread and butter because that is the fastest way while also going slow enough to understand context.
You should organize your code similarly and with as little fanfare. They are just tools, dont get clever with them. Sometimes, you get too many forks in same holder so you have to divide them but again, common sense prevails.
Everything is “logically organized” am I suppose to remember every method on every class?
The C#, Java, Go and other SDKs are the same (they are all auto generated by the same definition file)
It doesn’t matter how well structured a codebase is, once it gets large, you’re not going to remember every method on every class
So to understand a project, you start at the top and work your way down, you wont encounter anything you haven't come across yet as you go.
Ironically, this 'feature' so annoyed me when I first came across the language in 2015 or so, that I put it down after five minutes and forgot about it for years.
The full comment -
> Oh hey this is me. My typical setup is two terminals: one for vim, one running the compiler and other tools. I just make edits, then invoke the compiler, in a loop. As for finding a definition, most of the time I'm just familiar enough with the code that I know where it is. But when I don't, usually a well designed grep command will do the trick.
> The why: my job involves frequently doing development in environments I don't have much or any control over, and often don't even have Internet access. Over the years, I just learned to work with the basics (vim and a shell) since I can't take my favorite IDE with me to these different environments.
> Additionally, my vim configuration just involves setting up tabs to be 4 spaces and turning on line numbers. Having a complex config just became too much to try to keep in sync across environments.
I'd be interested in more concrete examples of what specifically you're referring to though.
I had a similar conversation with a blind classical guitarist before I ever played, which was echoed by my instructor when I started to learn a few years later. Something along the lines of "If you don't know a piece of music to play it with your eyes closed then you haven't practiced it enough for a performance."
I'm not sure I follow the same idea with not utilizing available tooling in software development, but I do believe that most developers would benefit from intentionally going 'back to basics' and limiting their use every so often and shining a light on what you might think you have a solid grasp of but are actually at the limit of your unassisted capabilities.
We rarely talk about it and it’s also the constant source of teamwork issues. Look, if our code needs structure to be observable, it lacks structure in the first place.
Languages and editing methods — not talking IDEs here, it’s more fundamental — are still “empty file canvas, paint anything” model. That must be stopped.
These structural issues are analogous to malformed xml issues. They should not exist normally. We could start with e.g. better isolation/visibility systems than “files with exports”, then address lack of annotated TOCs for projects and modules. Then replace files with something more database-like. Theeen we could talk about someone breaking a nice structure. Because this structure only exist in a human’s mind, blindness only serving as a bitter “equalizer” to it.
This argument sounds nice in theory but it seems to have some serious fundamental flaws w.r.t. "how do you code without an LSP":
- What do you do about dependent names? i.e. names that resolve to something different based on various conditions in the code? They might be defined in multiple places conditionally, their default definitions might be overridden for particular cases (and you'd have no idea if you just saw the default definition - think "template specialization" if you write C++), they might have different definitions on different platforms... do you seriously want to explore the entire codebase manually with all the compiler flags to figure out what something resolves to?
- What do you do about code that you can't refactor? Like third party code?
- Not every question the IDE/LSP answers is of the form "where does this belong". What do you do about things that aren't names? Like say, there's a quantity calculated at compile time and want to know its value? I'm not talking Math.PI here, I'm talking about something like STACK_BUFFER_SIZE. It can easily be something like (sizeof(T) + sizeof(U) * 4) / sizeof(void*). How much of your life do you want to spend simulating the compiler in your brain vs. having it just tell you what it already knows?
etc.
> Well written, clean code is amazing. It is also an issue because the second features or specs change, you have to undo/redo the work you just did! Further complicating things are two other real-world concerns:
> 1) Looming deadlines might make the time needed to express "best organized" code to either be executed suboptimaly, or outright incongruities, leading to confusion due to parts A, B, and D being expressed very well, but C, and E-J are left looking wonky.
> 2) It can foster a "Don't touch" mentality. "Oh, Bob (the pro) wrote that! Better not mess with it. I'll work around it with a hack-y solution." Basically it's a suggestion that, "In order to write very well organized code, you have to be an excellent programmer. So what do you do if you work with subpar to average programmers?" It would almost seem to suggest that by writing well organized code, you are giving yourself even more work, because it is intimidating or too daunting to other programmers who aren't at that same level.
I'm not sure how much I agree with those points, myself. I kind of feel like they are a cop-out, a kind of excuse to go with less thought out designs. I do see, however, that as far as real world situations are concerned, managers and even fellow programmers might prefer "good enough" to be done with it. I'm not really sure what to make of it, but it does seem to make a kind of sense.