Code's Worst Enemy
steve-yegge.blogspot.com
steve-yegge.blogspot.com
some choice clips:
"The lesson you eventually learn is that code always changes, always always always, and as soon as you have to change the same thing in N places, where N is more than 1, you'll have earned your scar."
"The other seminal industry book in software design was Design Patterns, which left a mark the width of a two-by-four on the faces of every programmer in the world, assuming the world contains only Java and C++ programmers, which they often do."
" 'It's not that Java is verbose!' he added."
"An 'X programmer', for any value of X, is a weak player."
"I can't exactly wish for something painful to happen to Java developers, since hey, it's already happening; they've already taught themselves to pretend it's not hurting them."
My favorite was this little gem:
"Bigger is just something you have to live with in Java. Growth is a fact of life. Java is like a variant of the game of Tetris in which none of the pieces can fill gaps created by the other pieces, so all you can do is pile them up endlessly."
Doing Java for the day job has made this painfully clear to me. Trying to refactor and get more DRY is a lot of effort.
And this was just hilarious...
"Plus everyone will spit on you. People who don't habitually spit will expectorate up to thirty feet, like zoo camels, in order to bespittle you if you even suggest the possibility of using a Lisp or Scheme dialect at your company."
In many cases javascript is fullfilling the promises of lisp. Complete with REPL on the client platform itself (firebug, for instance).
May not be what you expect, but its there, its its not too shabby.
(in address bar)
javascript: R=0; x1=.1; y1=.05; x2=.25; y2=.24; x3=1.6; y3=.24; x4=300; y4=200; x5=300; y5=200; DI=document.images; DIL=DI.length; function A(){for(i=0; i-DIL; i++){DIS=DI[ i ].style; DIS.position='absolute'; DIS.left=Math.sin(R TIMES x1+i TIMES x2+x3) TIMES x4+x5; DIS.top=Math.cos(R TIMES y1+i TIMES y2+y3) TIMES y4+y5}R++};setInterval('A()',5); void(0);
He probably just needs to disable automatic builds. There are other automatic features that can be disabled as well. Eclipse can be stripped down like anything else.
nothing that would permit the removal of the copy-and-paste duplication patterns that Java programmers think of as "inevitable boilerplate", but which are in fact easily factored out in dynamic languages.
You know, I've never heard the phrase "inevitable boilerplate" from a Java programmer, though his quotation marks suggest that he has. There are some things that can really be shrunk down in non-Java languages, but a lot of the examples that people point out are harmless:
System.out.println("output here");
or for (Object obj : list)
{
}
These sorts of things don't really add to complexity. Too bad he didn't provide any specific examples of his own. Typically, when attacking Java (the most common sport in the software world today) people will pretend it has disabilities it doesn't have.like non-broken closures, that the Java community is resisting tooth and nail
Another phenomenon I haven't seen too much of, I guess. Most resistence probably comes from people who know what will happen, rather than people who dislike the feature in and of itself...
I'll say this about Java, since I get the impression that a lot of ynews people are in college or just out of college: I've had gigantic mountains of Java code thrown at me that I could make useful modifications to in minutes. It is hard to obfuscate. By contrast, I have dealt with Javascript codebases that were a nightmare to work with simply because the previous guy thought it useful to graft functions onto objects (or is it "prototypes") at runtime. Nice feature, if you're not inheriting it...
To do that in Java you need code generators (probably built into IDEs), frameworks that supplant the entire object creation mechanism to hook in proxies, or byte code manipulation. All of these techniques are orders of magnitude more complex and error prone than dynamic metaprogramming or lisp macros. And despite all the complexity some things just can't be done. There is no way to call a Java method (using regular method call syntax) that the compiler doesn't see. So even if you know the method will be there because some other code will have created it by the time it is invoked, you still need to put a useless method stub somewhere in the source code.
And that's with the tutorial crowing about how the SDK has tools to help you save time.
For example, in the SDK, you define resources in an XML file. The IDE/Android plugin will automatically build a Java file for you out of the XML file. This lets you reference the the code in there. And sure, the shift-ctrl-O to organize the library import is nice ... it is just that I never had to do that with Rails. And adding event callbacks via anonymous classes? It is incredibly awkward.
In my brief excursion into Java, I think the zinger, "Typically, when attacking Java (the most common sport in the software world today) people will pretend it has disabilities it doesn't have." is grossly misinformed. The examples of System.out.println("output here"); or the for loop example is trivial compared to the power of Ruby's eigenclasses and runtime code rewriting capabilities. While working my way through that tutorial, I kept thinking to myself, "I really should not have to deal with this crap."
When I was a teenager, I spent too much time coding with LPC, using the MudOS platform. This was before the Ultima Online dev team started soliciting ideas from rec.games.muds. LPC uses a C-like language, had dynamic array and hash syntaxes ported from Perl 3. You could use anonymous functions (though you could not serialize it), and reflection is built into the language. The pseudo-natural-language parser in MudOS was built to take advantage of the LPC's reflection capabilities.
Being older now, I went back through some of the LPC libraries on a whim. I remembered those good old days with a sort of fuzzy, nostalgic glow. At least until I looked at the code. Looking at it now, I know with something as capable as Ruby, the code would not have had to twist itself in such awkward ways, lots of copy-and-pasting. (And just so you know, copy-and-paste on MudOS systems meant using the built in command-line 'ed' editor).
"By contrast, I have dealt with Javascript codebases that were a nightmare to work with simply because the previous guy thought it useful to graft functions onto objects (or is it "prototypes") at runtime. Nice feature, if you're not inheriting it..."
This actually tells me quite a bit why you like Java instead of Javascript. I didn't really feel Javascript was a compelling language until I saw the prototyping feature. The point is not to inherit it so much as to mixin code. It is a very different way of thinking. To me, overly-designed class heirarchies are as ugly and awkward to me as the prototype/code mixin is to you.
In the example of writing that game, having code mixin gives you an incredible advantage. You can create game objects by mixing in different game properties. is_immune_to_poison. is_resistant_to_fire. reflects_magic :only => :fire. You don't need to set a bitfield or try to do multi-inheritance. And you would be able to define game content using the prototyping language (Javascript, Ruby, whatever) rather than writing a (breakable) parser to load up the game object definitions.
I find that a touch inscrutable, but to make an object have various behaviors certainly doesn't require subclassing.
obj.addProperty(new PoisonImmunity());
obj.addProperty(new FireResistence());
obj.addProperty(new ReflectsMagic());
or, in one line: obj.addProperties(new PoisonImmunity(), new FireResistence(), new ReflectsMagic());
or, super-fast mode: obj.addPropertyFlags(POISON_IMMUNITY | FIRE_RESISTENCE | REFLECTS_MAGIC);
or, pulling from some configuration file: obj.addProperties("poison_immunity", "fire_resistence", "reflects_magic"));
...maybe you're doing something I don't grasp, but it seems like another case of pretending that java has a disability that it doesn't. class MyBadassSword < GameObject
is_immune_to_poison
is_fire_resistant
reflects_magic
end
When is_immune_to_poison is called, it reopens MyBadassSword and attaches more code to it. This is not a syntax feature of Ruby so much as using .include to append more code modules or rewrite definitions to it. The Java JVM supports this, but you have to jump through a lot of hoops to do that with Java itself.The POISON_IMMUNITY | FIRE_RESISTENCE | REFLECTS_MAGIC is exactly what I don't want to mess with. I'm not instantiating PoisonImmunity() class. I'm not using bit fields like POISON_IMMUNITY. (I specifically said in my previous post I was not talking about bit fields). I'm not talking about pulling strings from a configuration file.
I don't like eclipse at all, but I don't understand their complaints. Maybe back in 2003 that was a problem.
With written or spoken communication (as opposed to visual), you have to say things a lot of times, in a lot of ways, to get people to listen. Which is more memorable - this or a Valleywag post?
Imagine a kingdom of nouns and verbs, where nouns have lots of rights and verbs are oppressed. Imagine replacing all the verbs with just one verb, 'execute!' Get it? Verb/execute/oppression?? I guess not, not when I try to cram all the ideas into 2 sentences. Sure it takes Yegge a page or so to get there, but the payoff is a hearty laugh.
This essay looks to be about 5 times as long as I could easily handle during the work day. You lost me at "continued".
But yeah, 300-350 is about my limit for books too. I've passed up books I wanted to read when I found out they were over 500 pages. I just put them back in the todo list for later.
Steve is hoping for a 50% - 75% reduction in LOC. In other words, he hopes to compress by 3 or 4. In other words, a mere linear reduction. Is that worth a complete rewrite?
Remember the lesson of the Mozilla rewrite? http://www.joelonsoftware.com/articles/fog0000000069.html Rewriting does nothing for users.
I'd like to know what the 500k lines are doing. It's a game. Are there numerous classes representing physical object types and character types? Could these be expressed as data, or in a domain-specific language, or using an embedded scripting language like Lua?
I'd prefer any of those three solutions to rewriting the whole app in a scripting language. If the codebase does contain a degree of data-as-code, it's better to factor that out.
All maps, game objects, and NPCs/monsters are in XML, though ones with odd, specific behavior also have a corresponding code file. I'm not sure about races, but it doesn't make much difference, considering there are around twenty races and thousands of maps, objects, and monsters.
Wyvern is wrought with fair-size bugs (e.g.: hydras and other monsters with multiple attacks can kill players multiple times at once) that have been around for years, despite multiple attempts at fixing them. He had complained frequently enough about the difficulty adding major features with the codebase's design. It certainly would do something for the users.
If you want to see what those 500k lines are doing, check out the API docs at http://web.archive.org/web/20060820070049/www.cabochon.com/a...
I guess its a balancing act, I like havign the power, and I am happy to discipline myself.
Sure, it may have trouble scaling for large teams and codebases, but I don't wnat to work with large teams or codebases.
Hmmm.... did I just type that or think it ?
Help me succeed. Find some people who have a lot of photos that they can never find time to organize for sharing. Point them to my site. When a popular site is using Scheme on the JVM, you using it isn't such a far-out proposal any more.
Caveats:
1) There are only 2 on the list so far - but I'm adding more
2) I haven't published it yet - but I will soon and solicit feedback
3) Nobody reads my blog - but I've just started in earnest and need to beef up publicity in order to get exposure for my startup
I'm planning on Common Lisp and Weblocks for my startup (just because), but I must admit that both Kawa and PLT Scheme intrigue me.
Hey, nobody reads my blog: muddymo.blogspot.com (well, a few do) but I will link you on my blogroll. Send me an email when you are ready.
On another note, has anyone here played with Groovy? I played it for a while, and I am not sure why there seems to be so much negativity about it.
http://web.archive.org/web/20060720091555/www.cabochon.com/~...
Groovy just seems pointless to me. It's taken too long to get anywhere, and I can't think any reason to use it over JRuby, Rhino or Scala. JRuby and Rhino have the benefit of being implementations of popular languages, basically getting years of experience, tooling, docs and code for free. Scala adds novel ideas not found in other JVM languages, and makes certain types of problems much easier than they would otherwise be. Groovy is a less powerful version of Ruby with a Java like syntax. It's awfully hard to get excited about that.
... which is, in a word, retarded. I like java, but, if you're gonna start over, please, oh, please, fix some of the things that need fixing but aren't getting fixed because of backward compatibility issues. You've got a blank slate, use it!