{ |one, step, back| } 126 to 135 of 180 articles WikiSyndicate: full/short

Martin Fowler on Specification by Example   23 Mar 04
[ print link all ]
Martin Fowler shares some thoughts on Specification by Example and compares it with Design by Contract. I’ve written on DbC and Test First before, but Fowler expresses his ideas so much better.

Using WEBrick   19 Mar 04
[ print link all ]
Several folks (e.g. Kevin Altis, Aaron Brady) have written about a single line web browser in Python. I wondered what it would look like in Ruby. Here’s one answer…
  ruby -rwebrick -e 'WEBrick::HTTPServer.new(:Port=>8000,:DocumentRoot=>".").start'

Since WEBrick defaults to port 80 and doesn’t use the current directory as the document root by default, we have to add that information to the command line.

Although interesting, I find the following script more useful than a single line command. I often generate HTML docs on a machine at work that doesn’t have a web server, nor file system that is available to my browser’s "file:" protocol. So I fire up the "servefiles.rb" script below.

  #!/usr/local/bin/ruby
  require 'webrick'
  include WEBrick

  dir = Dir::pwd
  port = 12000 + (dir.hash % 1000)

  puts "URL: http://#{Socket.gethostname}:#{port}"

  s = HTTPServer.new(
    :Port            => port,
    :DocumentRoot    => dir
  )

  trap("INT"){ s.shutdown }
  s.start

Notice that the port is calculated from a hash function on the directory name. This allows me to run multiple mini-webservers in different directories. The script prints out the URL (with port number) when it starts, so I just cut and paste the URL into the browser to see the served files.

How do you use WEBrick?

Pretty Rublogs   19 Mar 04
[ print link all ]
I see a number of Rublog users have upgraded their blogs look and feel. (See Dave Thomas, Chad Fowler and Glenn Vandenburg). It leaves this site looking a wee bit plain now.

Hey Guys! Care to share your template and CSS files?

RubyGems Alpha 0.2.0 Released   19 Mar 04
[ print link all ]
I grabbed the latest version of RubyGems and typed:
    traken$ sudo gem --remote-install log4r
    Successfully installed log4r version 1.0.5

With one command, log4r was downloaded and installed without hassle or fuss. This is way cool.

There is a lot of work to be done on RubyGems, but making Ruby project installations this easy is great.

Some Pointers   13 Mar 04
[ print link all ]
I have not updated this Blog for over a month. It has been real busy around here. I have some ideas I want to share, but I think I’ve run afoul of Charles Miller’s #1 blogging rule. So I’m just going plunge into this posting by pointing out a couple of interesting reads I’ve found lately.

But First, Some Apologies

Yes, my site was down for a few days in February. I didn’t notice it right away, and when someone at work pointed out they couldn’t get to onestepback.org I had to wait to fix it until I got home. Even then, I thought it was only down for the day. It wasn’t until I reviewed the web stats for February did I realize that it was down for at least three days.

Sorry. It turns out that the copy of apache servicing http requests had crashed and burned. The ssl server was still up so remote access to my mail was OK. I just didn’t notice that the http server was down (see, I really was busy). Nevertheless, we now have some monitoring software in place so simple crashes shouldn’t cause extended outages any more.

Directing VS Enabling

Static verses Dynamic Typing. Checked verses Unchecked Exceptions. The battle rage on (and I’ve taken part in my share of them). Martin Fowler has some keen insight into the nature of the proponents of each side of the debate. He calls it the difference between a Directing attitude and an Enabling attitude. Directors wish to make the computing environment as safe as possible and willing accept restrictions to achieve that goal. Enablers desire flexibility above (in their view unneeded) safety, and will chaffe unagainst restrictions. Read Martin’s writeup, he explains it much better than I do.

I’ve landed on both sides of the debate in the past. Lately I’ve found myself on the enabler side of the equation more often than not.

When Generic’s Aren’t

Bruce Eckel has some surprising insight on the use of generics in Java (available in Java 1.5). For those who enjoy the ad-hoc polymorphism available in C++ generics are going to be surprised by Java’s version. If Eckel is correct, then generics look like they will be great for making generic containers and little else.

See Bruce’s article for details.

And More on Latent Typing

Speaking of the Static/Dynamic typing debate, the feedback page for Eckel’s Generics article, a commenter is defends the need for interfaces with the following comment:

In java, the symantics of a method are not bound to its name, so much as they are bound to the interface the method belongs to.

Bruce responds with a followup article on Latent Typing, but I would like to add my two cents here.

Java interfaces are more about syntax than semantics. They insure that implementing classes have the proper methods defined with the proper number and type of arguments, and that the methods actually do return a value of the appropriate type. But that’s it. Interfaces do nothing to support any meaningful semantics about the methods.

If you are interested in language support for semantics, I suggest you take a look at Eiffel. When you define a interface in Eiffel (which Eiffel would call a deferred class), you not only specify the argument list for the method, you also specify the promises to which the method implementor must adhere. This set of promises (the semantics) is called a contract and leads to the concept of Design by Contract.

Even if you never program a line of Eiffel code, understanding Design by Contract is a useful skill for a developer.

Speaking of Design by Contract

And that leads us to our final posting. Artima has published a series of interviews with Bertrand Meyer, the designer of Eiffel and Design by Contract. The interviews are worth reading (here is part 4, you can find links to the other parts from there).

I find that I don’t always agree with Meyer, but when I do disagree, I think through my position very carefully.

All for Now

I’ve run out of time. Hopefully it won’t be so long before I post again.

Writing an RCR   31 Jan 04
[ print link all ]
Matz is accepting RCRs (Ruby Change Requests) for Ruby 2.0 and Rite until the end of March. Tell the truth, is there something in Ruby that you wished worked a little differently? If so, now is your chance to stand up and be counted.

The Ruby Nuby Syndrome

I’ve noticed a trend on the ruby-talk mailing list. A nuby appears on the list, likes the language, except for one minor nit. Wouldn’t it be nice if Ruby would do (insert fix for minor nit here). A nit might be Ruby’s lack of overloaded functions, static typing, explicit interfaces, or anything else in Language X that is different in Ruby.

Now there is nothing wrong with static typing or interfaces. It is just that these topics have been hashed out on ruby-talk over and over again.

How Ruby Sucks

Don’t get me wrong. Ruby isn’t perfect by any means. In fact, I thought the Matz’s Keynote speech at the 2003 RubyConf was particularly healthy. Matz titled his talk "How Ruby Sucks" and then detailed the direction Ruby was moving for version 2.0.

And now that the features of Ruby 2.0 are beginning to solidify in Matz’s mind, he is encouraging Ruby Change Requests (RCRs) to be submitted through March at the RCRcive.net site.

But before you go and write up your favorite change request, consider the following.

Before You Write an RCR

Before you write an RCR, make sure you cover the following bases.

  1. Research. Has this change been requested before? Search the ruby-talk archives (Google is your friend). Also read the list of RCRs, both current and legacy entries to see if there are similar RCRs. Be sure to read and understand any issues raised during any previous discussions.
  2. Investigate. What would it take to implement your RCR. Can you simulate it with Ruby code today? What are the tradeoffs? Are there performance issues? Are there complexity issues? What about backwards compatibility?
  3. Solicit Feedback. If your suggestion is way out there, perhaps it would be wise to get feedback before you write up your RCR. It wouldn’t hurt to post a message on ruby-talk saying "I’m considering writing an RCR on XYZ, am I on track here?". Many ruby-talk members are tired of the same-old changes being discussed over and over again, but if you’ve made it past the research and investigate phase, a ruby-talk message would not be out of line. The feedback you get may help you tighten up the RCR.

Writing the RCR

Once you are ready to actually write the RCR, do the following

  1. Read the Submission Guidelines and Suggestions for submitting an RCR.
  2. Fill out each section of the RCR submission form. Pay special attention to the purpose of each section. The RCR submission help page goes over the sections, so I won’t repeat the information here.
  3. Remember the purpose of the RCR is to convince Matz and other Rubyists that they would benefit from your proposed language change. Clearly lay out what the perceived problem is and exactly how your proposal addresses that problem. Don’t skimp in the Analysis section, but carefully layout both the pros and cons to your RCR. Good, compelling examples are worth their weight in gold.
  4. If there is any way possible, provide an implementation of your suggestion. If your suggestion cannot be done in the current version of Ruby, approximate it as best you can. If you can’t provide a full speed implementation, provide a slow one (but include performance analysis as appropriate). Working code speaks much louder than vague suggestions.
  5. Don’t bother to invoke POLS (Principle of Least Surprise) as a justification for the RCR. Matz is the final arbiter of what is surprising and what is not, and telling him what his expectations are will not advance your position.

After You Write Your RCR

  1. Go back to review and comment on other RCRs. Make sure you vote too. But remember, the voting is only there to provide Matz with some indication of the interest in a given feature. This isn’t a democracy, Matz still makes the final call.
  2. Listen to feedback on your RCR. Several RCRs have already been withdrawn or rewritten based on the feedback provided by the RCR process.

It’s an exciting time for Rubyists, we are beginning to get a picture of what Ruby 2.0 might be like. So if you have an RCR in mind, please go ahead and submit it.

Just make sure you do the homework too.

Saw this ...   23 Jan 04
[ print link all ]
in a UseNet signature:
  A: No.
  Q: Is top-posting okay?

A Little Ruby, A Lot of Objects   23 Jan 04
[ print link all ]
It was my junior year in college and the math course I intended to take wasn’t offered that semester. My advisor recommended a computer programming course. He said "It will be useful, and who knows, you may like it." (Little did he know!). So that’s how I signed up for an introductory class on FORTRAN.

When I got to the first lecture, the instructor kept writing code snippets on the blackboard and asking questions about them. Now I knew a enough FORTRAN to do simple plots for my physics lab courses, but the code on the blackboard had way too many parenthesis to be FORTRAN.

Here’s one example (from memory):

  (DE MEMBER (PIP DECK) (COND
      ((EQ PIP (CAR DECK)) T)
      (T (MEMBER PIP (CDR DECK)))))

(And yes, the layout is accurate. The COND was definitely on the first line. At this point in the class, it was explained as required "magic".)

"What kind of programming language is this?" I thought. It didn’t make any sense for about 3 days. And then I had the "Ah-HA!" experience and everything fell into place. I finally "got it", and fell in love with Lisp and programming in general from that point on.

The instructor for the course was Daniel Friedman, the author of the book "The Little Lisper" (which was one of the required books for the course). The Little Lisper emulated, in print, Professor Friedman’s style of teaching, revealing a little bit of information through a question and answer session until the reader/student gains enough understanding to put all together.

Brian Marick has started a book where he emulates that Q&A style, but targets the book at Object Orientation and Ruby instead of Lisp. You can find the first three chapters of A Little Ruby, A Lot of Objects at www.visibleworkings.com/little-ruby. In those three short chapters he introduces objects, messages, protocols, inheritance, classes and meta-classes to a beginning programmer in a whimsical manner, similar to the original Lisp book. It was a delight to read the step by step approach used in the book.

The only downside is that Brian seems to have stopped after three chapters. Nevertheless, if you are looking for a gentle introduction to object orientation in general and Ruby in particular, take a look at A Little Ruby, A Lot of Objects.

Another Ruby Build System   21 Jan 04
[ print link all ]
Jon writes about a build system he put together using Ruby. Scripts in Jon’s system look alot like normal programs. Tasks are defined like a normal Ruby method, but a target_method command marks that method as special. These special commands are only executed once, no matter how many times they are called.

It’s a clever and remarkably simple approach.

Jon also describes a technique he uses to interface with ant to build a Java program. Details are a little sketchy, but I wonder if it is something that could be used with Rake.

Eckel and Fowler on Build Systems   08 Jan 04
[ print link all ]
Build systems seem to be at the forefront of everyone’s mind recently. Bruce Eckel and Martin Fowler have recently commented on the topic.

Bruce Eckel on Build Systems

In "Why We Use Ant", Bruce argues why we should continue use Ant, even though it has some significant flaws as a build system for large, complex projects. His arguments are:

  1. It’s never as easy as it seems [writing a replacement for Ant].
  2. It’s probably not the battle you should be fighting.
  3. Lots of people have tried and failed.
  4. Politics matter.

Number four is actually a very strong argument, especially in a group doing Java development.

Let me quote an interesting passage in Bruce’s article.

Another important proglem with Ant is that its XML-influenced declarative syntax is limited. A build system is really a little computer program. Normally, you look for conditions (a source file is out of date with its target is the primary one for make) and you execute commands, but sometimes you need to do things that are more sophisticated, conditional logic, that kind of thinkg. Both make and Ant fall down here because, while it’s possible to do these things it suddenly gets a lot more complicated because that’s not normally what they do.

Exactly! It was my need to dynamically generate some make targets that started my original make rant that sparked the rake project. make, by itself, just wasn’t up to the task

Bruce continues …

I suppost if I were give a budget and a bevy of programmers, I would ask them to take make, which is open-source, eliminate the silly tab-vs.-space thing, and meld it together with Python, also open-source. make would only retain the simplest of its functionalites (primariy the way you set up dependencies and execute simple commands), and as soon as you wanted to do something more complex you’d be able to drop seamlessly into Python syntax, using any Python libraries you want. I think that would probably be my dream build system.

Bruce, you really need to check out rake. Its exactly what you describe above (well, if you substitute Ruby for Python). And it didn’t take a bevy of programmers. The core functionality was an evening’s worth of work.

Dropping seamlessly into Ruby is trivial, because a Rakefile is a Ruby program, specified in standard (although idiomatic) Ruby syntax. Since we never leave Ruby, we have no parsers to deal with, leaving a very small code base for the core functionality. The core of Rake (dependency management, task execution and rule matching) is less than 200 lines of code. The minimal rake install (a single file) is around 500 lines of Ruby code and adds common file commands (system independent versions of cp, rm, mv, etc.) and a flexible FileList object that mimics Ant’s include and exclude semantics.

Martin Fowler on Build Systems

Martin Fowler echos many of Bruce’s comments and reiterates that a build system really needs a full blown programming language. Martin has been dabbling in Ruby, and it seems that he has discovered rake and has been using in it some small projects. Great!

A Build Language Needs to be a Programming Language

Why should your build system support a full blown programming language? Here is one small example taken from a real situation at work.

When we are ready to install a project at work, we create a staging directory containing the files to be installed into an environment (e.g. testing or production). As problems are discovered in testing, corrections are made in a development area and copied to the staging directory for reinstallation.

The following makefile copies 2 jar files from the developement area to the staging area. Yes, I know that a makefile is probably overkill for this problem, but in real life there are other tasks as well. For example, using make (or rake) allows me to ensure that a refresh step always occurs before an install step, but only if the refresh is needed.

So here is the makefile …

  # Makefile to copy jars

  DEV=/home/jim/development
  JARDIR=jars

  refresh: $(JARDIR)/a.jar $(JARDIR)/b.jar

  $(JARDIR)/a.jar: $(DEV)/AProject/lib/a.jar $(JARDIR)
          cp $@(DEV)/AProject/lib/a.jar $@

  $(JARDIR)/b.jar: $(DEV)/BProject/lib/b.jar $(JARDIR)
          cp $(DEV)/BProject/lib/b.jar $@

  $(JARDIR):
          mkdir -p $(JARDIR)

Notice that there are several duplications in the file. The copy command for the two jar files are remarkably similar, yet different enough that you can’t capture both cases with a generic make rule. Also, knowledge about a particular jar file is spread out in two places; once in the copy rule itself, and again in refresh task line.

First we will translate the above Makefile into an equivalent Rakefile. See the Rakefile documents for details on the syntax of a Rakefile.

  # Rakefile translated directly from the Makefile

  DEV = "/home/jim/development"
  JARDIR = "jars"

  task :refresh => [ "#{JARDIR}/a.jar", "#{JARDIR}/b.jar" ]

  file "#{JARDIR}/a.jar" => [ "#{DEV}/AProject/lib/a.jar", JARDIR ] do |task|
    cp "#{DEV}/AProject/lib/a.jar", task.name
  end

  file "#{JARDIR}/b.jar" => [ "#{DEV}/BProject/lib/b.jar", JARDIR ] do |task|
    cp "#{DEV}/BProject/lib/b.jar", task.name
  end

  directory JARDIR

All the duplication from the original makefile still exists in the rake version. Lets remove it by writing a function that will generate the dependency (and copy command) based on the jar file name and the project name.

  # Rakefile with (some) redundencies removed

  DEV = "/home/jim/development"
  JARDIR = "jars"

  task :refresh
  directory JARDIR

  def make_jar_copy_task(jarname, project)
    stagejar = "#{JARDIR}/#{jarname}.jar"
    devjar   = "#{DEV}/#{project}/lib/#{jarname}.jar"

    task :refresh => [ stagejar ]

    file stagejar => [ devjar, JARDIR ] do
      cp devjar, stagejar
    end
  end

  make_jar_copy_task("a", "AProject")
  make_jar_copy_task("b", "BProject")

Notice that the refresh task is now declared without any explicit dependencies. The individual jar file dependencies are added to the refresh task inside the make_jar_copy_task function.

If we had a lot of jar files, we could put them in an explicit list and replace the last two lines with something like this …

  jarfiles = [ ["a", "AProject"], ["b", "BProject"], ["c", "CProject"] ]
  jarfiles.each { |jar, proj|  make_jar_copy_task(jar, proj) }

Or perhaps we have to deduce the jar files from the current contents of the JARDIR directory. (Assume that projects is a lookup table mapping jarfiles to project names.)

  Dir["#{JARDIR}/*.jar"].each { |jar|
    jarname = File.basename(path).sub(/\.jar$/, "")
    make_jar_copy_task(jarname, projects[jarname])
  }

Or perhaps we need to pull our jar file names from a database …

  DBI.connect(DBI_STRING, USER, PASSWORD) do |db|
    sql = "SELECT jarfile, project FROM install_table WHERE install_date = ?",
    db.select_all(sql, INSTALL_DATE) do |row|
      make_jar_copy_task(row['jarfile'], row['project'])
    end
  end

Ok, that last example might have been a little over the top. The point is that builds can become arbitrarily complex, and anything less than a full programming language is just doesn’t cut it.

 

Formatted: 21-Jul-08 01:38
Feedback: jim@weirichhouse.org