Weblog

04/28/06: JSLint

I've been doing a lot of JavaScript (and a lot of cursing) lately. Edward pointed me to JSLint, which checks the syntax and style of your JS code. I think it's too strict (but it's supposed to be) but I do recommend reading the documentation -- the explanations of /why/ JSLint complains are clear and insightful.

Read More!

alex  Code 

04/01/06: JavaScript and Ruby support in IDEA

In addition to Ruby, I've been doing a lot of JavaScript programming lately, and I've just moved from Eclipse to IntelliJ IDEA 5.1. Their new JavaScript plugin works like a dream. It makes me hope for an IDEA Ruby plugin.

Read More!

alex  Code 

02/21/06: JavaScript and CSS Versioning in Rails

To defeat browser caching for static files that actually do change once in a while, a common trick is to append a random number to the URL:
<link href="/css/mysite.css?9238238" rel="stylesheet" type="text/css">
If you use a truly random number (or the current time), it will reload every time. However, this is not exactly what you want; instead, you only want it to reload when the file has changed, and use the cached version when it hasn't. A good way to do this is to use the timestamp of the time the file was last modified.

Here's an easy way to do this in Ruby on Rails.

Read More!

alex  Code 

02/12/06: Eclipse Am Bizarro IDEA

Bizarro World I've been using Eclipse again, after a blissful 2-year leave of absence from Bizarro World. I thought it would be appropriate to repost my classic "Eclipse Am Bizarro IDEA" rant from a few years back... (below the fold).

BTW, in the meantime I've discovered many other UI and feature decisions where the Eclipsers chose... poorly. For example:

  • There's no checkbox for "blessing" a Run configuration as a favorite in the Run settings dialog. Instead you have to close that dialog, click on the stupid "ha ha I'm really a separate menu even though I look like a little 8-pixel triangle" "button" next to the big green play button, select "Organize Favorites...", click "Add", scroll through a list of items that are selectable, but don't actually select the one you want -- instead, click on the checkbox next to it in the list -- then click "OK". Twice.
  • Double-click-and-drag selection still doesn't work; nor does triple-click to select a line.
  • The list of search results don't actually show the results, but just the files in which there were results. And there's no keystroke for showing the next result. These two factors combined means that it's easy to click on a "result", look at it, then click on the next "result" and accidentally skip over several hits from the earlier file. The "proper" behavior is to move your mouse all the way across the panel to the down-arrow "button" (again, one that doesn't look like a button since it doesn't have button-like affordances (a visible border inside which you click)).
  • Activating the test runner with Ctl-F11 doesn't update the screen layout to show you the test runner if your current window is maximized (for which, thank Zeus, they now have a keystroke (Ctl-M)). This encourages you to hit Ctl-F11 again, which totally breaks the test runner since it doesn't support multiple simultaneous test runs yet does nothing to prevent you from starting multiple simultaneous test runs.
  • Version diffing (from Local History or Repository) is incomprehensible. There are two options -- "Compare with" and "Replace with". They apparently differ only by the presence of a "Replace" button. Why not just have "Replace" be a feature of "Compare"? In the "Replace" window, if you accidentally hit "Enter", the default action is not the expected "Show me the selected version," but is "Replace", which astonishingly replaces your whole file and then closes the window really quickly so you're like, "What the heck just happened?"
  • In Eclipse, certain editor keystrokes (ctrl-J, ctrl-K, etc.) only work in certain "perspectives" or "editor types" or whatever the heck modal madness they call it. In contrast, in IDEA, they went the opposite direction, actually making cool features like control-space work inside dialog boxes. Eclipse is shifting sand... you never know what you can do or how you can get it done.
I'll probably update this list as more frustrations occur to me. Read More for the original Bizzaro essay...

Read More!

alex  Code 

02/11/06: Life Without Getters

Q: What's the first rule of Object-Oriented Design?

A: Put the behavior with the data.

Now, this may seem to be a simple enough rule. But if that's so, why do I keep seeing code like this?

foo.getBar().getBaz().process(getBar().getBaf())
"Oh, that's just a violation of the Law of Demeter, which isn't really a law anyway, more like a suggestion." you might say.

or this?

@iterations.each do |iteration|
  velocity = 0
  iteration.stories.each do |story|
    if story.feature?
      velocity = velocity + story.velocity
    end
  end
  iteration.total_velocity = velocity
end
"Oh, you're just complaining about Feature Envy", you may complain. "I hate it when IDEA makes half my code yellow so I turn that option off."

But I have a dream. I dream of a world without getters. A world where Tell, Don't Ask is the law of the land. A world where every reference to instance data is in the class containing that data. Let me be perfectly clear:

Every. Single. Reference.

Inside the Same. Class. As the data.

A world where in addition to the first rule above, the next four rules are:

  1. Put the behavior with the data.
  2. Not *near* the data... *with* the data.
  3. No, with the *data*.
  4. Yes, even with that data.
  5. Good. Now keep putting the behavior with the data.

More below the fold...

Read More!

alex  Code 

02/11/06: Creational Patterns: The Factory Family

Here's one of my favorite rants: The Gang Of Four didn't do a very good job at laying out the "Creational Patterns". Their timing was all wrong: they jumped the gun and started with Abstract Factory. This reminds me of the following Steve Martin routine (paraphrased):
I was never good at dating. My timing was all wrong. I'd meet a girl in a bar and say, "Hi, was it good for you too?"

So here's my take, in proper order, on the progression of patterns for creating an object.

Read More!

alex  Code 

11/20/05: Refactoring Combo: Extract Method Object

Let's say you've got a big class with a lot of methods -- a dispatcher or controller, say, that's gotten a bit out of control. The methods are real business methods (or at least they have business logic inside them), but they refer to several different entities, so you're not sure they belong on any given entity. But you want to get them out of the original class and into domain classes.

Read More!

alex  Code 

11/19/05: Feature Envy Rule of Thumb

If you're looking at a method and you see a lot of references to different objects inside it, do the following experiment:

Make the method static (which means turning the "this" pointer into a named parameter). Now count the number of times each object is referred to.

What object is referenced the most? Chances are that it would go better as a method on that object.

And if you can split it into meaningful chunks, each of which primarily references a different object -- then divide and conquer.


alex  Code 

08/19/05: State of Grace

Need a nice state machine? I've got a real beaut right under the fold. Barely used, gets great mileage. Here's what it can do for you:

  • pull together all sorts of disparate business logicky transitions into one nice, encapsulated, formally complete model
  • complain loudly when some application logic tries to make an illegal state transition
  • output itself in DOT format, creating nifty automatic documentation


This doesn't quite implement the State Pattern which, like Strategy, uses polymorphism to let an object change its behavior based on state. Rather, it's a Finite State Machine, representing only the nodes and arcs (states and actions) that make up the legal lifecycle of whatever concept.


By extracting the transition logic into a separate object, we apply Separation of Concerns and let the owning object deal with the business of actually verifying whether a transition is desirable, whether other business rules are met, of spawning other processes or notifying listeners, or attaching Command objects to perform entry, exit or transition actions. Of course, any of these features (especially notifying listeners) can easily be added to the machine itself, but let's keep it simple for now.
It's straightforward enough to refactor to the full State pattern (also described by Metzger) if and when we want to.


Why would you want to use a state machine in the first place instead of, say, a bunch of booleans, or just smart methods? As Metzger says:


When you model an object whose state is important, you may find that you have a variable that tracks how the object should behave, depending on its state. This variable may appear in complex, cascading if statements that focus on how to react to the events that an object can experience. One problem with this approach to modeling state is that if statements can become complex. Another problem is that when you adjust how you model the state, you often have to adjust if statements in several methods. The STATE pattern offers a cleaner, simpler approach, using a distributed operation.


But the real reason to use a state machine is social: with a large project, involving many engineers, product managers, QA testers, etc., it's good to have a formal, well-described model for the lifecycles of your objects; using the code below follows the principle of Don't Repeat Yourself by allowing the model, and its representation in actual, executing code, to reign supreme.



Read More!

alex  Code 

06/01/05: Primitive Obsession

In a g i l e l e c t r i c My Favourite Smells Chris Wheeler names a code smell that's been on my list for some time: Primitive Obsession. I frequently tell my.. (um... what's the opposite of mentor?...) proteges, it's perfectly acceptable -- no, really -- to make an object that wraps a single, primitive value.

My favorite example of this is the one Chris uses -- wrap an integer so you know whether an index is zero-based or one-based. But his solution isn't quite radical enough for my taste. He made two classes, OneBasedInt and a ZeroBasedInt. This isn't OO since it makes the mistake of naming for form rather than function. Chris, I see your value object and raise it -- that is, decrement it by one class:


public class PageNumber {
  public PageNumber fromZeroBased(int zeroBased) {
    return new PageNumber(zeroBased);
  }
  public PageNumber fromOneBased(int oneBased) {
    return new PageNumber(oneBased - 1);
  }
  private int zeroBased;
  private PageNumber(int zeroBased) {
    this.zeroBased = zeroBased;
  }
  public int asZeroBased() {
    return zeroBased;
  }
  public int asOneBased() {
    return zeroBased + 1;
  }
  public void increment() {
    zeroBased += 1;
  }
  ...
}



This way people don't even *need* to know which type of index they should pass in to a method -- they just pass the object, and if some low-level rendering code needs to extract an integer in the right format, it just asks the object to present itself in the proper form. Actually, according to Tell Don't Ask, it might do something like pass in an output stream and ask the PageNumber to render itself in one-based format (for human viewing) or zero-based format (for a URL GET parameter).

Astute readers will note that the internal representation is the One, True, Correct form of integer indexes, which is as handed down from the prophets Kernighan and Ritchie, world without end, Amen.


alex  Code