Sidebars are better than components 2

Posted by Justin Weiss Wed, 13 Feb 2008 01:10:00 GMT

This article made it across my RSS reader today. I ran into my own problem with this while writing a custom CMS for work. We wanted to have reusable components that could be added to CMS pages, which could take various parameters, could be cached, and could be viewed in different ways given a size. I investigated Rails components at work, but noticed that using those is discouraged by the Rails community.

My investigation brought me to Typo’s sidebar model, which I used as the basis for the model we ended up using for the prototype of the project. The ultra-simplified version of the model works like this:

We have a Sidebar base class, which inherits from ActiveRecord::Base. Sidebars inherit from this Sidebar class.

Which gives us something like this:

class Sidebar < ActiveRecord::Base
  serialize :config

  class << self

    def params
       @params ||= []
    end

    def param(name, type, options = {})
      params << options.merge({:name => name, :type => type})
      self.send(:define_method, name) do 
        self.config[name] || options[:default]
      end
      self.send(:define_method, "#{name}=") do |value|
        self.config[name] = value
      end
    end
  end
end

class StaticTextSidebar < Sidebar
  param :content, :text, :default => "Hello, World!"
end

So now we have a way of defining sidebars and their parameters. The metaprogramming in the Sidebar base class allows us to programatically query the parameters declared in a Sidebar. This will be important later. For now, we still need to declare the view of a sidebar, so we do it in _static_text_sidebar.rhtml:

<%= sidebar.content %>

Now, we add a helper to application_helper.rb to render the sidebar:

def render_sidebar(sidebar)
  render :partial => sidebar.class.name.underscore, :locals => { :sidebar => sidebar }
end

and then we can call render_sidebar in any of our views on an instance of a sidebar to render it. It’s not perfect, but it’s good enough for a prototype!

From here, we have a very basic reusable model-view framework that we can include in any of our pages. Sidebar instances can be associated with content on a page to be displayed, and their configuration can be serialized to the database along with the items they display with.

Creating and configuring sidebars can be done programmatically, by generating a form based on the parameters a sidebar takes and placing that form data into the sidebar, the same way one would with a standard ActiveRecord object. Their parameters can be validated using standard Rails validations and the result of the render_sidebar call can be cached.

This basic idea, with a little bit of work, can easily form the basis for a simple reusable component architecture, and we’ve been having a ton of success with it so far.

Leopard Prompt 2

Posted by Justin Weiss Wed, 26 Dec 2007 01:46:00 GMT

One thing that bugged me after upgrading to Leopard was the prompt in the terminal. It only showed the last part of the path, and I wanted to see the whole thing. I found the solution on a tumblog, so here's the prompt I'm using now:

PS1='e[32mu@he[0m:e[34mwe[0m$ '

I put this line in ~/.profile, and that brought things back to normal!

Well, partly... unfortunately, when I try this, after getting to about column 80 on the first line of text, the text starts wrapping over the beginning of the line. I'll probably have to read up on prompt settings and figure out what's causing all this to happen.

No-Impact Testing

Posted by Justin Weiss Wed, 18 Jul 2007 03:36:00 GMT

For my day job, I work on Legacy Code. As legacy code, it needs unit tests. Unfortunately, this particular legacy code is used by millions of people on a regular basis, precluding refactoring to make unit testing easier. I needed a way of testing our code without changing any of the code that was put into production. Luckily, I discovered a way of exploiting the C/C++ linker to allow me to stub out our dependencies, which I'll talk about here.

For me, the hardest part of writing C/C++ code is managing dependencies. It's very easy to get locked into a design due to dependencies that will make life harder later. The code that I've been working on is over ten years old in places, and wasn't written with dependency management in mind. This means that most of the functionality of the code calls APIs that I have no control over and I don't want to run in my unit tests, because they do things that change the state of the underlying system. Luckily for me, the C/C++ linker that I've cursed on many an occasion has become a useful tool for softening these dependencies. I'm sorry for doubting you, linker.

The current archtecture of the system looks like this:

my god it's full of hardcoded dependencies

I wanted it to look something like this:

pinch

In order to control both ends of the system from my tests, however, I needed to override the methods that my code calls that are exposed by the underlying layer that I have no control over. Of course, in the Software Engineering world, the only problem that can't be solved by another layer of abstraction is performance, so that's what I did -- created a proxy layer as a library that re-implemented each of the methods exposed by the underlying layer. This library would forward these calls to a global instance of a proxy class with stub functionality that I could override in my test code. This looked something like this:

Better, but still not perfect...

Ruby came to the rescue here, as it tends to do, allowing me to write a quick and dirty (ok... filthy) script to parse the header file of the dependency and generate these classes for me. This saved me the trouble of doing it by hand, which would make me cry. I took these generated files and generated a .dll and a .lib, which I statically linked into my test code, making sure to link it before the real .lib I depended on.

As you can see, I could now pinch my production code between my test code, enabling me to control what goes in and look at what comes out. The best part of all of this is that it didn't require a single change to the code that goes into production, allowing me to cover methods with tests before refactoring. For easily broken code that is used by an enormous population, this is a huge deal. But it's not the end.

I've heard many experienced unit testers say that the most difficult places to test are the "Ends of the World..." that is, upstream and downstream dependencies. The most common way I've seen people avoid this is by writing proxy objects that isolate these dependencies from the code. This leads to an architecture that looks like this:

Soft and smooth

This leads to a few benefits. First, your interface to the dependent code is written by you, so you can expose only the functionality that you actually use in a way that you like. Second, when your dependency breaks you, you have a simple test case that you can toss at them, which avoids the communication problems that plague large, distributed teams. Finally, you can subclass and override this proxy, allowing the injection of test code on both ends of the code. That's a much easier way of doing what I described above, and doesn't require any build hackery. It's the route I'm planning on taking once I get good enough test coverage that I feel comfortable making wild, invasive surgery on the code.

Much love for Michael Feathers' book "Working Effectively With Legacy Code", which gave me the idea and the confidence that this could in fact be done.

Language Geek

Posted by Justin Weiss Wed, 20 Jun 2007 02:50:00 GMT

I love programming languages. Learning a new one is one of my favorite computer-related activities to do. Right now my favorite is Ruby for reasons I'll get into at another time. There are a few others, though, that have caught my attention lately:

  • Erlang: There's something really powerful about a language where remote procedure calls are built into the language. I also realized (again) how cool tail recursion can be. I don't have any ideas trying to get out of my head that would find Erlang useful now, but I really want to play with it more.
  • Scala: Scala is an interesting language. It's strongly typed with type inference, which I find very cool and wish more languages would try. It also supports the actor model (like Erlang) and some really crazy generic programming constructs. To me it seems like magic. It also runs on the JVM, which means I get every library people can think of right off the bat. Score!

I also found the article by Stostroup here to be really interesting. It's about 50 pages long, but well worth reading if you're interested in or (are forced to) use C++ at all.

Help from the compiler vs. Less code

Posted by Justin Weiss Mon, 04 Jun 2007 13:48:00 GMT

Jeff Atwood's Coding Horror has recently become one of my favorite blogs (although he seems to be more of a Code Complete guy while I'm more of a Pragmatic Programmer guy).

One of the recent posts on the blog made the point that "the best code is no code at all." This is something I completely agree with, but I get into arguments on this topic pretty regularly. This particularly comes up when I discuss static vs. dynamic languages. When I talk about Ruby being my favorite language (for now), many people who come from a C++/C#/Java mindset wonder how correct the code I write can be if the compiler isn't doing any compile-time checks. After all, errors are much cheaper to catch early, and compile-time checking is really early, right?

In theory, they have a point, but in practice, it hasn't been a problem. I was thinking about this recently, and I think there are two main reasons I haven't had noticeably more bugs in my dynamic programs than I do in my static programs:

The first is what Jeff refers to in his blog: Dynamic languages, as a whole, require less code to be written. I don't care how "correct" the compiler thinks my code is, I am smart enough (in a way) to write broken code that the compiler can't catch. When the broken code is a single line hidden in a ton of boilerplate C++/C#/Java style class/method/etc. definitions, it takes a little longer for me to wrap my head around what I need to do to fix the problems. In Ruby, I find that my mistakes are much easier to catch and fix, because my code _is_ my intent. Part of it is because less code = less room to make mistakes, and the other part is less code = easier to find the mistakes I do make.

The other reason, which branches off from the first, is that the dynamic programs are (again, in my experience) easier to test. When you can torture every object in the system at runtime, it becomes unbelievably easier to mock, isolate, and test the exact functionality that exists in a part of the program. Not only does this hit most of the dumb mistakes that compile-time checks will notify you about, it also will tell you when another dumb mistake breaks logic errors that the compiler could never tell you about.

This leads me to an interesting fact that I just recently discovered: Not only does the code I write in C++/C# not have fewer (discovered) errors than my Ruby code, my Ruby code is, on the whole, easier to fix when things do go wrong. Less code provides a lot of benefits when it comes to agility, avoiding needless multitasking, and verifying code correctness, and that's one of the many reasons I've been moving much more toward more dynamic languages lately (and been much a much happier developer for it).

RailsConf 2006 Keynotes

Posted by Justin Weiss Wed, 23 May 2007 15:04:00 GMT

It's almost exactly a year late, but I stumbled upon the video for the RailsConf 2006 keynotes. I'm hoping (and expecting) that they do something like this again for the RailsConf that just occurred last weekend, since I wasn't able to go. The keynotes for last year's conference were really good. I've never really been a huge fan of Paul Graham, but his keynote was excellent, as was Martin Fowler's keynote on "Why Ruby?"

It's hard to find the time to watch hour long videos, but I do have an hour-long bus ride to work. I figured transcoding the video into audio would be a good idea, so that I could listen to the talks on my Shuffle. This turned out to be much easier than I expected. It was trivial to get Quicktime Pro to export the audio to WAV, after which I could just add the WAV to iTunes, right-click, and convert to AAC. Checking the "Remember Position" option for the AAC track is crucial, of course, for an hour-long talk. A few minutes after having the idea to listen on my iPod, I had a few hours of smart people to keep me busy on the long traffic jam we call the 520.

Teenage Mutant Ninja Testing

Posted by Justin Weiss Mon, 21 May 2007 15:29:00 GMT

Recently I've been hearing more and more about automated "mutation testing" tools such as Jester (for Java) and Heckle (for Ruby). These are tools that will try to break your code by doing things like changing the truth values of clauses of if statements, modifying immediate values, changing array indices, and returning bad data, then running your unit test suite on the modified code. If the modified code passes your test suite, then chances are your test suite is either lacking coverage or you have dead code.

Now, I love automated tests. It's not just the bugs I catch early or the debugging time I save or the live documentation aspects of the tests, but the confidence having my code fully tested gives me to work with and refactor the code to make it the best code possible. However, I could never shake the feeling that this confidence was a little misplaced, especially when I discovered bugs in the tests or code that wasn't being tested despite coverage numbers being high.

It was always hard when I'd evangelize unit testing and people would ask, somewhat sarcastically, "How do I know the tests are right? Do I have to write tests for the tests?" It always seemed to me to lead to an infinite regression of questions that I didn't have the answer to.

Luckily, someone (or some group) was smart enough to come up with the idea of brute-force testing tests, and I think these sorts of tools will lead to code that can be considered "correct" for all real purposes without resorting to formal methods. My somewhat shaken confidence in my unit testing tools can be regained.

I haven't had the chance to play with these tools in-depth yet, but I'm definitely going to use them on my next project. I'll probably talk more about them then.

svn+ssh 2

Posted by Justin Weiss Fri, 18 May 2007 15:04:00 GMT

I've been using Subversion for years on my own machines to manage documents, code, and everything else I didn't want to get lost. It wasn't a perfect solution, because I needed the host machine to be turned on and on the network all the time (easier said than done) and I also needed to have the Subversion server running (which is pretty much how I learned launchd).

When I moved to a shared host that offered Subversion access, I saw how easy svn+ssh could make things. Svn+ssh will automatically spawn a svnserve process upon access using an svn+ssh:// URL, meaning the Subversion server doesn't have to be running constantly on the server machine.

Passwordless login over SSH is really cool, and it's really simple to get it working with Subversion. Right now, I have Subversion "owned" by a single user on the server, and I manage permissions using SSH keys.

First, I created a new ssh keypair, to be specifically used with Subversion:

$ ssh-keygen -t rsa Generating public/private rsa key pair. Enter file in which to save the key (/Users/justin/.ssh/id_rsa): /Users/justin/.ssh/id_rsa.subversion etc...

I then copied the contents of ~/.ssh/id_rsa.subversion.pub into the Subversion owner's ~/.ssh/authorized_keys file. This is enough to get svn+ssh working, but you'll have to use a command like this, passing in the full path to the repository:

$ svn ls svn+ssh://user@server.com/full/path/to/repository/application/trunk

I think you'll also have to specify the username/password on the command line as well, if you can commit to the repository as an alternate user at all. Finally, this can be dangerous, as it leaves the user account open to all users you've given access to.

However, adding something like the following in the ~/.ssh/authorized_keys file, on the same line as the public key you added earlier, will solve these problems:

command="/path/to/svnserve -t -r /full/path/to/repository/ --tunnel-user=user_name",no-port-forwarding,no-agent-forwarding, no-X11-forwarding,no-pty

This will connect to the repository at /full/path/to/repository/ with Subversion user user_name, disabling most of the other stuff the user would be able to do on the server.

The last thing I did is set the SVN_SSH environment variable on my local machine to point toward the key created earlier, which I did in my ~/.profile:

export SVNSSH='ssh -i /Users/justin/.ssh/idrsa.subversion'

After following these steps, you can test it out using

$ svn ls svn+ssh://user@server.com/application/trunk

That command should now work without requiring a password, or the svnserve server running on the remote machine.

I'm still having one issue with my setup -- when I give svn the root path, like:

svn ls svn+ssh://user@server.com/

I get an error:

svn: Syntax error parsing revision 'server.com'

So far I haven't found a way to resolve this that I'm satisfied with, but in reality it's not really a problem -- how often do you really access the root of your repository, anyway? If it's common, chances are the repository isn't laid out very well.

'Make'ing Erlang

Posted by Justin Weiss Wed, 16 May 2007 15:15:00 GMT

I finally started reading my beta version of Joe Armstrong's Programming Erlang and I'm right about where the good stuff comes in -- concurrency.

There's some things I like and some things I don't like about the language so far, which I'll get to when I understand the language a little bit better. There's one thing that surprised me, though: Is make really the tool most Erlang developers use to do their builds? I mean, I assume build order isn't really as big of a deal with Erlang as it is in some languages, but make is one of those tools I couldn't help but get frustrated using. It turned me off of things that use "significant whitespace" completely, and that's one of the reasons I never could get into Python.

Maybe build management isn't a huge deal in Erlang, or it's just a temporary lack of tool support, but I hope it's not something I'll have to deal with often.

Or maybe I can just use Rake.

Setting up a domain name

Posted by Justin Weiss Tue, 15 May 2007 02:01:00 GMT

As you can hopefully see, I got a new domain set up for my Linode virtual server, so I can show off all the awesome stuff I've been working on. Not having to use my laptop as a Subversion server anymore is nice, too.

It was a lot more difficult than I expected, mostly due to my first attempt to buy a domain name through 1and1 (since I heard they were cheap, and so am I). Unfortunately, it looks like 1and1 doesn't allow wildcard subdomains, which is kind of a killer for me. I like being able to host each application on its own subdomain, so I'm not doing crazy path rewrites in my Rails apps. I also wasn't a huge fan of their domain management dashboard, it seemed more geared toward managing shared hosting than managing domains pointing to off-site locatons.

I figured I'd try someone else, and went with GoDaddy for the domain you see above. This worked much better, and I got it set up within about 12 hours (would have been less, but I accidentally got rid of the default A record and had to fix that. Unfortunately, the other domains I bought won't be transferred to GoDaddy until the waiting period is over, but other than that, I'm really happy with the way everything's set up.

Next steps: Installing Trac, and deploying an application. This is so much better than shared hosting it's not even funny.