19 ms·
Vim plugin to disapprove deeply indented code
- dheera 10y ago... and then people just "solve" the problem by not indenting at all. Seriously though, it's super hard to avoid deeply-indented code in some languages (cough Java, JavaScript). @Override protected void onDestroy() { super.onDestroy(); if(someCrap != null) { PendingResult<MessageApi.SendMessageResult> pending = Wearable.MessageApi.sendMessage(mGoogleApiClient, mPhoneNode.getId(), path, data); pending.setResultCallback(new ResultCallback<MessageApi.SendMessageResult>() { @Override public void onResult(MessageApi.SendMessageResult result) { runOnUiThread(new Runnable() { ....
- lugg 10y agoNot if you auto format in CI. Though that could be dangerous. Although you could just have a build step that waits for a human if the formatted doesn't match submitted.
- Groxx 10y agoretrolambda will get rid of some of those :) But generally, if the code is too onerous to modify due to e.g. excessive use of closure-captured data, then the code usually deserves a long, hard ಠ_ಠ to make sure it doesn't deserve a (╯°□°)╯︵ ┻━┻. Hard to test, hard to fix, hard to control.
- malikNF 10y agoI like to think of plugins like this one playing a sort of "assistant" role rather than a "benevolent dictator" kind of role. So you don't have to end up making ugly hacks to just make it work.
- TheCoreh 10y agoasync/await has greatly reduced the need for indentation in JavaScript
- ismail-khan 10y agoAnd Promises too!
- colordrops 10y agoEven without async/await, if you properly organize code in bite size functional blocks and use other asynchronous constructs then the indentation should be manageable.
- programmarchy 10y agoSmall improvement, but this can help: if(someCrap == null) { return; } I like that Swift makes this more explicit with the guard statement, but I've found it useful to reduce the "mental stack" in other languages, too.
- adrianN 10y agoNot everybody is allowed to do that. MISRA for example requires a single exit point.
- rjzzleep 10y agoThat's 14.7, but if for some reason 14.7 doesn't apply 16.8 requires that all exit points return a value. So I'd argue MISRA lets you do that.
- programmarchy 10y agoReading up on MISRA, I found an interesting defense of a single return statement [1]. In the embedded world, I imagine it would be a good standard to force people to consider refactoring functions to their truth table. Generally, I strongly favor coding standards to combat bad coding habits. Curious how MISRA works out in practice. [1] https://spin.atomicobject.com/2011/07/26/in-defence-of-misra/ https://spin.atomicobject.com/2011/07/26/in-defence-of-misra...
- lmm 10y ago> That’s a lot simpler isn’t it? WTF?? No it isn't. You have this magic initial value and have to figure out which code paths have mutated it and which haven't. Mutable variables make code far far more complex to read. I'm all for single return but through the use of expressions, not variables; I would probably express the given function as: expression() { return a ? (b && c) ? 2 : 1 : 0 ; } (Ideally I'd use a language that allowed a sensible conditional expression rather than one that relies on bizarre symbols, but we work with what's available)
- platz 10y ago"Bulldozer code" - gives the appearance of refactoring by breaking out chunks into subroutines, but that are impossible to reuse in another context (very high cohesion)
- golergka 10y agoSubroutine that is only used in one place still improves readability: instead of a bunch of statements, you have a name, explicit parameter list and a retugn value.
- platz 10y agoit's not when applied once, it's when something that can be understood more easily "locally" is exploded into a billion such pieces - then you have to mentally find all the call sites and usages to mentally build the call graph back up — you still have to understand how the whole ensemble works and bulldozing can (but not always) make understanding the ensemble more difficult especially if done by a poor programmer has the effect of obfuscation rather than clarification.
- patmcguire 10y agoIt's good when it gives a name to what you're doing. connection = establish_connection_given_these_conditions(cond1, cond2) Vs the many lines of checking, creating the ConnectionFactory, passing in the the conditions to the ConnectionConditionFactory, and generally having a new statement every time you want to blow your nose. What were we doing again? I dunno. I've used it. I'll defend it. It's better than comments when done properly as above.
- vog 10y agoIndeed! More generally, functions are not only about abstraction, but also about decomposition. The only thing that may hurt readability is when the decomposition itself is too much nested. Usually, it's best to split a large task purely linearly in subtasks (functions), and have them called all from a single function. That main task function gives you not only an overview of all sub tasks, but also about the dataflow between them. In constrast, too much subtask nesting (subtasks of subtasks of subtasks) often hide the overall flow, which then makes it hard to get the overall view.
- golergka 10y agoPromises?
- logicallee 10y agoBut for example your indent if(someCrap != null) { followed by indentation on the following block, would be turned by the programmer into something like: if(someCrap == null) return; //nothing to do without an indent following. thereby saving the indent and having to have the reader keep track of another level. How many times have you seen: } } } } And is it really that great? Breaking it into line by line is actually easier to follow than nested conditions. (You don't have to worry about proper indentation or matching braces properly, it's simply easier to write.) I think it's easier to read as well.
- dheera 10y agoI agree with you if that's all it were. But sometimes it's if(someCrap == null) { try { CrapSurface mCrapSurface = CrapGenerator.generateSomeCrap(CrapGenerator.CRAPPY, new CrapFactory.CrapOptions(new CrapOptionsCallBack() { @Override int getHeight() { return 5; } @Override int getWidth() { return 9; } })); someCrap = CrapSurface.getCrap(); } catch (SomeException e) { try { someOtherFailSafeButInefficientWayToGenerateTheCrap(); } catch (WeirdExceptionThatWillSeriouslyNeverHappenButStupidJavaRequiresMeToHaveATryCatchClauseAnyway f) { // do nothing because this exception will never happen and if it happens the user deserves it } } } else { ... the other code I had before ... }
- rootlocus 10y agoif(someCrap == null) { someCrap = makeNewCrap(); } That's more readable and less indented. It's also self documenting. } catch (WeirdExceptionThatWillSeriouslyNeverHappenButStupidJavaRequiresMeToHaveATryCatchClauseAnyway f) { // do nothing because this exception will never happen and if it happens the user deserves it } Nice joke, don't do this. I don't believe it's the user's fault, and even so either print the stack trace or name the exception `ignored`. It's not that hard to pipe all ignored exceptions in a single catch. Also, somebody made the conscious decision of making that exception checked, which means it's the implementor's fault for forcing you to catch it. If you want, you can use lombok's `@SneakyThrows`.
- rootlocus 10y agoIt's only "super hard" if you insist on anonymous classes. Reversing the `someCrap != null` condition and using an inner class reduces the identation count down to 2 (and that's in only one place for the return statement in the inverted null condition). Also, consider using static imports for `Wearable.MessageApi.sendMessage` and `MessageApi.SendMessageResult`.
- tokenizerrr 10y agoI really don't like static imports for stuff like that. You always have to do a double take to recognize where the method comes from.
- rootlocus 10y agoPersonally I've never had this problem. The context was always sufficient, and a simple IDE shortcut can offer me any additional information. I would argue a double take is worth reducing the number of dots I have to follow when reading the code. Also, in the case of `Wearable.MessageApi.sendMessage`, you can statically import `MessageApi.sendMessage` which gives a little more context.
- barrkel 10y agoI really like being able to read code in source control historical diffs, pull requests, etc. IDE shortcuts aren't a full solution; not everyone has time to check out a branch at that commit, create a project (if necessary), fire up an IDE (if there's a UI available) just to understand a line of code. Similarly, static imports at the top of the file are usually remote from the point of use, so you lose that context when viewing a diff.
- chukye 10y agoNo, it's not hard to avoid, actually it's pretty easy to avoid if you understand what you are doing.
- bsder 10y agoTime for my apocryphal story: I needed to a fix a particular kernel protocol subsystem so I could use Linux at work. I sat down with the spec and a non-Linux computer that implemented it. I spent 8 weeks (I thought it would take a couple days--HAH!), and I wrote it and wrote the very nice test suite which included the single test case I couldn't handle (handling would have required major changes to the kernel). It's a protocol. The word protocol means "state machine". Especially when hardware dudes design something. However, state machines mean "indentation". One level for current state, one level (at least) for output variables, and a couple of levels for input variables. My code was well documented, tested, and easily changeable if you needed to add a new state. "But, that's more than two levels of indentation. Rewrite it.". After I pulled my jaw up off the floor, swore a couple of times, I replied: "No. This code is properly written, well-tested, and very amenable to changes when the spec gets updated. This code does what I need and what a bunch of people need. I will happily distribute it to them and you will have a bunch of users of this subsystem happily telling everybody to not use mainline because they are a bunch of tossers. If you wish to rewrite it to your indentation spec, feel free, but I will not sign off until it passes all of the tests." So, they did. They decided to rewrite it to remove the indentation. Lots of early returns (full of bugs). State cases that got "simplified" by sharing common code (full of uninitialized variable bugs). And, because of all the sharing, it became difficult to add cases when the spec changed (which it did--regularly). But, eventually they got their two levels of 8 character indent. After SIXTEEN WEEKS. My question, of course, was "Why not just pull each state into a function? It was the obvious way to get what you want. It would have been much easier." The response: "Well, we tried that. But there are so many variables per state, that the function calls were all exceeding an 80-character line length and we had to wrap them too much." I had a bruise on my forehead that day. Yeah, formatting rules exist and have good reasons. But please remember that the goal is "code quality and readability"--not formatting rules.
- weitzj 10y agoMy questions I ask myself every time to keep indentation to a minimum: - Is there a way to use an early return? (In your case early return if == null) - How can I get around using an `else` ? And I am happy this works so well. Of course there are sometimes if/elseif constructs but exclusive if/else is rare.
- mnarayan01 10y agoSo looking at the example, you can avoid one level of indentation by doing e.g.: if (items === null) { return 0; } at the start. Which is fine if that's the preferred style, but if it is, then you should do it regardless of how deeply nested the dependent stuff is.
- mplewis 10y agoYep! That's happy path/golden path/line of sight programming, and it's awesome. https://medium.com/@matryer/line-of-sight-in-code-186dd7cdea88#.m3qqyv35i https://medium.com/@matryer/line-of-sight-in-code-186dd7cdea...
- moonshinefe 10y agoNice, I didn't know there was actually a name for it. My 15 years of coding experience has just taught me it's the far better way to code. It's one of my peeves to be following code paths and oh look, now we're in a situation where it's if (OK) { if (OK) { if (OK) { if (OK) { ... } } } } and I'm trying to remember what all the conditions were to get here since it's long since scrolled off the page. I always find myself thinking "why, why didn't you just return way up there!?"
- shthed 10y agoother names for it: http://wiki.c2.com/?ArrowAntiPattern http://wiki.c2.com/?ArrowAntiPattern http://thedailywtf.com/articles/Coding-Like-the-Tour-de-France http://thedailywtf.com/articles/Coding-Like-the-Tour-de-Fran...
- hodgesrm 10y agoSorry to be cynical, but this sounds as about as useful as Microsoft Word syntax checkers that draw green lines under perfectly valid sentences.
- hackuser 10y agoI was helping someone edit a book, and that syntax checker came in very handy. There were indeed many false positives, but it provided a much smaller search space for my eyes than 'every word on every page'. (I did read every word, but the ones with the green lines under them got extra focus that was not going to be available for 200+ pages.)
- oblio 10y agoI also love how the very people who can spend tens of hours on configuring vim, emacs, bash, zsh or their IDE can't be bothered to spend 5 seconds disabling the Office spellchecker if it bothers them so much :)
- hodgesrm 10y agoI'm glad that feature worked for somebody--that's definitely a different use case. For smaller documents it's more effective just to reread the doc carefully. Spell checks on the other hand are invaluable, especially since you can extend the dictionary to cover new words like "deserialization."
- hackuser 10y agoDoes anyone know a good plugin that will provide faint vertical lines so I can see where the indents line up (as described below)? Someone I know used something called Cream, which they said was Vim with a simplified GUI-based interface (I know; what's the point?). But it had one nice feature: If you indented a line, then Cream would draw an unobtrusive vertical line, extending down from the indent's left-most character (I forget how far the lines extended or what that logic was, but they went far enough to be useful). You could easily see how many tabs 'in' you were and line up a current line with one (not directly) above.
- smilekzs 10y agohttps://github.com/Yggdroot/indentLine https://github.com/Yggdroot/indentLine
- hackuser 10y agoGracias
- cmcginty 10y agoI think you're looking for [IndentLine](https://github.com/Yggdroot/indentLine https://github.com/Yggdroot/indentLine) I also use the following options in my vimrc: " set indentline style let g:indentLine_char = '│' let g:indentLine_color_term = 66 let g:indentLine_color_gui = '#4f5b66' " fix performance issue with long lines let g:indentLine_faster = 1
- hackuser 10y agoExcellent, thanks.
- hodgesrm 10y agoSublime Text puts in the lines natively. It's really useful.
- lomereiter 10y agoNice idea, but I'm afraid those who are too lazy to structure their code are not likely to give Vim a chance either. A plugin for a popular IDE would be more beneficial.
- watwut 10y agoI have opposite experience. People with good IDEs (idea, visual) were more likely to structure the code while people with weaker IDEs (vim, sublime) less likely. Mostly because weaker IDE does not navigate code that well and jumping from call to definition requires more manual scrolling. In the extreme, with pure text editor, you want all details together where you effortlessly see them. Helper function means manual search and scroll.
- andrewshadura 10y agoHelper functions mean one key press to jump to their definition and another one to jump to their declaration, and one more to jump back.
- TorKlingberg 10y agoThat is just the point watwut made. The jump to definition function in vim or sublime is not quite as good as a (correctly configured) full-blown IDE. They search for something like a definition, but do not understand the code on the same level as an IDE that has all the build information. On the other hand, IDEs force you to spend time configuring it, or there will be red squiggles under everything.
- gjjrfcbugxbhf 10y agoThere are plugins that let have this level of understanding. Youcompleteme. But then vim gets heavy like an ide... Pick your poison.
- deleted 10y ago[deleted]
- joe563323 10y agoThe problem is not in the code you write, in the code you have to extend or maintain.
- vomitcuddle 10y agoNever needed a plugin for this, just `:set tw=79`
- khanki_magi 10y agoGet Out Full Movie online Free https://www.linkedin.com/pulse/copyfull-get-out-freefull-online-movie-frances-xiong https://www.linkedin.com/pulse/copyfull-get-out-freefull-onl...
- htor 10y agoThis plugin made me laugh! Those disapproving eyes. Might go crazy if using this while developing though.. (stop harassing me, EDITOR)
- jlebrech 10y agoI'd like a language that designed to have zero indentation and you wire things up graphically from those subroutines you've created.
- TorKlingberg 10y agoTry LabView. It is graphical programming and you can make literal spaghetti code. It has problems, like diff and merge is very hard.
- msoucy 10y agoIt's also good at making extremely simple things incredibly complex... but then provides some high level "functions" to do weirdly specific things.
- tribune 10y agoClever idea but I tend to disapprove of using things like this in practice. Formatting (or rejection of poor formatting) should be handled in CI.
- falcolas 10y agoIf you wait for CI, you're adding time to the feedback loop. This is, imo, a bad thing since it interrupts The Flow to go back to previously written code to fix it. By the time I commit, I've already evicted that stack from my mental model; I'd rather not have to go back and rebuild it 5 minutes later when the build breaks.
- shultays 10y agoReminds me of this emacs plugin, deldo: https://youtu.be/D1sXuHnf_lo?t=2m57s https://youtu.be/D1sXuHnf_lo?t=2m57s Slightly NSWF.
- K0nserv 10y agoCyclomatic complexity[0] is a decent proxy for indentation level all though not all indentation increases cyclomatic complexity and not all increase in cyclomatic complexity increases indentation. However for the purpose of reducing complexity it is wonderful. The ruby community is fairly good at using Rubocop[1] to enforce number of lines in methods and cyclomatic complexity. I've found that limiting yourself to 10-20 lines per method and a cyclomatic complexity lower than 7-10 is very beneficial to code quality and perceived complexity. Those numbers obviously need to tweaked to suite the language, but work well for ruby. Often this does involve pulling out blocks of code into a methods that's only called once, but as discussed elsewhere in the thread this is still an improvement in perceived complexity and readability. 0: https://en.wikipedia.org/wiki/Cyclomatic_complexity https://en.wikipedia.org/wiki/Cyclomatic_complexity 1: https://github.com/bbatsov/rubocop https://github.com/bbatsov/rubocop