5 ms·
Spartan Programming
- edw519 18y agoInteresting concept. Certainly struck a nerve with me. I've found one of the easiest ways to minimalize my code is to require less code. How? Better program design. Tighter structure, more efficient algorithms to accomplish to same thing. Reverse the order of two functions and suddenly that conditional is no longer necessary. Adding a parameter to a function may make it larger, but useful in more places. Only handle 90% of cases and send the outliers off to custom-land. You get the idea. It then becomes a whole lot easier to minimalize 50 LOC than 100 LOC. [EDIT: The timing of this post couldn't have been better. I struggled with some pretty complex code all day yesterday. I woke up at 5 a.m. and thought, "Just switch the order the functions are called." I did and it simplified beautifully, working perfectly, and eliminating about 50 LOC.]
- LogicHoleFlaw 18y agoOne of my most productive days was throwing away 1000 lines of code. --Ken Thompson
- AndyKelley 18y agoThis can also sometimes be achieved with math. For example, I was writing code that handled velocity and animation based on the arrow keys. The character had to change animations depending on 8 directions - nesw & diagonals. At first I had an ugly if-elseif statement handling all the keystates. But then I realized I could come up with a cool scheme to simplfy and beautify the code. I also needed to solve the problem of having a constant max-velocity that stayed the same even when going in a diagonal. //which direction to go dirX = 0; dirY = 0; if( keystate[SDLK_LEFT] ) dirX--; if( keystate[SDLK_RIGHT]) dirX++; if( keystate[SDLK_UP] ) dirY--; if( keystate[SDLK_DOWN]) dirY++; if( dirX == 0 && dirY == 0){ //stand still heroVelX = 0; heroVelY = 0; heroAnimation = heroStill[oldHeroDirIndex]; } else { //run in a direction angle = atan2(dirY,dirX); heroVelX = heroSpeed * cos(angle); heroVelY = heroSpeed * sin(angle); oldHeroDirIndex = (dirX+1)*3 + (dirY+1); heroAnimation = heroRunning[oldHeroDirIndex]; } //step to next frame in animation if( ++heroAnimation->curFrame >= heroAnimation->numFrames ) heroAnimation->curFrame = 0; heroX += heroVelX; heroY += heroVelY; -removes conflict from pressing left and right or up and down at the same time -uses a formula to calculate which animation to use, instead of using switch statement -uses a little bit of trig to keep max-speed constant Programming like this is very rewarding, if only for the feeling you get when it works. I guess this isn't really a big deal to any of you, but this sucker used to be 70 repetitive and buggy lines, rather than the pretty 29 it is now.
- mtw 18y agoIsn't this a fanciful expression to label DRY programming?
- ajross 18y agoUh... More like DRY is equally a new, fancy acronym given to a whole bunch of techniques that have been in use for years. This stuff isn't new at all, it's just experiencing something of a renaissance after the dark ages of the late 90's Big Design Madness. The "Spartan Programming" stuff Atwood talks about is focused mostly on C, Java and other low level imperative languages. "DRY" tends to be most used in the context of web development. Other than that, I agree: they're mostly the same idea.
- j2d2 18y agoHmm... It's amusing to me that spartan programming has a name like this. To me, it's simply about efficiently using resources. I am reminded of the time I asked Miguel de Icaza about design patterns. He said he never saw the point of having them in a book because people would just invent them when they needed them.
- Tamerlin 18y agoI agree, this could have been described as good programming. :) There's a quote by a well-known author whose name I cannot recall at the moment, concluding a lengthy letter: "Forgive me for writing such a long letter, I did not have time to make it brief." One of the reasons that I've almost invariably been more productive than most other coders I've worked with is that I write a lot less code than they do. Another side effect of that is that my code has never been a bottleneck, so I've never had to do any further optimization. It also takes significantly less time to debug :)
- seano 18y ago"I have made this letter longer than usual, because I lack the time to make it short" - Blaise Pascal (French mathematician)
- coffeeaddicted 18y agoA point for having design patterns in a book is that everyone can use the same names for the same patterns. That helps somewhat in communication.
- j2d2 18y agoI'm not convinced patterns are that complicated.
- coffeeaddicted 18y agoThey are not complicated. They are common - that's the whole thing behind them. They are so common that it's useful to use same names to talk about them because you will see them over and over in the code of different persons. And certainly defining them exactly and having good implementation examples might also occasionally help a programmer as we're not all perfect ;-)
- orib 18y agoSounds quite a bit like what Rob Pike has to say about programming style: http://www.lysator.liu.se/c/pikestyle.html http://www.lysator.liu.se/c/pikestyle.html
- edw519 18y agoNice reference. Thanks. I don't expect you to agree with all of them... I don't. Even index variable names should be meaningful. Just drop down a couple of nested levels, use "i" again, forget to make it local, and see how much fun you'll have. But I love the disclaimer at the beginning. Made me feel a whole lot better, no matter what he said. I'll have to remember that one.
- henning 18y agoCode Complete discusses this. When only at a single loop level, follow convention and use i. However, as soon as you drop to 2 iteration levels, you should rename your index variables so that they are meaningful. Do not use j or k.
- edw519 18y agoRight. Problem is that it probably won't be you adding the next level. Here's what really happens: - You code a proper loop iterating with "i". - Programmer 2 adds 50 LOC. - Programmer 3 adds 100 LOC. - Programmer 4 drops a level, but since he doesn't see the whole routine (too many LOC for one page or one screen), he uses a global "i" again. But nothing breaks because "i" is always 0 in both levels, both in testing and in production. - Data changes and it breaks. You get the call, "What's wrong with your program?!?" That's why you should have never used "i" in the first place. Call it "SkuNdx", "RecCtr", "ClassNbr", "Ctr1", anything but "i".
- Locke 18y agoWow, different strokes. I wouldn't want anything to do with code that used variables like "SkuNdx" over a simple i, j, or k. That said, ideally I prefer using languages with each or foreach or a similar construct. If you want to iterate over a set of objects, you should only have a variable for an object. Who cares about the index? foreach( sku in skus ) Or skus.each do { |sku| .... } If you reserve i, j, k for cases where you actually need an index, I think you'll find that i has even more meaning: i is an index and it's presence means the index is actually important. That's a lot of meaning for a single letter. With respect to what other programmers might do, I think "defensive" programming is a waste of energy. A bad programmer will screw up your code regardless of what you name a variable. The best you can do is avoid working with such people. If that doesn't work, write unit tests. Seriously, at least then you know that a bad programmer broke your code before you get a call.
- ratsbane 18y agoThis reminds me my 9th grade "Computer Science" class. Mr. Brown taught us some of the same principles with Applesoft Basic. I'm always surprised when I work with other programmers who don't think it's important to write spartan code. Which isn't to say I haven't been guilty of the same thing a time or two - but this article reminded me of my first exposure to programming in the 9th grade. Here's to you, Mr. B.
- ajross 18y agoOne thing I think is missing from this exposition is a discussion of tradeoffs. You can't blindly apply these rules, because they're to some degree contradictory. Example: you can make all your variables private to better "minimize accessibility of variables", but that requires elaborate accessor methods which increase "vertical complexity". Which is the right path? It depends, and the solution is a sense of aesthetic. That, not the rules themselves, seems to me what this techniques is all about. It's really just a different, more specific way of rephrasing PG's essay about taste in software engineering.
- jimbokun 18y ago"Example: you can make all your variables private to better "minimize accessibility of variables", but that requires elaborate accessor methods which increase "vertical complexity"." No. don't create accessors and don't access the data in private variables outside of the scope in which they are defined. Accessors, in most cases I have seen, simply outright defeat the entire purpose of having a private keyword to begin with. EDIT: replaced CAPS with italic emphasis, in order to reduce decibel level.
- ajross 18y agoChill. That was exactly my point. Clearly you have a strong aesthetic sense. :) You might want to lose a few of those CAPITALS though. Someone might think you were screaming about software.
- snorkel 18y agoI've programmed in many styles until I read Martin Fowler's "Refactoring Code" and it taught me the best style is simple READABILITY! The only thing that matters is "Is it reabable"? For example, don't be afraid of replacing 5 lines of code with a descriptively named function whose only content is those 5 lines of code. It may seem pointless to have a function that is only called once but if it makes the code more readable then do it.
- cousin_it 18y ago
- jimbokun 18y agoI now have a name for my coding style! The email-send-function-case-study he links to pretty much follows the way I write code (when forced to write Java here at work).
- mojuba 18y agoSome kill-OOP rules in addition: * Rewrite your code so that you have more static functions that only deal with their arguments and possibly return something (no access to global data or class data). In other words, localize and isolate parts of your code that have minimal side effects. Such parts would be easier to write, debug and maintain. * A class that contains only ctor/dtor and one method should be rewritten to a single static function. * A class that returns a reference to a single instance (singleton) is a sign of terrible design. Rewrite. * If the amount of lines in your unit tests is comparable with that of the original code, it means you expose too much in your interfaces. Rewrite your classes by making their interfaces smaller and simpler. This will reduce your unit tests and make them more meaningful as well.
- DanHulton 18y agoYeah, there's a few things here that set me on-edge. For one, early returns means you have to go poking around for the returns. That highly-indented style is a much clearer "bad code smell" that makes it easier to clean up the routine. And their "reduce curly braces" is just SCREAMINGLY awful. If you have a one-line block, you STILL want curly braces around it. The eye just loves to skim over this mistake: if (condition) i++; applyTaxes(order);
- dangoldin 18y agoI agree with you. I dislike returns scattered throughout a single method. Makes tracking them a bit difficult.
- cstejerean 18y agodoes your editor not highlight returns properly?
- dangoldin 18y agoMost of my editors do but I end up doing a lot of work SSHed from other computers without windows so I end up doing a good amount of work in raw text files. Also, it's easier for me to process a single return line than to take a look at the logic behind each of the other returns. If I end up returning an undef at the beginning of a function and then edit it a few months later I may just skip that step and not see where that case is being handled. It just seems a better way to structure my code, for me at least.
- cstejerean 18y agoI do 99% of my work in a terminal and usually over ssh. that's why I use Emacs. Since you use a single return statement I'm assuming you keep track of the value to return by assigning it to a variable. How is keeping track of multiple assignments to the variable you will return easier than keeping track of multiple return statements? I've always found it easier to keep track of return statements since they're highlighted.
- Herring 18y agoThis is madness.
- pistoriusp 18y agoMadness? This is programming.
- dmoney 18y agoProgamming? This is Web surfing!
- mojuba 18y agoI guess Adobe would agree with you, I mean, today's Adobe.
- dangoldin 18y agoNo.. This is Sparta!
- msluyter 18y agoI like a lot of the concepts, but I'm dubious about terse naming. The long e-mail example simplifies "msg" to "m", for example. Now, while I would agree that veryLongVariableNames can get tedious and annoying, and while I'm also in favor of standardized generic loop indexes (i,j,etc..), I think this may go to the other extreme. I could see going from "message" -> "msg", perhaps, but I'm not sure "msg" -> "m" is a win. Why is saving two characters that important?
- mynameishere 18y agoI could see going from "message" -> "msg" There are dozens of possible abbreviations for "message" but only one correct spelling of "message". Abbreviating a word forces the reader to remember both what it is, and what its abbreviation is. One of the seldom-mentioned gifts that java has given the world is killing the horrendous C practice of insane abbreviations. I can't tell you how many times I've had to look up itoa(). It just wouldn't stay in my brain. But I guess it keeps my teletype's ink from running out too fast.
- AndyKelley 18y agoI think once you load the context of any given program into your head, the variable names become irrelevant. Programming on my TI-83 in elementary school, all I got was A-Z, but when I spent every class making a checkers game in TI-basic, I never forgot that C was the X-dimension of the current selection, Q was the number of black pieces left, and matrix [B] was the last saved game
- msluyter 18y agoWhile it's true that there are many abbreviations of "message," surely some are inherently easier to cognitively process than others. Compare: "eag", "sg", "msa" -- randomly chosen letters (in orig order) vs. "age", "meg","mag" -- purposefully misleading substrings, vs "msg", "mes", "mssg" -- closer to semantic content My point is not so much to quibble, but to suggest that we may have something to learn from cognitive psychology on the subject. Does anyone recall the recent study that showed taht as lnog as the fsrit and lsat lteters of wrods wree the smae, poplee culod gnerlaly mkae out the manenig? (whew! hard to type that.) This suggests to me that at the very least, retaining the first letter is important, and possibly the last as well. My qualm about single letter variable names is that they may require more "lookup time" (on average) because so much of the semantic content has been stripped from the name. I'm curious if anyone has actually researched this? I'm only theorizing here.
- jamongkad 18y agoHot damn I've been practising Spartan Programming for years before I read this article. People thought I was crazy then :-)