
Spartan Programming - bdfh42
http://www.codinghorror.com/blog/archives/001148.html
======
edw519
Interesting 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.]

~~~
AndyKelley
This 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.

------
msluyter
I 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
_I 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.

~~~
ericb
I'd upvote you twice if I could.

You don't even have to look at the screen if you follow a consistent rule of
not abbreviating.

If you do abbreviate, does your buddy use the same scheme? Consistently? Why
optimize for typing speed when memory and "variable lookups" are the
bottleneck?

------
j2d2
Hmm... 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
I 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
"I have made this letter longer than usual, because I lack the time to make it
short" - Blaise Pascal (French mathematician)

------
mojuba
Some 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
Yeah, 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);

~~~
snorkel
I am a reformed indentaholic. Now I adore early returns and use them often. If
you follow the first cardinal rule of OOP, keep methods short, then early
returns are easy to spot.

This kind of short-sighted nesting annoys me:

    
    
      function foo(bar) {
       if (bar == 1) {
          doThis();
       } else {
          var x = doSomething();
          if (x == 2) {
             doSomethingElse();
          } else {
             var y = doThat();
             // ... more code here ...
             for (var m=0; m<y; m++) {
                doBoo(m);
             }
          }
       } 
      }
    

Yuck! I much prefer:

    
    
      function foo(bar) {
         if (bar == 1) {
            doThis();
            return;
         }
    
         var x = doSomething();
         if (x == 2) {
           doSomethingElse();
           return;
         }
    
         var y = doThat();
         // ... more code here ...
         for (var m=0; m<y; m++) {
            doBoo(m);
         }
         return;
      }
    

The difference here is not drastic in this short example but in functions with
50+ lines of code it's very clear.

The average person's short term memory is only 5 - 7 items deep. 3 of those
slots are already occupied with what they are doing, so you have 2 slots left,
maybe 4 slots if they've had their coffee and are really paying attention.
Every time you make a code indent, whether it be a loop or nested condition,
then you're asking the reader to remember that context switch. Once you have
indenting more than two tabs deep then you're in hazy territory where the
reader is unlikely to remember all of the conditions that lead to those lines
of code being executed.

~~~
jcl
One other heuristic I follow that's not mentioned in the essay is: If one
branch of an "if" statement is much shorter than the other, change the
condition so that you can put the short branch first.

My reasoning is also involves memory: While the reader is reading the first
branch, he needs to hold the possibility of an "else" branch in his head,
along with the condition. By minimizing the length of the first branch, you
minimize the amount of time he needs to remember this.

~~~
scott_s
I disagree. I think it depends on context. Generally, one branch is the more
common case, and I prefer to put that one first. It's the main flow of the
code.

~~~
queensnake
Yes but, say you've got a longish chunk of code with several error conditions;
you come across an 'else' after a lot of closing braces. What the heck does it
match with? What other error conditions need handling and got forgotten in the
forward rush of common cases? Error handling is easy to forget; the common
case remembers /itself/ you might say, and can be put off for a moment while
you get the clutter out of the way. My MO, anyway.

~~~
scott_s
I stress the common case for the same reason that when I construct sentences,
I try to put the main point up front, and save the side comments for later.
Example:

"I ran into Bob while walking to the store."

"While walking to the store, I ran into Bob."

The point I'm trying to get across, in this case, is that I ran into Bob. I
try to do the same with code.

------
ajross
One 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.

~~~
snorkel
I'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
Extracting a single-use function can get in the way of future refactorings
that cross the function's boundary. I inline single-use functions whenever I
see them, and almost always after that, other, more useful possible
refactorings become visible. This can happen with multiple-use functions too,
but much less often.

------
orib
Sounds quite a bit like what Rob Pike has to say about programming style:

<http://www.lysator.liu.se/c/pikestyle.html>

~~~
edw519
Nice 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
Code 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
Right. 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
Wow, 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.

~~~
jrockway
_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._

Exactly. I had a really hard time working with normal programmers... I would
explain why I did something that wasn't brute force, they wouldn't get it and
their way also worked... so the codebase was one big festering pile of shit.

Now I work somewhere where my coworkers are arguable some of the best
programmers in the world... and I don't have this problem.

Life is too short for bad jobs. As a programmer with a clue, you are a very
hot commodity. So go somewhere where you won't want to kill yourself at the
end of the day. (Or start your own company, of course. Then you _really_ get
to pick who you work with.)

------
Herring
This is madness.

~~~
dangoldin
No.. This is Sparta!

~~~
sophist
Geez. Please tell me these pun threads are not spreading here from reddit.

------
ratsbane
This 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.

------
jimbokun
I 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).

------
jamongkad
Hot damn I've been practising Spartan Programming for years before I read this
article. People thought I was crazy then :-)

------
mtw
Isn't this a fanciful expression to label DRY programming?

~~~
ajross
Uh... 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.

