15 ms·
What I have changed my mind about in software development
- 0x445442 3y agoUnit testing private methods via public interfaces is accidental testing and leads to overly complex and brittle test code. The author’s first instincts were correct here.
- IshKebab 3y agoI agree. It's also not always possible to sufficiently stimulate a private function using public methods. He was right to change his mind about the other things. I was also skeptical about remote working, and while I think it is worse in most ways than office working, it's not a lot worse, and the lack of commute is sooo big a benefit that overall it's totally viable.
- isityouyesitsme 3y agoExactly. I worked in a place that disallowed friend functions and classes generally, but explicitly for unit testing. I never wrote another private function. Instead, there was an explosion at the tiny-free-function-that-could-have-been-a-private-function factory, and the parts ended up everywhere.
- SoftTalker 3y agoHow is it accidental? The code can only do what its public interfaces expose. This indirectly (not accidentally) exercises the private methods. If all the public interface test cases pass, isn't that enough?
- isityouyesitsme 3y agoWhether or not it is enough depends on the context. Some cases require 100% condition and decision coverage. In these cases, it gets to be very difficult to achieve that unless you are directly testing the functions you write, not through a caller. But even deeper, it is "accidental" because you are not testing contracts on the public APIs, you're testing the private functions through a layer higher. When the implementation changes, you have coupled your tests so tightly to the implementation that they are useless for regression testing. If not, then you actually aren't testing the private function at all, you're just hitting some parts by coincidence.
- mvdtnz 3y agoI don't necessarily agree, I think it's situational but I think that the dev community as a group has swung too far to the "only test public interfaces" side lately. It ignores some important realities in favour of ideological purity. Sometimes there are well-defined processes for performing a task, and that task is performed in only one place in the system. Therefore the details of the process can be kept class private inside of the only consumer. That doesn't mean that the processes should never be tested. If the task is cumbersome to set up or runs slowly then there is good reason to test the internal parts of the process which can be tested with dozens, hundreds or even thousands of permutations of input data cheaply and efficiently. Always relying on the large-scale tests to hit every combination of inputs for a well understood subroutine can be inefficient. You could make the argument that this well-understood process could be broken out into its own class/package/module and tested with its own public interface, but if there really is only one consumer then that's kind of a strange trade-off to make in many cases.
- 0x445442 3y agoIn the vast majority of cases, The Enterprise, private methods are little to no use anyway. Whenever I’m faced with updating a code base that has Draconian code coverage metrics in place I’m more apt to make a private method public than futz around trying to figure out mock magic to test the change
- Joky 3y ago> You could make the argument that this well-understood process could be broken out into its own class/package/module and tested with its own public interface, but if there really is only one consumer then that's kind of a strange trade-off to make in many cases. That's how I develop in general: a "component" does not exist because it has multiple-clients, but because it is a conceptual piece of logic that makes sense to document and test in isolation. It allows to define what is the public API of this component and what isn't. This is how software scales and stays maintainable over time IMO.
- mvdtnz 3y agoI don't disagree, I'm just saying it's situational. The trade-off doesn't always make sense. But I typically develop in much the same way as you do.
- 0x445442 3y agoThere are a number of issues. First, the fundamental unit under test is the method/function, not the entire call stack. Second, complexity starts to grow when there are code coverage gates in place. When I see tests that are orders of magnitude larger than the units they’re testing and contain mocked references that are used 7 stack frames deep I know the author had a fundamental misunderstanding of how to write helpful and maintainable tests.
- jcpst 3y agoThis perspective is really interesting to me. I’d be interested in knowing what people find problematic with it. I used to unit test all the components individually. But these days I test with most of the componentry wired up, only mocking the i/o layers. I end up writing fewer tests, they have been less brittle, and refactoring is easier.
- 0x445442 3y agoIf you want to expose issues in a code base’s architecture, don’t allow mocking frameworks and see how complex and lengthy unit tests become.
- pc86 3y agoYes if you eliminate an entire class of testing infrastructure, tests become harder to write because you end up poorly implementing that infrastructure in every class. How does this show you "issues in the code base's architecture?"
- 0x445442 3y agoWhen code is written to interfaces those interfaces can be mocked without mocking frameworks. Mocking frameworks mask poorly structured code.
- piva00 3y agoThen you have to reimplement method call count when you need to assert something was called in your interface-based mock; and reimplement differing returns based on input or call count; and maybe reimplement throwing exceptions when those are necessary to test not-so-happy paths. In the end you'll have an implementation of the interface with quite complex logic in the methods' implementation to handle differing returns, which will couple your mock implementation to the test cases setup, or you'll reimplement a mocking framework. I prefer to use a mocking framework to deliver stuff instead of stabbing myself to keep purity of interface-based APIs.
- 3y ago
- waynesonfire 3y agoif your private methods are complicated enough that you're not able to achieve sufficient coverage through public interfaces it's time to refactor. make the private code a library that you can test in isolation.
- BeetleB 3y agoThis. When I did C++ programming, I would test via public interfaces. If it didn't seem sufficient, or got messy, the reason would always be "This is a big class that is doing a lot of stuff." I would then identify all the things the class was doing, make classes for each one, and have instances of them in the original class as private members. This way I could test the individual classes easily, and still test the (formerly) big class using only the public interface (with appropriate mocking as needed). The main thing I learned from unit testing is to pay little attention to the word unit. Insisting on testing the private methods after the exercise above is usually a symptom of aiming for a level of intellectual purity that does not benefit the code. (Of course, a better solution may be not to use OO to begin with, but that's a whole other discussion).
- wvenable 3y agoTests freeze code and design. Often this is exactly what you want but sometimes it's not what you want at all. If your internal interfaces are unit tested then you can't refactor easily because you'll break all your tests. However, if only your external interface is unit tested then those tests actively benefit refactoring the internals.
- jcpst 3y agoIt would be interesting to know how long the author has been developing software. For me, this is the kind of stuff I questioned in my first few years. After I productionalized a few real world systems for a business, the whole “dev street cred” thing lost it’s appeal. It wasn’t about some imaginary “dev purity” thing anymore, it was about being efficient and making sure I was contributing to the bottom line.
- SoftTalker 3y agoMaybe. I have been developing for over 30 years. I still use emacs, use logs and printf for debugging, and have never even looked at ChatGPT. I'm willing to admit I may be set in my ways but I get my work done.
- jcpst 3y agoGood point. They’re all just tools and patterns. The actual tools used _could_ save some time, but experience plus the capacity to reason about software is a bigger deal. The article just made me think of some devs that I’ve worked with that were obsessed with particular tooling (insert comment about a hammer and everything being a nail). I do keep an eye on emacs. It turned into mainly my org-mode editor, but the v29 article that hit the HN front page recently has me curious about trying more dev work with it.
- Turskarama 3y agoIt might be possible to do anything with a chisel that you can do with a CNC machine, but that doesn't in any way mean either choice is as reasonable as the other. I just can't see a genuine reason to not use a real IDE and debugger. You can even fall back on the same tools you had before with them! Using a debugger doesn't mean you can't also use print statements, but if I could only have one I'd pick the debugger every time.
- jiggawatts 3y agoNearly 40 years here — I exclusively use IDEs and debuggers and have done so since the early 1990s. Computers aren’t digital pencil and paper. They’re levers for the mind. If the 3 GHz processor just sits there idling, waiting patiently to copy some bytes from one buffer to another, it’s being wasted. It could be checking the syntax, looking up documentation, or chasing memory references in the debugger so I don’t have to.
- mplewis 3y agoI wish that my programming languages had a "public for testing only" scope. Despite the rigorous arguments of the Properly Factor Your Public API crew, I still find myself in real-world situations with functions that should not reasonably be used outside of the module, but that I still find valuable to cover with unit tests.
- wavemode 3y agoC++ has "friend" classes, a quirky feature I've never seen in another language. But which solves this very problem.
- sanderjd 3y agoIt's not much different that package-private (the default visibility in java).
- brabel 3y agoWe use package-private and @VisibleForTesting (I forget which library provides that now) for these cases.
- sanderjd 3y ago@VisibleForTesting is mostly documentation; you can just as easily use package private without an annotation. (Though yeah, I think it's good to use the annotation anyway.)
- mvdtnz 3y agoThis exists (in kind of a hacky way) in C# with the ExternalsVisibleTo attribute. It exposes methods and classes only to specified assemblies (like your unit test assemblies). https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.internalsvisibletoattribute?view=net-7.0 https://learn.microsoft.com/en-us/dotnet/api/system.runtime....
- 3y ago
- 29athrowaway 3y agoWith IntelliJ, spellchecker + linter + static analysis + duplicate code detection + etc = basic quality as opt out feature VS Code and other setups make those opt in. Meaning, when you see a bunch of typos and really poorly written code you know it is from one of the DIY setup people. So then you have to move all those checks to the next stages like SCM hooks and CI.
- guideamigo_com 3y agoExactly. And since you can't force people to setup IDE properly, automatically enforce them with CI.
- Lio 3y agoThe flip side of this, the only times I've run into projects without external build tools, protective githooks or even .editorconfig, it was set up by an JetBrains family dev using the IDE as part of the build process. Having to start a heavy, proprietary IDE to build code and other assets is a royal pain in the hole.
- deergomoo 3y agoI’ve never understood why anyone would choose to debug by printing and logging if they have a good debugger available to them. My day job is mostly PHP (yeah yeah, I know) and the general attitude towards Xdebug in the community seems to lie somewhere between apathy and active avoidance. To me, a debugger is such an invaluable tool not only for identification of bugs but also for familiarising oneself with new code. The value of being able to not only trace execution from start to finish but also to modify state in a running program is immense, and gives me a small taste of what Lisp folks rave about. Littering print statements everywhere feels like banging rocks together when there’s a perfectly good lighter in your pocket.
- Topgamer7 3y agoHaving good log statements about what is being called with what value is invaluable when running a server and using log output to investigate issues.
- accoil 3y agoThey also let you troubleshoot a problem after it has happened. Logs can give information about the trigger, which the debugger can't do as it requires you to known what inputs caused the issue.
- deleted 3y ago[deleted]
- Hermitian909 3y agoOne of the great UX features of printing is that it is a quick way to have an auditable form of state over time. I look at states 1-n, compare and contrast, which my debuggers don't make as easy. I'd add many people don't work in languages with good debuggers. I work in TS and the debugging async node code is an absolutely garbage experience in many cases.
- smusamashah 3y agoCan you please explain how does debugger can help in cases where you can't wait too long on a breakpoint because some thread or service waiting on it will fail? I do this many times at work in Java with intellij. I do fine with breakpoints most of the times but sometimes print statements is the only way to trace the thing. From your comment I feel like I am missing better ways to debug.
- pc86 3y agoOverall a pretty good article, however I do feel like the author misses the mark on a couple points. > Unit testing private methods. As someone else pointed out this leads to accidental testing. I'm not a test zealot, I think 100% coverage is a fool's errand, and I think TDD is an abomination, but well-structured, well-thought-out tests can be a game changer when used appropriately. Testing things by accident has inevitably lead me to finishing some piece of work then spending half a day or more tracking down why some test failed inexplicably. > Using an IDE. I think a better point here is to get really good with whatever tool you use. If you know every incantation in vim you're going to be amazingly productive. If you know every keyboard shortcut in IntelliJ you'll be as effective, but probably not much more. The person who knows vim or emacs in and out will beat the person clicking around in an IDE every day of the week. That being said some of it is spot on in my admittedly limited experience (only about 13 years or so, in a handful of industries, never FAANG-level scale). The point about commenting problem areas in the domain has really changed my approach to comments. I don't write any comments about what the code is doing unless it's a "here be dragons, don't change $X unless you're free the rest of the week" kind of warnings. But I comment extensively why the business or regulation requires A or B to happen instead of the more straightforward C. The ChatGPT bit as well matches my experience. For well-defined things where it's hard for ChatGPT to make the answer up, and easy for you to verify if it does (or at least low-damage), it's worth the $20/mo IMO. I tried using it to learn CDK and while I'm not sure it saved me any time, it did save me from having to trawl through AWS documentation.
- randomdata 3y ago> I think TDD is an abomination I'm intrigued. TDD may bring way more pomp and circumstance than it deserves, but when you get right down to it all it says is: 1. Write a test first so that its failure state is proven. 2. Test behaviour, not implementation. I have certainly been caught in haste writing a test after the fact, messing it up – in a way that saw it pass, and then later realized that it wasn't actually testing anything. #1 solves a real problem. Which must mean the abomination is the behaviour testing? Do you really care about the implementation, though? Surely that can be considered throwaway? You are not going to gain anything asserting that you used bubble sort and have that assertion fail when you update your code to use quick sort.
- AnimalMuppet 3y agoDebugging by printf is useful in a bunch of places. Debugging via debugger is useful in a bunch of places. Why would I limit myself to only one? (Doesn't matter which one; why would I limit myself?)
- bryanlarsen 3y agoIt's weird to see Emacs lumped in with VI in the editor wars rather than being thought of as an IDE. Emacs is the ultimate and original integrated development environment. The joke is that Emacs users have integrated everything into Emacs, so much so that Emacs is the OS. That's one of the main reasons I picked up Emacs back in the day -- it provided a nice integration with gdb.
- lawn 3y agoFunny enough, Neovim har great LSP and gdb support. The distinction between an IDE and a text editor now mainly comes down to the configuration time, where both (neo)vim and Emacs support the classical IDE features as long as you configure them to.
- bryanlarsen 3y agoWhen I adopted emacs, vim itself was new, neovim was still two decades away. :)
- deleted 3y ago[deleted]
- AceJohnny2 3y ago> Using an IDE [is great, in particular for navigating the codebase] As a longtime and ongoing Emacs user... I have to agree. Sure, Emacs Can Do It [tm?], but having to setup the appropriate tag system, and ensuring it's kept up-to-date with the codebase is a pain. For example, our codebase is embedded C with #ifdefs depending on which target we're building from. This means that a naive, cscope(regex)-like search will get confused about which is the proper definition for the active target... when it even can find a definition (it's shocking how often it fails for no clear reason). So I turned to RTags, which meant having to generate compile-commands.json, which... I'll stop here. Suffice to say setup wasn't trivial, and for some reason it eventually broke and I never bothered again. Rinse and repeat for every other language.
- PhilipRoman 3y agoInteresting, I have the opposite experience. Ctags are resilient in face of missing headers, source code preprocessing, syntax errors etc. VSCode usually just gives up. At one point I even had to install the Ctags plugin for VSCode...
- throwaway290 3y agoYep. And in case of a big project LSP requires at least all dependencies properly installed right on the machine where you write code. Upgraded OS and something is incompatible for a while? You get no hints now, hope you're not in rush because you'll be running full build to discover your typos. And especially good luck should you want to use LSP on two different projects that require different versions of the same dependency...
- dpc_01234 3y agoWait, what? Tagging system? What is it? 2015? Doesn't emacs have a good LSP support by now? Nowadays with the popularity of treesitter and LSP even small-community command line text editors can have most of what IDEs do built-in.
- a1o 3y ago
- JohnBooty 3y agoOver the years I have realized that some comments are needed and useful. These days I add comments when there is something particularly tricky, either with the implementation, or in the domain. Ah, yes. Another convert. There are dozens of us. Dozens!! Nothing makes me feel crazier than trying to get fellow engineers to comment their code. Code alone can only tell you the "what." If the "why" is not obvious, comment it. Unit testing private methods. I am always dismayed by engineers who vote a hard and unyielding "no" on this issue. I guess ideally your private methods should not be tested directly. If you work at an ideal shop doing ideal things under ideal conditions, please let me know if you are hiring. In all or most of these cases the tests for private code will hopefully be somewhat temporary; perhaps think of them as scaffolding used during construction or renovation. - For example, perhaps you have a good reason to write the private methods first and you would like to make sure they are sound before proceeding. - Perhaps you have a division of labor due to a time crunch and you are writing the private methods while somebody simultaneously writes the public methods. - Perhaps you are encountering some thorny preexisting code with no test coverage and you would like to just make sure things work. - Perhaps the public methods are undergoing a lot of flux and you would like to make sure the private methods do not suffer regressions during this flux - Sometimes it's just easier to test private methods directly rather than indirectly via a public interface. Maybe this is a code smell, but also maybe you don't have time for a full refactor.
- mkoryak 3y agoIf you don't have time to write good tests, maybe consider not writing any tests. I've worked for many a startup where we didn't have any tests because we rewrote everything every few months. And that was ok because everyone was happy to have a lot of shit written fast. I guess maybe what I'm trying to say is that shitty tests are sometimes worse than no tests.
- JohnBooty 3y agoI don't agree that private method tests are shitty. However, I do agree that maybe there is a time during which it's OK to just not have tests. If you are just spitballing it, prototyping, code jamming, maybe even blasting out an MVP for alpha or beta testers. Sure. Part of mastering a craft is making reasoned decisions about breaking rules.
- andrewstuart 3y ago>> I used to think that the names of the classes, methods and variables should be enough to understand what the program does. No comments should be needed. Over the years I have realized that some comments are needed and useful. Comments are needed where there is more to the code than just reading it. Where there is some external reason WHY. Where it is written in a specific way for non-obvious reasons. Where there are pitfalls and dangers in changing the code. Where this specific approach is the result of fixing some problem and if you change it then you might be reintroducing a problem. There's lots of reasons to comment your code, but mostly I think code should be the documentation. The fewer comments the better, because then developers who come later will see comments and thing "this must be important because there is a comment here". Too many comments dilutes the value of comments. When it really matters I start my comment with a couple of lines like this: // LISTEN UP!!! // LISTEN UP!!! I have to say, it seems strange that the author EVER thought that no comments should ever be needed - that seems like a strange and dogmatic conclusion to have come to.
- ajmurmann 3y agoAnother way to address some of the reasons for comments you call out so well, is clear tests for these edge cases or weird, past problems.
- throwaway290 3y agoYou self-contradict with: > it seems strange that the author EVER thought that no comments should ever be needed - that seems like a strange and dogmatic conclusion to have come to. But just before that you say: > There's lots of reasons to comment your code, but mostly I think code should be the documentation. Exactly that's why it's not at all strange. As you yourself write, code should be the documentation. Need to add comments => your code is unclear, and unclear code => bad code, and so instead of writing comments your time is better spent improving the code. The reality of course is that things need to be done and there's no time to fix all layers and have perfectly organized and readable code and therefore clarifying comments are needed. So no need to shame the author, it's just a typical progression from youthful maximalism to more mature shades of grey thinking.
- zimpenfish 3y ago
- xlii 3y agoIDEs are a deep topic but I don't hold such absolute. For some languages using commercial IDEs is a very smart choice. Refactoring TypeScipt, for example, with Jetbrains IDE is a breeze, and I think it should be available in developers toolkit whatever their preference is. For some, more dynamic/niche languages (Hello Elixir!), IDEs stand in a way because they take longer to set up and they still don’t produce results as good as glued together scripts and editor macros (side note: macros aren’t only for inserting text, one can pick text under cursor and search for a specific pattern using rg or even send refresh signal to a browser on the other screen). There are also two other layers that I always mention as arguments against IDEs. First is that IDEs change often and no matter how much you try your workflows are going to change. It’s hard to get high proficiency when things are changing and having new IDE feature replacing Your Way is a pain and a learning deterrent (thing that I experienced multiple times). Second is something I call GPS Development. When I work with IDE I tend to not pay attention where am I and where I should be going because hopping navigation is super easy. And then when I am deprived of those tools I’m completely lost and not productive at all. With arguably dumber tools I can open shell and still navigate and edit with whatever editor I have and it still works well. Thing is that with my line of work stuff breaks often and IDEs rightfully decline to work on broken codebase. My current stance is to use whatever you’re most comfortable with (on a unit by unit basis). Struggling with editor or IDE, even the coolest/smartest one, is going to interrupt your thinking process and cause performance hit much bigger than whatever gains it could ever produce.
- brabel 3y ago> Thing is that with my line of work stuff breaks often and IDEs rightfully decline to work on broken codebase. So you throw away smarter tools like IDEs because they do not understand your code when it's broken, but then you start using dumber tools that NEVER understand your code? I would say an IDE can still do anything your dumber tools can (grep, dumb find-replace) even when your code is broken, but when it's fully working it gives you so many superpowers it's incredible you would not want that.
- xlii 3y agoThe thing is that those dumber tools can do smarter things than IDEs. I had 2 use cases lately - one was to investigate usage of all function bodies that used specific library for the last 6 months. JetBrains IDE has semantic search but it requires a lot of fiddling (syntax feels very foreign, might be Groovy thing or their own DSL and doesn’t span across multiple commits. Second was to navigate through a custom pre-transpiration layer, which JetBrains could pick up around 30% of the times. Those are two cases solved quickly with list refiltering (first one took 15 minutes, second took less than 3). And they were portable, as sharing was a simple copy & paste. The gist of it is that dumb and smart is marketing thing. ripgrep is dumb tool just as fzf is, but they can be made into a very smart setup. IDEs can make high general work impact but from my experience suck badly when you enter road less traveled.
- ravenstine 3y ago> Unit testing private methods. What if I told you that you don't need private methods?
- jay_kyburz 3y agoBurn! This is one of my favs that is all over out codebase. private float chanceOfRain = 0.1f public float GetChanceOfRain() { return chanceOfRain; } Perhaps somebody can explain it too me because I'm too afraid to ask.
- Yodel0914 3y agoThat looks like basic encapsulation to me - a consumer of the class can read but not modify the value of chanceOfRain. It also allows the class to change how 'chance of rain' is calculated without changing the public interface of the class.
- jay_kyburz 3y agoOh right, yeah. Thanks
- mathisfun123 3y agoPre-emptive encapsulation is a cargo-cult plague/mind-virus. Until someone actually inadvertently fiddles with chanceOfRain (ie actually fucks something up) you are just building a bureaucracy for yourself and your users. And, potentially, you are actively impeding someone who is smarter than you or just disagrees with you on how 'chance of rain' is calculated. I deal with this kind of bs every day in a large oss C++ codebase - some style guide at Google says everything needs to by default go into an anonymous namespace and so you can't reuse anything that the original braingenius deemed useful. Of course this means very few things are actually decomposed/composable. I have lately resorted to forking and carrying patches that expose all the functionality in the anon namespaces.
- Yodel0914 3y ago
- throwmeout123 3y agoDecent insights but nothing earth shattering The whole point is ignoring the dogmatism of our profession full of various shamans with magic formulas to solve everything from scrum to xp to tdd to rust to functional programming to ood etc. Then it’s always the same shit, but it’s your fault because you didnt do this or that It reminds me of something…
- thom 3y agoI’m always surprised this is controversial but: everything you write in a commit message should be evident from your code and its comments. Nobody should ever have to look at git history to understand a codebase.
- ReptileMan 3y agoIt's controversial because it is false. Looking at the code gives you what is happening. The why is almost impossible to put inside. The developers have been trying to cram more and more context into the codebase since the first assembly comments were written. And still we fail.
- thom 3y agoThat's just bad code, and yes, that happens. But if you can write it in a commit message you can capture it somewhere else that people will actually see without having to root around in a completely separate system.
- ReptileMan 3y agoIn my experience the implementation is always hairy and because of the immensely complex stacks we are using in modern dev it is full of all kind of weird workarounds. And we don't really have good place to put - I wrote it in this insane and stupid way because some other module that I have no control over crashed except the commit message. And anyway any project that uses issues tracking also has a lot of context in the issue tracking - by your point of view the developer writing the piece of code that needs commenting should somehow cram the whole issue inside the codebase. We are already using external system anyway - there is no harm in putting information there - the system won't be complete without it anyway. In my experience (and I have been on any kind of failed at any scale) there is no good way to manage information and context - just slightly less terrible ones.
- thom 3y agoBut if you have a piece of insane code, especially if it's fairly localised, why is it superior to explain it in a commit message and not a comment right there next to it? Save people the head scratching. And yes - I do exactly think that the developer should cram the whole issue in the codebase! Those are your acceptance tests, or explicit representations of use-cases or strategies, or service layers, or at the very least some comments lamenting what would otherwise be inscrutable. If your codebase doesn't have a first-class way of describing what it does and why, I don't think it's well-factored. I totally agree that it's easy to mess up, I just continue to think this terrible workflow of externalising key information about code and why it exists is fundamentally defeatist. I don't think we should settle for it.
- xenodium 3y agoWith lsp, the gap between IDEs vs text editors is narrowing. While I still prefer Emacs, I’m pragmatic enough to jump on to whatever tool does a better job for a specific task. At times, that is Xcode. Was also sceptical about ChatGPT and changed my mind like OP. I was less pragmatic on this one and brought ChatGPT over to Emacs https://github.com/xenodium/chatgpt-shell https://github.com/xenodium/chatgpt-shell. Pretty happy with the result so far.
- jeppester 3y agoIt seems to me that the underlying theme is "I was a bit stubborn and dogmatic, now I learned that the other side was not as bad as I pictured".
- cyrialize 3y agoI echo the comments on Emacs. Jetbrains tooling is just so /nice/. You can get your Emacs to act like Jetbrains in a number of ways, but that can sometimes end up being quite complicated. I very much like the experience of opening any Jetbrains IDE and having this working relatively easily compared to Emacs. All that being said, investing in Emacs gives you benefits you won't find anywhere else. For example, I was able to make my Emacs find by reference and find by definition functionality work well and exactly the way I wanted it to. I basically set it up to fall back on resources if the previous one didn't return anything. It went from Language Server Protocol -> CTags -> Regex with rg. It was also cool to pick multiple sources and priority order them for suggestions. Mine, from highest to lowest priority, were: Language Server Protocol -> local buffer matches -> open buffer matches (or something like that, it's been a while since I touched my config). This made it so that I'd get suggestions from my LSP for code, but if I were typing a comment and repeating a word I've used before then LSP would come up empty but Emacs would be auto-completing that word for me.
- MrMan 3y ago[dead]