I'm a programmer, and I'm on vacation today. Guess what I'm doing? As much as I'd love to tell you I'm sipping Mai Tais in the Bahamas, what I'm actually doing on my vacation is programming.
So it's a "vacation" only in the HR sense – I'm taking official time off work, to give myself some free time to get my computer game back online. It's a game I started writing about ten years ago, and spent about seven years developing. It's been offline for a while and I need to bring it back up, in part so the players will stop stalking me. It's going to take me at least a week of all-day days, so I had to take a vacation from work to make it happen.
Why did my game go offline? Not for want of popularity. It's a pretty successful game for a mostly part-time effort from one person. I've had over a quarter million individuals try it out (at least getting as far as creating a character), and tens of thousands of people who've spent countless hours playing it over the years. It's won awards and been featured in magazines; it's attracted the attention of game portals, potential investors, and whole schools full of kids.
Yup, kids. It was supposed to be a game for college students, but it's been surprisingly popular with teenagers and even pre-teens, who you'd think would be off playing some 3D console game or other. But I wrote it for myself, and apparently there are sufficient people who like the same kinds of games I do to create a sustainable community.
I took the game down for all sorts of mundane reasons - it needed some upgrades, work got busy, I didn't have lots of time at nights, etc. But the mundane reasons all really boil down to just one rather deeper problem: the code base is too big for one person to manage.
I've spent nearly ten years of my life building something that's too big.
I've done a lot of thinking about this — more than you would probably guess. It's occupied a large part of my technical thinking for the past four or five years, and has helped shaped everything I've written in that time, both in blogs and in code.
For the rest of this little rant, I'm going to assume that you're a young, intelligent, college age or even high school age student interested in becoming a better programmer, perhaps even a great programmer.
(Please – don't think I'm implying that I'm a great programmer. Far from it. I'm a programmer who's committed decades of terrible coding atrocities, and in the process I've learned some lessons that I'm passing along to you in the hopes that it'll help you in your quest to become a great programmer.)
I have to make the assumption that you're young in order to make my point, because if I assume I'm talking to "experienced" programmers, my blood pressure will rise and I will not be able to focus for long enough to finish my rant. You'll see why in a bit.
Fortunately for me, you're young and eager to learn, so I can tell you how things really are. Just keep your eyes open for the next few years, and watch to see if I'm right.
Minority View
I happen to hold a hard-won minority opinion about code bases. In particular I believe, quite staunchly I might add, that the worst thing that can happen to a code base is size.
I say "size" as a placeholder for a reasonably well-formed thought for which I seem to have no better word in my vocabulary. I'll have to talk around it until you can see what I mean, and perhaps provide me with a better word for it. The word "bloat" might be more accurate, since everyone knows that "bloat" is bad, but unfortunately most so-called experienced programmers do not know how to detect bloat, and they'll point at severely bloated code bases and claim they're skinny as a rail.
Good thing we're not talking to them, eh?
I say my opinion is hard-won because people don't really talk much about code base size; it's not widely recognized as a problem. In fact it's widely recognized as a non-problem. This means that anyone sharing my minority opinion is considered a borderline lunatic, since what rational person would rant against a non-problem?
People in the industry are very excited about various ideas that nominally help you deal with large code bases, such as IDEs that can manipulate code as "algebraic structures", and search indexes, and so on. These people tend to view code bases much the way construction workers view dirt: they want great big machines that can move the dirt this way and that. There's conservation of dirt at work: you can't compress dirt, not much, so their solution set consists of various ways of shoveling the dirt around. There are even programming interview questions, surely metaphorical, about how you might go about moving an entire mountain of dirt, one truck at a time.
Industry programmers are excited about solutions to a big non-problem. It's just a mountain of dirt, and you just need big tools to move it around. The tools are exciting but the dirt is not.
My minority opinion is that a mountain of code is the worst thing that can befall a person, a team, a company. I believe that code weight wrecks projects and companies, that it forces rewrites after a certain size, and that smart teams will do everything in their power to keep their code base from becoming a mountain. Tools or no tools. That's what I believe.
It turns out you have to have something bad happen to you before you can hold my minority opinion. The bad thing that happened to me is that I wrote a beautiful game in an ugly language, and the result was lovely on the outside and quite horrific internally. The average industry programmer today would not find much wrong with my code base, aside from the missing unit tests (which I now regret) that would, alas, double the size of my game's already massive 500,000-line code base. So the main thing they would find wrong with it is, viewed in a certain way, that it's not big enough. If I'd done things perfectly, according to today's fashions, I'd be even worse off than I am now.
Some people will surely miss my point, so I'll clarify: I think unit testing is great. In fact I think it's critical, and I vastly regret not having unit tests for my game. My point is that I wrote the game the way most experienced programmers would tell you to write that kind of system, and it's now an appallingly unmanageable code base. If I'd done the "right thing" with unit tests, it would be twice appalling! The apparent paradox here is crucial to understanding why I hold my minority belief about code base size.
Most programmers never have anything truly bad happen to them. In the rare cases when something bad happens, they usually don't notice it as a problem, any more than a construction worker notices dirt as a problem. There's just a certain amount of dirt at every site, and you have to deal with it: it's not "bad"; it's just a tactical challenge.
Many companies are faced with multiple million lines of code, and they view it as a simple tools issue, nothing more: lots of dirt that needs to be moved around occasionally.
Most people have never had to maintain a half-million line code base singlehandedly, so their view of things will probably be different from mine. Hopefully you, being the young, eager-to-learn individual that you are, will realize that the only people truly qualified to express opinions on this matter are those who have lived in (and helped create) truly massive code bases.
You may hear some howling in response to my little rant today, and a lot of hand-wavy "he just doesn't understand" dismissiveness. But I posit that the folks making these assertions have simply never been held accountable for the messes they've made.
When you write your own half-million-line code base, you can't dodge accountability. I have nobody to blame but myself, and it's given me a perspective that puts me in the minority.
It's not just from my game, either. That alone might not have taught me the lesson. In my twenty years in the industry, I have hurled myself forcibly against some of the biggest code bases you've ever imagined, and in doing so I've learned a few things that most people never learn, not in their whole career. I'm not asking you to make up your mind on the matter today. I just hope you'll keep your eyes and ears open as you code for the next few years.
Invisible Bloat
I'm going to try to define bloat here. I know in advance that I'll fail, but hopefully just sketching out the problem will etch out some patterns for you.
There are some things that can go wrong with code bases that have a nice intuitive appeal to them, inasmuch as it's not difficult for most people to agree that they're "bad".
One such thing is complexity. Nobody likes a complex code base. One measure of complexity that people sometimes use is "cyclomatic complexity", which estimates the possible runtime paths through a given function using a simple static analysis of the code structure.
I'm pretty sure that I don't like complex code bases, but I'm not convinced that cyclomatic complexity measurements have helped. To get a good cyclomatic complexity score, you just need to break your code up into smaller functions. Breaking your code into smaller functions has been a staple of "good design" for at least ten years now, in no small part due to the book Refactoring by Martin Fowler.
The problem with Refactoring as applied to languages like Java, and this is really quite central to my thesis today, is that Refactoring makes the code base larger. I'd estimate that fewer than 5% of the standard refactorings supported by IDEs today make the code smaller. Refactoring is like cleaning your closet without being allowed to throw anything away. If you get a bigger closet, and put everything into nice labeled boxes, then your closet will unquestionably be more organized. But programmers tend to overlook the fact that spring cleaning works best when you're willing to throw away stuff you don't need.
This brings us to the second obviously-bad thing that can go wrong with code bases: copy and paste. It doesn't take very long for programmers to learn this lesson the hard way. It's not so much a rule you have to memorize as a scar you're going to get whether you like it or not. Computers make copy-and-paste really easy, so every programmer falls into the trap once in a while. 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.
However, copy-and-paste is far more insidious than most scarred industry programmers ever suspect. The core problem is duplication, and unfortunately there are patterns of duplication that cannot be eradicated from Java code. These duplication patterns are everywhere in Java; they're ubiquitous, but Java programmers quickly lose the ability to see them at all.
Java programmers often wonder why Martin Fowler "left" Java to go to Ruby. Although I don't know Martin, I think it's safe to speculate that "something bad" happened to him while using Java. Amusingly (for everyone except perhaps Martin himself), I think that his "something bad" may well have been the act of creating the book Refactoring, which showed Java programmers how to make their closets bigger and more organized, while showing Martin that he really wanted more stuff in a nice, comfortable, closet-sized closet.
Martin, am I wrong?
As I predicted would happen, I haven't yet defined bloat except in the vaguest terms. Why is my game code base half a million lines of code? What is all that code doing?
Design Patterns Are Not Features
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.
Design Patterns was a mid-1990s book that provided twenty-three fancy new boxes for organizing your closet, plus an extensibility mechanism for defining new types of boxes. It was really great for those of us who were trying to organize jam-packed closets with almost no boxes, bags, shelves or drawers. All we had to do was remodel our houses to make the closets four times bigger, and suddenly we could make them as clean as a Nordstrom merchandise rack.
Interestingly, sales people didn't get excited about Design Patterns. Nor did PMs, nor marketing folks, nor even engineering managers. The only people who routinely get excited about Design Patterns are programmers, and only programmers who use certain languages. Perl programmers were, by and large, not very impressed with Design Patterns. However, Java programmers misattributed this; they concluded that Perl programmers must be slovenly, no good bachelors who pile laundry in their closests up to the ceiling.
It's obvious now, though, isn't it? A design pattern isn't a feature. A Factory isn't a feature, nor is a Delegate nor a Proxy nor a Bridge. They "enable" features in a very loose sense, by providing nice boxes to hold the features in. But boxes and bags and shelves take space. And design patterns – at least most of the patterns in the "Gang of Four" book – make code bases get bigger. Tragically, the only GoF pattern that can help code get smaller (Interpreter) is utterly ignored by programmers who otherwise have the names of Design Patterns tatooed on their various body parts.
Dependency Injection is an example of a popular new Java design pattern that programmers using Ruby, Python, Perl and JavaScript have probably never heard of. And if they've heard of it, they've probably (correctly) concluded that they don't need it. Dependency Injection is an amazingly elaborate infrastructure for making Java more dynamic in certain ways that are intrinsic to higher-level languages. And – you guessed it – DI makes your Java code base bigger.
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.
Millions of Lines of Code
I recently had the opportunity to watch a self-professed Java programmer give a presentation in which one slide listed Problems (with his current Java system) and the next slide listed Requirements (for the wonderful new vaporware system). The #1 problem he listed was code size: his system has millions of lines of code.
Wow! I've sure seen that before, and I could really empathize with him. Geoworks had well over ten million lines of assembly code, and I'm of the opinion that this helped bankrupt them (although that also appears to be a minority opinion – those industry programmers just never learn!) And I worked at Amazon for seven years; they have well over a hundred million lines of code in various languages, and "complexity" is frequently cited internally as their worst technical problem.
So I was really glad to see that this guy had listed code size as his #1 problem.
Then I got my surprise. He went on to his Requirements slide, on which he listed "must scale to millions of lines of code" as a requirement. Everyone in the room except me just nodded and accepted this requirement. I was floored.
Why on earth would you list your #1 problem as a requirement for the new system? I mean, when you're spelling out requirements, generally you try to solve problems rather than assume they're going to be created again. So I stopped the speaker and asked him what the heck he was thinking.
His answer was: well, his system has lots of features, and more features means more code, so millions of lines are Simply Inevitable. "It's not that Java is verbose!" he added – which is pretty funny, all things considered, since I hadn't said anything about Java or verbosity in my question.
The thing is, if you're just staring in shock at this story and thinking "how could that Java guy be so blind", you are officially a minority in the programming world. An unwelcome one, at that.
Most programmers have successfully compartmentalized their beliefs about code base size. Java programmers are unusually severe offenders but are by no means the only ones. In one compartment, they know big code bases are bad. It only takes grade-school arithmetic to appreciate just how bad they can be. If you have a million lines of code, at 50 lines per "page", that's 20,000 pages of code. How long would it take you to read a 20,000-page instruction manual? The effort to simply browse the code base and try to discern its overall structure could take weeks or even months, depending on its density. Significant architectural changes could take months or even years.
In the other compartment, they think their IDE makes the code size a non-issue. We'll get to that shortly.
And a million lines is nothing, really. Most companies would love to have merely a million lines of code. Often a single team can wind up with that much after a couple years of hacking. Big companies these days are pushing tens to hundreds of millions of lines around.
I'll give you the capsule synopsis, the one-sentence summary of the learnings I had from the Bad Thing that happened to me while writing my game in Java: if you begin with the assumption that you need to shrink your code base, you will eventually be forced to conclude that you cannot continue to use Java. Conversely, if you begin with the assumption that you must use Java, then you will eventually be forced to conclude that you will have millions of lines of code.
Is it worth the trade-off? Java programmers will tell you Yes, it's worth it. By doing so they're tacitly nodding to their little compartment that realizes big code bases are bad, so you've at least won that battle.
But you should take anything a "Java programmer" tells you with a hefty grain of salt, because an "X programmer", for any value of X, is a weak player. You have to cross-train to be a decent athlete these days. Programmers need to be fluent in multiple languages with fundamentally different "character" before they can make truly informed design decisions.
Recently I've been finding that Java is an especially bad value for X. If you absolutely must hire an X programmer, make sure it's Y.
I didn't really set out to focus this rant on Java (and Java clones like C#, which despite now being a "better" language still has Java's fundamental character, making it only a marginal win at best.) To be sure, my minority opinion applies to any code base in any language. Bloat is bad.
But I find myself focusing on Java because I have this enormous elephant of a code base that I'm trying to revive this week. Can you blame me? Hopefully someone with a pet C++ elephant can come along and jump on the minority bandwagon with me. For now, though, I'll try to finish my explanation of bloat as a bona-fide problem using Java for context.
Can IDEs Save You?
The Java community believes, with near 100% Belief Compliance, that modern IDEs make code base size a non-issue. End of story.
There are several problems with this perspective. One is simple arithmetic again: given enough code, you eventually run out of machine resources for managing the code. Imagine a project with a billion lines of code, and then imagine trying to use Eclipse or IntelliJ on that project. The machines – CPU, memory, disk, network – would simply give up. We know this because twenty-million line code bases are already moving beyond the grasp of modern IDEs on modern machines.
Heck, I've never managed to get Eclipse to pull in and index even my 500,000-line code base, and I've spent weeks trying. It just falls over, paralyzed. It literally hangs forever (I can leave it overnight and it makes no progress.) Twenty million lines? Forget about it.
It may be possible to mitigate the problem by moving the code base management off the local machine and onto server clusters. But the core problem is really more cultural than technical: as long as IDE users refuse to admit there is a problem, it's not going to get solved.
Going back to our crazed Tetris game, imagine that you have a tool that lets you manage huge Tetris screens that are hundreds of stories high. In this scenario, stacking the pieces isn't a problem, so there's no need to be able to eliminate pieces. This is the cultural problem: they don't realize they're not actually playing the right game anymore.
The second difficulty with the IDE perspective is that Java-style IDEs intrinsically create a circular problem. The circularity stems from the nature of programming languages: the "game piece" shapes are determined by the language's static type system. Java's game pieces don't permit code elimination because Java's static type system doesn't have any compression facilities – no macros, no lambdas, no declarative data structures, no templates, 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.
Completing the circle, dynamic features make it more difficult for IDEs to work their static code-base-management magic. IDEs don't work as well with dynamic code features, so IDEs are responsible for encouraging the use of languages that require... IDEs. Ouch.
Java programmers understand this at some level; for instance, Java's popular reflection facility, which allows you to construct method names on the fly and invoke those methods by name, defeats an IDE's ability to perform basic refactorings such as Rename Method. But because of successful compartmentalization, Java folks point at dynamic languages and howl that (some) automated refactorings aren't possible, when in fact they're just as possible in these languages as they are in Java – which is to say, they're partly possible. The refactorings will "miss" to the extent that you're using dynamic facilities, whether you're writing in Java or any other language. Refactorings are essentially never 100% effective, especially as the code base is shipped offsite with public APIs: this is precisely why Java has a deprecation facility. You can't rename a method on everyone's machine in the world. But Java folks continue spouting the provably false belief that automated refactorings work on "all" their code.
I'll bet that by now you're just as glad as I am that we're not talking to Java programmers right now! Now that I've demonstrated one way (of many) in which they're utterly irrational, it should be pretty clear that their response isn't likely to be a rational one.
Rational Code Size
The rational response would be to take a very big step back, put all development on hold, and ask a difficult question: "what should I be using instead of Java?"
I did that about four years ago. That's when I stopped working on my game, putting it into maintenance mode. I wanted to rewrite it down to, say, 100,000 to 150,000 lines, somewhere in that vicinity, with the exact same functionality.
It took me six months to realize it can't be done with Java, not even with the stuff they added to Java 5, and not even with the stuff they're planning for Java 7 (even if they add the cool stuff, like non-broken closures, that the Java community is resisting tooth and nail.)
It can't be done with Java. But I do have a big investment in the Java virtual machine, for basically the same reason that Microsoft now has a big investment in .NET. Virtual machines make sense to me now. I mean, they "made sense" at some superficial level when I read the marketing brochures, but now that I've written a few interpreters and have dug into native-code compilers, they make a lot more sense. It's another rant as to why, unfortunately.
So taking for granted today that VMs are "good", and acknowledging that my game is pretty heavily tied to the JVM – not just for the extensive libraries and monitoring tools, but also for more subtle architectural decisions like the threading and memory models – the rational answer to code bloat is to use another JVM language.
One nice thing about JVM languages is that Java programmers can learn them pretty fast, because you get all the libraries, monitoring tools and architectural decisions for free. The downside is that most Java programmers are X programmers, and, as I said, you don't want X programmers on your team.
But since you're not one of those people who've decided to wear bell-bottom polyester pants until the day you die, even should you live unto five hundred years, you're open to language suggestions. Good for you!
Three years ago, I set out to figure out which JVM language would be the best code-compressing successor to Java. That took a lot longer than I expected, and the answer was far less satisfactory than I'd anticipated. Even now, three years later, the answer is still a year or two away from being really compelling.
I'm patient now, though, so after all the dust settles, I know I've got approximately a two-year window during which today's die-hard Java programmers are writing their next multi-million line disaster. Right about the time they're putting together their next Problems/Requirements slide, I think I'll actually have an answer for them.
In the meantime, I'm hoping that I'll have found time to rewrite my game in this language, down from 500,000 lines to 150,000 lines with the exact same functionality (plus at least another 50k+ for unit tests.)
The Next Java
So what JVM language is going to be the Next Java?
Well, if you're going for pure code compression, you really want a Lisp dialect: Common Lisp or Scheme. And there are some very good JVM implementations out there. I've used them. Unfortunately, a JVM language has to be a drop-in replacement for Java (otherwise a port is going to be a real logistics problem), and none of the Lisp/Scheme implementors seems to have that very high on their priority list.
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.
So it's not gonna be Lisp or Scheme. We'll have to sacrifice some compression for something a bit more syntactically mainstream.
It could theoretically be Perl 6, provided the Parrot folks ever actually get their stuff working, but they're even more patient than I am, if you get my drift. Perl 6 really is a pretty nice language design, for the record – I was really infatuated with it back in 2001. The love affair died about five years ago, though. And Perl 6 probably won't ever run on the JVM. It's too dependent on powerful Parrot features that the JVM will never support. (I'd venture that Parrot probably won't ever support them either, but that would be mean.)
Most likely New Java is going to be an already reasonably popular language with a very good port to the JVM. It'll be a language with a dedicated development team and a great marketing department.
That narrows the field from 200+ languages down to maybe three or four: JRuby, Groovy, Rhino (JavaScript), and maybe Jython if it comes out of its coma.
Each of these languages (as does Perl 6) provides mechanisms that would permit compression of a well-engineered 500,000-line Java code base by 50% to 75%. Exactly where the dart lands (between 50% and 75%) remains to be seen, but I'm going to try it myself.
I personally tried Groovy and found it to be an ugly language with a couple of decent ideas. It wants to be Ruby but lacks Ruby's elegance (or Python's for that matter). It's been around a long time and does not seem to be gaining any momentum, so I've ruled it out for my own work. (And I mean permanently – I will not look at it again. Groovy's implementation bugs have really burned me.)
I like Ruby and Python a lot, but neither JVM version was up to snuff when I did my evaluation three years ago. JRuby has had a lot of work done to it in the meantime. If the people I work with weren't so dead-set against Ruby, I'd probably go with that, and hope like hell that the implementation is eventually "fast enough" relative to Java.
As it happens, though, I've settled on Rhino. I'll be working with the Rhino dev team to help bring it up to spec with EcmaScript Edition 4. I believe that ES4 brings JavaScript to rough parity with Ruby and Python in terms of (a) expressiveness and (b) the ability to structure and manage larger code bases. Anything it lacks in sugar, it more than makes up for with its optional type annotations. And I think JavaScript (especially on ES4 steroids) is an easier sell than Ruby or Python to people who like curly braces, which is anyone currently using C++, Java, C#, JavaScript or Perl. That's a whooole lot of curly brace lovers. I'm nothing if not practical these days.
I don't expect today's little rant to convince anyone to share my minority opinion about code base size. I know a that few key folks (Bill Gates, for instance, as well as Dave Thomas, Martin Fowler and James Duncan Davidson) have independently reached the same conclusion: namely, that bloat is the worst thing that can happen to code. But they all got there via painful things happening to them.
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.
But as for you, the eager young high school or college student who wants to become a great programmer someday, hopefully I've given you an extra dimension to observe as your tend your code gardens for the next few years.
When you're ready to make the switch, well, Mozilla Rhino will be ready for you. It works great today and will be absolutely outstanding a year from now. And I sincerely hope that JRuby, Jython and friends will also be viable Java alternatives for you as well. You might even try them out now and see how it goes.
Your code base will thank you for it.
163 comments:
If you could snap your fingers and bring Perl 6 on Parrot's implementation up to the level of Rhino's, would you still choose JavaScript?
I wish he could snap his fingers to get rid of his anti-Ruby collaborators. Ha. :-)
But, I'm training for decent athlete status myself.
And I'm hoping for a quick release of that Emacs + JavaScript IDE / byte-code compiler. :-)
I think you make a lot of good points in your post. I also, however, think you're confusing the problem of codebase size with code duplication. I'm all for removing duplication from my code, and keeping it as small as possible in the meantime. But there's a point where making code smaller by using macros, terse languages and the like actually harms the maintainability of the code as much as code bloat does.
Just so you know where I'm coming from, I've worked professionally only in C++ and Java. I think they're fine tools for a lot of jobs, but they do leave a lot to be desired as you've pointed out. My personal projects, however, range from Perl, Python, Java, C++, and Assembly all the way up to my most recent favorite language, which is Ruby. Ruby offers a lot of extra power, and I've got a personal project I'm working on right now that's using JRuby. (I agree wholeheartedly with you about VMs, by the way.)
But that doesn't mean that I like Ruby just for its terseness. As a good example of what horrors you can inflict on people in the same of reducing code size, go take a look at this MUD written in Ruby in only 15 lines of code. Would YOU want to try and add a feature to that? Granted, it's an extreme example, but I think it illustrates the problem with your thesis. Yes, codebase size can be a problem. But reducing size by decreasing readability is just as big of a problem.
Anyone dumb enough to have curly braces as a requirement is never never going to consider Javascript to be a legitimate language for developing "real" apps
Did you consider Scala at all? Ramming JRuby down people's throats still sounds like a good option too ;)
I tried to "learn programming" via Java 1.1 in high school back in the day, self-taught. My plan was to build a MUD server and client and use XML for data storage. It was... fun. Years later, in college, I did it again in Java and then in C#, always getting to the point of no longer liking what I was doing at pretty much the same stage of functionality.
Recently, as a way of evaluating the true ninja-like qualities of Ruby, I decided to re-write it using Ruby and YAML.
My personal experience, to your point, was that the Ruby version came out 1) massively smaller in code size, 2) far easier to debug and pick up after long periods of awayness, 3) in at least 1/3 of the time it took previously and 4) had ass-loads more functionality in that time frame.
Now, you could argue that my first go was as a green programmer, but the college versions were written while I was earning a degree in software engineering and (WORSE) the Ruby version was written after having worked in Marketing for a few years. Marketing!
I used Smultron. Not really scalability concerns, there. It turned out that the benefits of an IDE were only valuable because what I was doing was needlessly complex enough that an IDE became relevant. IDEs are not features of a lanaguage, in my opinion, but necessities of a language due to a lack of other features - at least to some scale.
Good stuff. As a poet, I loved the camel metaphor.
Can you say a bit more about why, exactly, you're up at 500,000 lines of code? I can guess, but the idea of one programmer working along and getting to that amount of code is a bit startling.
Good! Let's go with JavaScript, also known (to some) as Lisp/Scheme in the sheeps clothing.
And you have the right word to sell it: "Interpreter Pattern". You cannot sell anything to Java Community without first saying a spell from GoF book.
What about SCALA?
I find SCALA to be a pretty easy language to get excited about. Great expressiveness and integration into the JVM.
What about something like JPype:
http://jpype.sourceforge.net/
For some stuff you can use Python when convenient (like string processing) and for other stuff you can use Java (like library support).
@Alec,
> Yes, codebase size can be a problem. But reducing size by decreasing readability is just as big of a problem.
Lots of people assume software's length and clarity are linearly correlated. But consider this:
"I think what is wanted with programming languages and programs intended for human consumption is something along the lines of "the greatest meaning-based compression" (or "greatest semantic compression", to be more succinct). If greatest possible compression were the goal, then all that would be needed to write succinct programs would be to run the final program through a compression program like gzip."
That comes from this post, succinctness = power. Since I originally found it from Steve Yegge's Ten Challenges, I think that's probably what he's going for.
Just tossing an idea - beside reducing the size of the dirt you could also ship it to someone else. I mean someone who would actually welcome it.
Hmm I think I'll stop being metaphorical now - how about
turning parts of the program as libraries and publishing them with some Open Source license?
Sir C.A.R. Hoare agrees: "The price for reliability is the pursuit of the utmost simplicity. It is a price which the very rich find most hard to pay." (cribbed from Dijkstra's EWD1304)
Count me in the minority, too. Code size is a huge problem, and like you suggest, programmers who aren't familiar with templates, generics, lambdas, and tuples (I'd say macros, too, but I'll leave that for lispers) will be missing useful tools for compressing their code.
OTOH, today you don't get checks for writing with languages that have strong support for those approaches. That is, unless you start your own company and sell it for a hefty sum because you got in before anyone else had a chance to finish ;)
Amazon has 100 million lines of code? Are you sure? Unbelievable!!! Windows is around 50 million, Solaris is ~ 35 million.
I agree that size can be a big problem (I'm working on a very large Java project) but I'm not convinced that 200,000 lines of Ruby code really is more maintainable than 500,000 lines of Java. We programmers have a lot of experience in dealing with large Java/C/C++ codebases but has anyone got 200,000 lines of Ruby?
Jeff Atwood recently discussed the problems with Bugzilla and its large Perl codebase. Sometimes the LoC is not the problem but the functional complexity of the system.
@Jamie,
> ...I'm not convinced that 200,000 lines of Ruby code really is more maintainable than 500,000 lines of Java...Sometimes the LoC is not the problem but the functional complexity of the system.
Since ruby allows for greater semantic compression, I think a ruby system done well would take much longer to reach 200 kloc, than a Java system would to reach 500 kloc.
The trick is to maximize semantic compression, not just LoC.
Most programmers are Javascript users these days. That should not be taken to imply any fondness for curly braces and semicolons. I love the dynamicism and the object model. Unfortunately, most people proposing changes to the language want to keep the syntax and scrap the object model.
Just taken a look at Rhino. NBL is shaping up nicely.
Before ruling out Scheme, try
SISC. http://sisc-scheme.org/
Maybe you did this already, but I
never saw you mentioning it in
your blog.
It is a *great* JVM Scheme
implementation, with good
documentation.
I also like the JVM and this
combination of Scheme and the JVM
is working very well for me.
SISCWeb (http://siscweb.sourceforge.net/)
is also very nice.
That's a lot of words just to say "code is a liability". :-)
As opposed to everyone else here commenting on code size vs functional complexity vs blah, I really want to ask one question.
Can I join you in your venture of rewriting this game, or is this a solo effort?
Agreed that code size is a problem, and the language of choice can definitely lead to bloat.
That being said, I've worked with many smart folks - "good" programmers, who just don't raise their level of abstraction even when the language allows it. And that holds doubly so when time is "of the essence" - as it often feels when on a deadline.
Another vote for Scala. I like Javascript and Rhino sounds interesting, but Scala is a much more powerful, expressive language.
Suppose you structured your code in such a way that you only had to look at under 1000 LoC at a time in order to do useful work. Would the 500KLoC be as big a problem?
First of all I would agree that code-base size is as big a problem as you say. However, I would posit that the size of the problem be more of a function of the structure/design of the code, than just the number of LoC.
The latest system I put into production had roughly 500KLoC. Developers would have only a couple thousand LoC in their IDE open at a time. This came about as a result of a much architectural and design work.
[You can find some of the patterns and frameworks we used on my blog: http://udidahan.weblogs.us]
Thoughts?
Also, I have a different take on the 'millions of lines of code' problem:
If I leverage 'millions of lines of code' from Apache projects, Eclipse, and a few other third-party modules in a small app with a Maven POM, is that the same thing?
How about if I have a larger app, like a game, but the game engine, logic, etc. are modularized in a similar fashion?
Maybe millions of lines of code are inevitable. But as long as they're well-defined to the point you don't have to pull them all into your head at once, there's no problem.
I agree that reorganizing into new containers and shelves won't solve anything. Its all about defining good modules and keeping those modules current and relevant in the face of unanticipated changes that would cause them to otw grow strange appendages.
Why can't that be done in Java? Apache and Eclipse seem to pull it off well enough...
@Casey
I get the feeling that's why he chose the JVM. He had existing code as well as the multitude of code that makes up the JVM supporting libraries.
Steve, I'm stealing this quote: "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."
If you ever see it again (which is unlikely with my modest blog) you're welcome to retaliate.
I assume when measuring the size of your game, you didn't include the JDK. That suggests another way to reduce lines of code: write code for a more featureful platform. The lines don't disappear, but they become someone else's problem.
You know that the fearfulness of bloat applies equally well to documents in natural language, too?
Rhino is a Java implementation of an ECMA script interpreter, right?
How does it do speed-wise?
Are you envisioning a Java program that's just a thin wrapper around Rhino and the "real" program is written in ECMA?
Have you looked at Lua at all?
How about LISP on JVM? Have you looked at clojure?
http://clojure.sourceforge.net/
+1 Scala.
"Its a poor workman who blames his tools." -- Anonymous
Highly structured languages make complexity possible. Scripting languages fall over before you get anywhere near the same level of complexity. if you consider that a feature I suppose thats your business.
(And Yes, I've done a lot of Java and a lot of PERL in my day. And C, C++, Modula2... )
I think you probably missed the most important tool you could have used on this project, though now maybe its a bit late...
Effective Java
It seems to me that you've experience the power of Java and it's allowed you to create something much bigger than you imagined you could. It's probably bigger than you can manage to support. So, this is the point that you have to decide is it a multi-developer project or is it still just your little pet?
There was a lot of text and I skimmed a lot. Did you tell us what the name of your game is and where to find it when you get it back on line?
Wow, that was long...I read only the first couple of paragraphs. But I was pleased that I found the word "garden" when I searched the rest of the text, as I believe it is a useful metaphor: If you only "plant" and never "weed", you won't have a pleasing result.
"The Java community believes, with near 100% Belief Compliance, that modern IDEs make code base size a non-issue. End of story.
"
Actually, we believe that IDE's make us much more productive when we have to manage code bases of varying sizes. Big difference than making "code base size a non-issue". Code base size is always an issue in probably any language you write.
Finally, I don't think your 500,000 line Java game is a good example. Mainly because you are the only one maintaining it and you're the only one who has written the code. Try dealing with an OSS project where code contributions come from volunteers who may or may not stick around to maintain their code. Coming from that perspective an IDE is invaluable to data mine, debug, and refactor code for the OSS project leads. Reliable refactoring and code analysis are crucial.
Personally, I feel most of Java's problems lie not with the language itself but with the libraries and frameworks within the JDK and outside the JDK. Rails, is IMO, the only reason Ruby has gotten any traction. Its filling the productivity void that EE has generally failed on.
you people seem to have missed the coolest (and probably the fastest) JVM language of them all...
CLOJURE
google it.
functional programming, macros, software transactional memory, etc.
you can't lose.
+1 Scala
Right there with you. I have a seemingly smaller problem than you -- 250Klines of C# and a team of people -- but the code base is just not as malleable as I'd like it to be.
Over the last 6 months, I've started attacking it from multiple directions.
For one thing, I'm integrating an IronPython interpreter. Initially, this is just for application scriptability, but long-term, I'm hoping we can replace enormous chunks of C# with it in the upper layers. I picked IronPython because it's the closest thing to a mature language out there that runs on the .Net CLR.
On the flipside, I've started integrating F# (Microsoft's OCaml variant for .Net) in the lowest layers. Initially it's as the back end for some DSLs that we're using to simplify some messy and complex code, but I'd like to see it start flatly replacing C# in a lot of places. So far, the only real problem with F# is that writing F# libraries to be used from C#, while better than using C# itself, is more cumbersome than writing F# that only has to be called from itself.
The early returns are that this is helping. It seems like a multi-language strategy is at least helping to keep our code's growth rate contained. If it gets proven, I may be able to make a push for using the new languages to actually shrink the code base, which would be a nice win.
So what's the game??? I want to play.
I see where you're coming from, but I think you're seeing a symptom as the problem. Large code is monstrously hard to manage, but I don't know that the fact that it is large code is the issue.
Can you give more information about why exactly you think this is the problem with your code? How did you reach this conclusion exactly?
Let me prescribe you a better solution:
Java programmers will stop writing bloat codes if Author Stevey stops writing bloat article about bloat Java programs without giving any factual or statistical analysis to the cause (and why these other P* languages will solve the problem.)
Oh... let's not blame the author. Let's just blame English being a bloat and bulky language.
The code size of your rant is too big and bloated.
I tried to load it into my brain, but it just hung, indefinitely, until I force quit it.
I believe the game in question is Wyvern, which was hosted at http://www.cabochon.com/
It's sort of a mud but with a graphical interface as well.
I think most technologies suffer in their success - as more people participate in the community, more competing (and complementary) thoughts/patterns/practices vie for our attention and we understand more about what problems the technology didn't solve well. We then focus on that and lose sight what problems the technology did solve well.
Good software designers need to carefully weigh both sides (instead of getting caught up in the 'throw it out' mindset) and calculate how to bridge the gap. On that very tactical point, I totally agree that selective application of dynamic languages in an existing JVM-based application is absolutely the right way to go and achieve "semantic compression" without sacrificing too much existing investment. Further, such a decision needs to weigh factors like talent availability - the code most likely will be maintained by a third party.
I'm a Rails novice (and thus, in the 'honeymoon' period), but thoroughly expect the community to go through the same contortions in 5(+/-) years. Look at Perl. Look at JavaScript. Extrinsic factors drastically changed the fortunes of both languages in the preceding 5 years.
Semi-related: http://icedjava.blogspot.com/2007/12/dear-java-thanks-for-complexity-of.html
Steve, you sure discounted Lisp fairly quickly considering that you have made no mention that other people will be using your code base. Are you unwilling to say that you yourself dislikes Lisp?
I am writing a pretty heavyweight game in Lisp, using real graphics middleware like Gamebryo. I fail to see what a lack of a VM provides, and I wonder if the speedup from using sbcl/corman common lisp will outweigh the immediate performance hit from your application's dependance on the jvm threading model.
I think the core premise (your code is 500k lines; unit tests would double it; there is no hope!) is wrong.
Proper modularization, which really requires a good set of unit tests, would fix your problem by making one 500k project into, say, ten 10k projects, each of which acts somewhat independently. At that point, working on any of the areas of the application is working on a single 10k application with 9 additional libraries being used (in addition to the many standard and third-party libraries you are already using).
There is a certain level of verbosity in Java, and much of the required syntax doesn't do a good job of "fading into the woodwork" leaving just your functional code. Likewise, the lack of defined language constructs makes cut-and-paste (which is what patterns are) necessary, and you are right that that is bad. So, point taken there. I just don't see that as a 2-5x differential in apparent code complexity. I'd gauge that more as a 10% differential, of course varying depending on the particulars of the project.
If dynamic typing is desired in your application hacking that into Java isn't the best use of your time. Dead stop there. If you want/need dynamic types, move off Java.
Still, a 500k application need not be overwhelming, if it was designed "well" in the first place.
So, was there something keeping this from being modularly designed?
I agree that code size or bloat is an issue, but what is being discussed is really compression. Think of a picture or a movie: Each as some discrete values that are displayed. You could create a file for each for each describing all attributes of each attribute. This then properly captures the Meta data such as shapes and faces. What people have found over the years is that the size of these files is large. In order to reduce the size, you can do one of two things: 1) Reduce the number of attributes saved (resolution, depth, etc). 2) Enable some compression method. Compression methods typically look for patterns, but there are other types as well. Sometimes you do both things at once. Can you take three different pictures and reduce all to a single bit and still tell the differences between the original images? Nope, not possible.
You can think of lines of code as the same thing. Yes, using macros or another language might reduce the lines of code, but it probably does not reduce the complexity. Not unless you are also reducing the functionality (as many scripty/webby languages tend to do).
Suppose you have two languages X and W. X has 20 tags and W has 100 tags (instead of tags, I could say functions or operations or syntax or…). You can presume that something written in W will be smaller than something written in X, particularly if W has all the tags of X. Does this make the program less complex? Not really. Instead of the developer having to learn 20 things, she now has to learn 100 and that does not include knowing anything about the program itself, i.e. what it is suppose to do.
So you say the previous example does not apply, then lets try this. Suppose you have languages X and Y. X has 20 tags and Y has 20 tags but lets you use macros. You can presume that something written in Y is smaller than something in X. But is it less complex to understand? Once again, macros are just adding more tags to language Y.
To make matters worse, when you start to combine multiple languages, especially if you count XML as a language (it is really a meta language), then not only does the developer have to learn all the used parts of each language used, but has to learn how to use one over another and the complexities of moving from one to another.
Am I Java Developer? Definitely. Is Java a perfect language for every situation? Definitely Not!! Not even in Most Situations. The same could be said for any language. Any language is going to have issues (proponents, detractors, snobs, and blind followers).
So I said I agreed that code bloat is an issue, yet I went and proved that solving it by using a different language (or yet another language) does not solve the problem. I think the real problem is complexity. The more functionality you have, the more complex it becomes. If you have 500K lines that are easy to read (which your game is not), then 150K lines probably does not make it any less complex. Not unless you copied/pasted each line of code 3 times.
Lastly, developers should stop looking for the “silver bullet” of development. There is no such thing. The next language is not going to solve your problems, nor is the next design book (GoF = GOOFS?), nor the next management methodology (agile…make me walk instead of run).
Writing and maintaining a multi-million-line Java program is easy enough,
if you manage to split it up into a few hundred sub-projects (libraries)
that each have a very small "surface area" (public interfaces) that hardly
ever change.
Of course, definining these interfaces is hard, and keeping them non-"leaky"
is even harder. (In a sense, all that easy and obvious interface abstractions
have already have been defined and are now part of the runtime environment
(or event the operating system) -- hardly anybody has to implement their own
network stack, file system, or process scheduler anymore.
There are many factors in why a specific language is picked for a software project, my interpretation of what you're saying is that the size of resulting code base is not given enough priority in the decision making process.
I understand that the blog is a rant and so is more emotional rather than about rational analysis but I do think it might be nice to have a follow up where you look at specifics of how Java bloat is eliminated by languages with different features.
When the company that I work for did this we actually ended up creating our own language with the feature list we wanted. Similar to you, one of our desires was to have it work on the JVM.
This language (called Cal) has now been open sourced and can be found here:
http://openquark.org/
I've hit a few painful things over the years, but more importantly I saw the light ages ago when I got to work on an incredibly elegant bit of code. The language has some effect, but more often it is using brute force to pound out your solution that produces fat and ugly code.
Bloat and artificial complexity don't have to be problems. They often stem from the project's organization structure and/or its processes. Even a single developer can cause a problem. If you had been more disciplined, I bet your 500,000 lines could have easily been implemented in half, if not a quarter of the size. I've been ranting about that for years, but as you say nobody takes size seriously as an issue.
That said, I do find Java to be much fatter than languages like Perl or C. Some days it feels so close to VB that it makes me shiver.
Paul.
Boo. Ok, its CLR, not JVM but at least you get JVM support with IKVM. And Boo should be tried once, just for its logo if not for anything else.
(Oh, completely agree on bloat. Sure.)
Dare I mention Fortress?
I'm a mobile developer so I feel your pain. Code base is a real problem for us...as every byte we put out in code is a byte less that we can use for heap memory. Systems are getting easier, but it used to be a real problem. Now just imaging having to write a Java program in the least number of lines possible...and you start to see the problem with mobile dev. :-)
You know, Steve,
you kinda fail to explain why this is a problem in the larger scheme of things and how it fits into that scheme. For example, in the old days, car mechanics could take apart and fix an entire car by themselves. Same for television amateurs. But these days, the amount of computer technology and integration in such machines makes them into mere bystanders. You sound a bit like an old television amateur who bemoans the amount of complexity present day's devices represent, while not talking about the greater picture and at the same time quite enjoying the extra functionality or performance his device offers him.
The only thing that can beat complexity is simplicity; does expressiveness elicit simplicity or is it just a way to shrink code? You do not make it clear. If you can shrink your code down to even 20%, just wait a couple of years, and you'll be back to where you started. There's a basic tendency in human culture that bespeaks of this motion, and it is the desire for more and better. But in principle, size needs to be no enemy; the only requirement is that the amount of information you have to deal with at any level, is kept at a certain minimum. That is why OS X is so praised, and why Windows will for a long time be more popular than desktop Linux: the amount of options open to you at any point in time is so very limited and that is what makes it easy to use. The same holds for software. Compare the man page for 'rpm' with that of 'dpkg' and you'll see what I mean. Abstraction, small interfaces, limited options, modularisation, hierarchy, layering, you name it.
I am not speaking as a senior programmer, but as one of target audience, not yet familiar with scripting languages. But I also have a bit of a mental block regarding complexity: I cannot hold as many pieces of information 'in vision' and have a bit of a harder time digesting information than most people. Because of that, I'm perhaps a bit better qualified to speak of such things. And I will tell you this: most people - most programmers - do not appreciate the difficulty people can have with the digestion and navigation of information, and this applies to everyone. Introducing simplicity at every step and every boundary and every interface, and limited, self-contained areas of relevance for any given viewpoint, is the most important thing in making complex systems simple and manageable.
If you have a system of 7 layers each of which has seven more layers, and so on, into infinity, will it be hard to manage? No. You can easily understand the working of the system at any level from any viewpoint, and the levels/area's you cannot see are irrelevant to the understanding of that part of the system you can see at any time. You will need more people to do the management of course, and there may be more to manage than if you had not been so vigorous in modularizing, but it will be a lot easier to do.
Maybe my lack of experience with large projects is speaking through, but I just want to make a general point.
I said as much here recently:
http://beust.com/weblog/archives/000462.html
ie, big code bases talk to maintanancea a lot more than your pet language's typing features
But now I see Bob Lee responding to my non-existent comment, so looks like it got pulled. Oh well.
@Udi and Tom:
I'd conjecture that in a way, modularity/limited visibility can make the code "size" problem worse, for a very simple reason: You don't know what's in there that you aren't looking at.
It's a lot easier to make a small code base "modular", in the sense of orthogonality. If you suddenly realize that you should be abstracting out, say, your text-formatting routines into a text-formatting object or library, you can do that. If the project is small enough, you can probably just scan through the thing visually and find all the text-formatting code. Or you can go tell the three other guys who work on the code to start using your new library.
When a project has millions of lines of code - you just can't do that. Nobody knows where to find all the routines that use text formatting. Sure, search capabilities are helpful, but they're not all-powerful.
This is a bigger problem with large dev teams, where there are developers you probably don't even know exist who are, at this very minute, writing something that formats text. But even one-man teams can suffer from it, because you're not always going to remember something you wrote a few years back.
I had the recent joy of looking at code I wrote 15 years ago. The first thing I noticed was that I made extensive use of linked lists, but I repeated a lot of the code. At the time, it was intentional; function calls were too expensive. But now we have fast computers, so I resolved to write myself a linked-list helper library.
A little further into the project, I was looking through some other code, and - what do you know! - found a linked-list helper library. It seemed like just what I needed. And that's when I realized - it ought to, because *I* wrote that. I just hadn't looked at it in 15 years, and neither had anyone else. So if I can't even remember to use my own abstractions, how can I expect the rest of the company to?
There's an anti-pattern I keep seeing, but haven't found a great name for yet. I call it "stratification".
Basically, the more you write high-level libraries that wrap lower-level ones, the less you use the low-level libraries. Thus, the less you understand them. At some point, you forget they even exist. At that point, you will - inevitably - write an even-higher-level library that recreates the lower-level functionality ON TOP OF the high-level library.
And if you've ever scanned in a document so you could use fax software to transmit it to a remote bank of faxmodems which will make a voice call over an IP-based, packet-switched telephone network only to reach another faxmodem in the same data center which will take the fax, convert it to a PDF and send it via e-mail to your recipient, who reads it via a web-based mail interface that uses JavaScript to implement offline mail reading functionality... you know what I'm talking about.
Seriously, am I the only one who wants to have a go at this game, bugs or no bugs?
Come on, stick it back up! Post a link. Post a linnnnnk.
It's in Java, it's not like it's going to wipe my hard drive. Well, maybe, but that'd be damn impressive.
I don't see how you prove your main point, that code size is an issue. You spend a lot of time saying it is, but offer up little in the way of proof or examples. (EG: what was the bad thing that happened to you?) It's not hard to say "code size is a problem". It's hard to say why it's a problem and give examples of 1) code that is too big/bloated and 2) code that does the same thing more succinctly.
Simple code-size reduction is not a silver-bullet. C and C++ are capable of very compact code that is almost as hard to read as Perl code. (see the ioccc - http://www.ioccc.org/ )
What I think you're getting at is code size reduction while maintaining readability. An altogether different beast and one that requires good design as much as language choice.
None of that should be taken as disagreement. Huge code-bases are beasts and have their problems. I like the idea of what you're attempting to show. I just think you've failed to adequately prove your point.
Tangentially, I wonder how much reduction is possible. This drive to write smaller code sounds very similar to the ideas behind the infamous programmer-induced rewrite. Namely, the "I can do it better!" syndrome. A noble idea, and not always misplaced. But rewriting code because the original code is ugly/too big isn't a panacea either. Crufty, old code contains a lot of knowledge about the problem being solved, earned over many years (through many nasty bugs and hours of debugging them) and encoded in usually inelegant ways. Tossing that and rewriting from scratch means you have to go through that learning process again.
There's a balance between good and good enough and simply assuming any code base over some number of lines of code is bad is near-sighted to say the least. Large problems sometimes need large solutions.
The simplistic solution, breaking the program into smaller programs that work together to solve the larger problem, only masks the problem and pushes it to someone else's plate (the poor schmuck that has to get the programs to work together correctly).
+1 Scala. Steve, could you please comment on your thoughts about Scala compared to Mozilla Rhino?
Thanks.
Amen! As a (currently)Java programmer, this frustration is what's driving me towards my own JVM language. Luckily, it has no due dates or constituency, so I can be very, very "patient" with it.
It boggles my mind that bigger is seen as better -- maybe what we need is APL for the JVM? :-)
+1 Scala. My guess is that Stevey just prefers dynamic typing. But there's not much you'll need to do in practice that Scala's type system can't express. BTW, The Scala book is now out in PDF.
Great post, I agree in principle with the code bloat argument. However, I notice Steve doesn't count the lines of code comprising the code base of the OS, JVM, or the Java libraries he uses as part of the code bloat.
I believe this is because a stable and well-designed (or well ... designed in the case of the Java libraries) and well-tested component doesn't require the mental overhead of a poorly-designed component.
Now, it is true that these things tend to be services and infrastructure, not domain elements, and services tend to have much firmer interfaces over time than domain classes, which change as your understanding of the problem domain and customer changes. However, I suspect that in any application a good portion of the code are value objects and services, not domain code. Anything to make that portion smaller is almost certainly a good idea.
Perhaps that is the future: systems and infrastructure programming in C# or Java surrounding domain programming in your favorite scripting language, which is as mutable as domains tend to be.
So when are your tips for tech interviews coming up? I have one coming and could use some advice!
Could you explain why you think VMs are important and/or useful? I am curious about this.
I'm also going through a VM scri