Recontexting and Hygienic Code

  • Posted By Stuart Halloway on May 23, 2007

When building software, we are often faced with a choice: Should we build just what we need now, or should we do extra work now to make things easier in the future? Consider this simple example:

// 1. Simple
GasGrill grill = new GasGrill();
Hamburger h = new Hamburger();
grill.cook(h, 375, 8);
This is great, but what if I want a charcoal grill? One alternative would be use a factory:
// 2. Factory
Grill grill = GrillFactory.newInstance();
Hamburger h = new Hamburger();
grill.cook(h, 375, 8);
Now, the details of grilling are hidden behind the GrillFactory, and we can choose another grill without modifying code. Or, I could avoid the dependency on factories with POJOs and dependency injection:
// 3. Dependency Injection
public class InjectionGrillAction {
  private Hamburger h;
  private Grill g;
  public Hamburger invoke() {
    g.cook(h, 375, 10);
    return h;
  }
}

Agile practice argues "You Ain't Gonna Need It (YAGNI)." So we could build the simple, concrete implementation, and switch to factories or DI only when and if necessary.

Modifying code to be more flexible or general is one form of refactoring. Refactoring is a Good Idea, but in this case there is a Better Idea. What if we could recontext? Instead of changing the code, we change the context in which the code runs. Consider this example:

# 4. Hygienic: grill_main.rb
h = Hamburger.new
g = Grill.new
g.cook(h, 375, 8)

Is this an example of the Simple, Factory, or Dependency Injection approach? You can't tell, without context. Depending on what other code runs first, the Hygienic code might exemplify any of these approaches, or none. I can run the code in a Simple context:

ruby -rsimple_context grill_main.rb
=> Hamburger is medium_rare and has a totally generic flavor
Or, I can run the code in an Injection context:
ruby -rinjection_context grill_main.rb
Hamburger is medium_rare and has a generic outdoor flavor
The injection framework I am using here supports injection through system properties, so we can inject a charcoal grill:
export Grill=CharcoalGrill
ruby -rinjection_context grill_main.rb
=> Hamburger is medium_rare and has a delicious charcoal flavor

The Hygienic approach is as simple as the Simple approach, and more powerful than the Dependency Injection approach. How is this possible? All of the other approaches commit to too much. Rather than simply solving the task at hand, the Simple, Factory, and DI approaches all embed presumptions about future needs. They either do not plan for the future at all (Simple), or they complicate the code with concerns peripheral to the task at hand (Factory, DI).

Hygienic code cleanly commits to solving the task at hand, and avoids committing to anything else. This is a simple idea, but look what it does to some sacred cows:

  • Factories (and most other design patterns) are code smells.
  • Refactoring IDEs may have done more harm than good. How often are you refactoring code that should be recontexted?
  • POJOs are a necessary evil. In more hygienic languages, the notion of a POJO is almost meaningless.
  • Domain-Specific Languages (DSLs) are a Good Thing. They naturally tend to be hygienic.

If you would like to see the grilling code example in full, you can get it here. If you are interested in learning more about hygienic code, we are integrating this approach into our curriculum. Or, come to North Carolina and work with us.

The Business of Rails

  • Posted By Justin Gehtland on May 22, 2007

At RailsConf, I had the distinct pleasure of serving on a panel called “The Business of Rails”. Nathaniel Talbott organized it, and asked Joe O’Brien, Robby Russell, Andre Lewis, Geoffrey Grosenbach, and myself to participate.

First of all, thanks to Nathaniel for getting this on the schedule. The number of people in the room, and the subset of those people that were thinking of starting a business based around Ruby and Rails, was awesome to behold. If only the most excellent Extra Action Marching Band had held off for a few more minutes, we’d have had a complete success. As it is, we lost part of the crowd to this. Such is life.

Also, since the panel was such a success, and so many people wanted to continue the conversation, Robby set up a Google Group for anyone who wants to keep the discussion going. So, drop by the Ruby on Rails meets the business world group and be part of the revolution!

Language Matters

  • Posted By Stuart Halloway on May 21, 2007

My Design Patterns are Code Smells post has been picked up by TheServerSide.com. It is interesting to read through the comments. One side exchange about Test-Driven Development includes this observation:

I think the point of the TDD comment is that TDD forces you to consider using interfaces to reduce coupling between classes.

Yes, near 100% of my data access interfaces have exactly one implementation. But I never create these interfaces because, gosh, I may want to change from Oracle to Some-New-Cool-Database in the future.

This is a terrific example of how implementation languages color your thinking. Notice how easy it is to switch between concept and implementation details:

  • "TDD forces you to consider..." (conceptual)
  • "...using interfaces to..." (language-specific)
  • "...reduce coupling..." (conceptual)
  • "...between classes." (language-specific)
There is nothing wrong with this level-jumping; it is often more concise than speaking at a single level could be. Just make sure that you understand what level you are playing at, and why. Otherwise you might conclude that
  • "If only I had an interface ..." (language-specific)
  • "...then I could mock my data access layer..." (conceptual)
which says more about your platform choice than it does about the problem at hand.

Domain Driven Design

  • Posted By Stuart Halloway on May 21, 2007

In Design Patterns are Code Smells I argued that Design Patterns are heavily influenced by implementation language. This should not be surprising, since design patterns are often translated directly into code. What about higher design abstractions? Surely as you get more distant from the code, the language dependency goes down. You wouldn't expect to see UML, or Domain-Driven Design, or Model Driven Architecture, totally colored by implementation language, would you?

In fact, you should. I have been reading a lot of software design and architecture books lately, and have come to two conclusions:

  1. No matter how far you get from code, design and architecture is inevitably colored by the designer's knowledge of programming languages.
  2. The design literature unintentionally creates a vicious lock-in around programming languages, as follows: Design books tend (even more than programming books) to fixate on the most popular programming language at the time they are written. Call it Language X. Enterprise developers need "lots of design", because they are writing "serious" code. Q.E.D., enterprise software must be written using X, because the design books (implicitly) say so. But this is not the designers' intent! Designers are not making proactive language recommendations. They are making reactive, lowest common-denominator choices in order to reach a broad audience.

I will be expanding on this topic at the Rails Edge in Chicago, August 23-25. In "Domain-Driven Design in Ruby," I will revisit the concepts in Eric Evans' excellent book, but with Ruby-colored glasses, and maybe even a bit of a Lisp. You can find the abstract here (scroll down).

Nice review of R4JD

  • Posted By Stuart Halloway on May 18, 2007

Rafi Jacoby says this about R4JD:

This is probably one of the best programming books I’ve read. It was a quick and easy read, and really hooked in well with my background. All scenarios are laid out as “here’s how you’d do it in a Java stack, and here’s how Rails does it.”
Thanks Rafi!

Design Patterns are Code Smells

  • Posted By Stuart Halloway on May 17, 2007

In the original GoF book, the authors made it clear that when you are doing design patterns, implementation language matters:

The choice of programming language is important because it influences one's point of view. Our patterns assume Smalltalk/C++ language-level features, and that choice determines what can and cannot be implemented easily. (Design Patterns, p.4)

Unfortunately, this message has generally been lost, and programmers all too often use patterns as recipes. Martin Fowler explains the difference:

Recipes tend to be more particular, usually tied to a particular programming language and platform. Even when patterns are tied to a platform, they try to describe more general concepts.
If you have seen a Java or C# application that looks like a C++ recipe collection, you know the damage that conflating these two concepts can cause.

Regardless of how you distinguish patterns from recipes, the programming language that you think in will be the programming language you design for. This is one reason why the Prags encourage everyone to learn one new language a year. You will still design for the union of the languages you know, but at least you will not be hopelessly provincial.

Language advances kill patterns-as-recipes. Back in 1998, Peter Norvig argued that most of the original GOF patterns were invisible or simpler in Dylan or Lisp. Since then, Greg Sullivan has made the same point for Scheme. Jan Hannemann demonstrated the same for Java+AspectJ. Design patterns do not perform well as recipes. They are seasonal at best.

At code level, most design patterns are code smells. When programmers see a design pattern in a code review, they slip into somnolent familiarity. Wake up! Is that a design pattern, or a stale recipe from a moldy language?

JavaOne book sales: Statistics in Context

  • Posted By Stuart Halloway on May 16, 2007

Well, it's over. Grails beats Rails: As Michael Yuan points out, three Groovy and Grails books were in the top ten sellers at JavaOne. No Ruby or Rails books made the cut.

Read that again. Groovy and Grails are kicking some serious Ruby Rails ass. I like both stacks, but frankly the JavaOne numbers do not match my impression of what people are up to. Let's double check that against the Amazon rankings:

Programming Ruby is currently #1,731 on Amazon, and did not make the top 15 at JavaOne.

Agile Web Development with Rails is currently #531 on Amazon, and did not make the top 15 at JavaOne.

The Definitive Guide to Grails is currently #24,375 on Amazon, and was #4 at JavaOne at the time of Michael's post.

Hmmm. So maybe Grails does a lot better only at a Java-specific events. Not too surprising. But actually, we don't even know that. As it turns out, the Pragmatic Press books were not for sale at JavaOne. After my talk, attendees followed me to the bookstore asking what to buy, and I told them to wait until they got home.

I guess winning the battle of statistics is about choosing the battleground.

[Editor's note: Stuart Halloway, the author of this post, is the best selling Java book author ever, among Duke graduates with the initials SDH. Take that, David Geary!]

Groovy and Grails: Three Worries

  • Posted By Stuart Halloway on May 16, 2007

Yesterday I blogged ten pleasant surprises with Groovy and Grails. Let me reiterate that overall, I am impressed. But there are a still a few issues that make JRuby a more promising alternative at present.

  1. Groovy classes are not open. I understand the reasons for this decision, but I want the productivity boost possible in a language where this is legal:
    class Person { 
      def firstName; 
    }
    p = new Person();
    class Person {
      def lastName;
    }
    p.lastName = 'Halloway'
    
    My example here is trivial, but the concept isn't. For more on both sides see here and here.
  2. Grails is not written in Groovy! (For the most part.) I went looking for the implementation of the chain method, and it was a whole Java class to itself. I am hoping that the Java bias is legacy, and that the Grails team is now more comfortable eating Groovy dog food.
  3. The "optional static typing" argument is a red herring, until somebody produces some compelling examples. Groovy advocates point out that they have the best of both worlds--dynamic typing with static typing available on request where needed. This sounds good, and it may be good, but show me some significant examples. Better yet, articulate some rules of thumb for when to use dynamic typing, and when to use static typing, within a single Groovy project. This is a serious request, not flamebait. Instead of debating "static typing--yes or no?", let's debate "static typing--when?" in a language with a clean syntax for both.

Microsoft Licensing Apology

  • Posted By Justin Gehtland on May 16, 2007

In my post about Silverlight, I described the Microsoft Permissive License as the “Nixon-mask” of open source licensing. I was confusing the MsPL with the Microsoft Limited Permissive License, which restricts usage of the code to Windows-only boxes. My apologies, the MsPL really seems like a fine (if redundant) addition to the OS Licensing space.

Microsoft-235

  • Posted By Justin Gehtland on May 15, 2007
That's the isotope of Microsoft that goes nuclear and wipes out everything.

Silverlight, the DLR, and thee

  • Posted By Justin Gehtland on May 15, 2007

I had the privilege of giving a talk last week at the Triangle .NET User group on the topic of Ruby and the CLR. My talk was prepared well in advance, and was going to go into detail about RubyCLR and its place in the Ruby runtime universe. Then, of course, at the beginning of last week, the world shifted under my feet at Mix07 when John and Jim announced Silverlight, the DLR and IronRuby.

At the meeting, Chris Love gave a 15-minute talk before I got up, all showing samples of Silverlight in action. (Thanks, Chris, for the kind words, by the way). Chris did a great and enthusiastic job, but he said something then that I’ve since heard repeated and I’d like to talk about. He said, approximately, “Here’s Silverlight, and it has just killed Ajax.”

Silverlight vs. Ajax

The general thrust of this argument is that having a full-fledge rich-windowing experience in the browser is going to put a stop to all that amateurish mucking around with JavaScript and the DOM. I said it at the meeting, and I’ll say it again here, that’s hogwash. First and foremost, there will always be a developer community whose members will not adopt a technology that is a) closed source and b) under the control of a single corporate entity. Anybody who ever used the acronym LAMP in casual conversation is a member of this group. They simply will not base their technology stack on Silverlight, or Flash, or Flex, or JavaFX, or whatever.

Which means that, to the extent that Chris and others are right, they may be right that Silverlight will kill off Ajax development within the current Microsoft development community. That’s probably true, but only to a degree. Silverlight currently runs only in IE and Firefox on Windows and Firefox and Safari on the Mac. (From what I hear, Opera for both platforms is “close”.) There are two platforms missing from that list: *nix and the loose collection of OSes known as mobile devices. Development teams will still need to support those clients, so Silverlight won’t just nix JavaScript and the DOM overnight.

More importantly, if the message of Silverlight is “write rich desktop-like apps and deliver them in the browser”, then Silverlight isn’t going to kill Ajax. It is going to kill ASP.NET. Why even have a stack whose purpose is to translate big, functional, object-oriented code into some combination of HTML and JavaScript if you can just whip up some slick XAML and get cool features like local storage to boot? If Silverlight is the future, then necessarily, ASP.NET is the past. I don’t see many people talking about this. Sure, there are a ton of articles about creating Silverlight controls for ASP.NET apps, but really, why not go all the way? Which brings me to my next question….

Silverlight vs. Flash vs. ClickOnce vs. Web Start vs. XUL vs. Applets

Remember when applets were the future? And the browser wars of the mid-90’s were supposedly because Microsoft was afraid that Netscape Navigator would replace the desktop? Remember when Flash represented the future of the UI? Or Web Start and ClickOnce would bridge the gap between the rich desktop experience and the ease of deployment of the web? Yeah, me too. And exactly 0% of those things came to pass. Applets died and left the world with nothing but a gymnastic Starfleet insignia. Navigator bought it when IE became “free” as in “monopoly”. If the state of XUL can be inferred from the state of XULPlanet, then XUL has been visited by the Borg. Web Start was too slow, and ClickOnce was just another way to launch a Windows installer but without all the, well, windows. Flash has become the game/media player/cartoon/hip banner ad technology of choice, but how many of us have actually used an application developed in Flash? (Other than Rich Kilmer).

So what does Silverlight have that the others don’t? At first glance, it is just the Flash model. Except, its the Flash model with multiple possible languages with which to write your code. So you get reach, rich controls, browser interaction, access to extra-browser capabilities, cross-platform deployment AND your choice of C#, VB, JScript, IronPython or IronRuby to author your apps. The downsides seem to be Microsoft dependence, lack of *nix support, lack of Standards (meaning minimal third-party ability to create more deployment vectors), and the Microsoft Permissive License (worst legal document name EVAH…sounds like something from a swingers’ club).

What about JavaFX?

So, Sun immediately comes out with its answer to Silverlight, called JavaFX. It seems to be an unimpressive, needless alternative to Groovy (I’m not alone in thinking this. It has no coherent deployment story, other than the JavaFX Mobile platform, so it at least hits a niche Microsoft missed on its first swing. I think I’ll just stick with Groovy, thanks. Or JRuby. Or Jython. Or anything that doesn’t have this lame q/a in its FAQ:

Why isn’t Groovy enough? Groovy and other languages have two specific traits which don’t precisely meet these needs, namely that they are generic in nature and don’t provide the appropriate abstractions necessary to optimize the UI design process and similarly are designed specifically for programmers other than content authors.

I mean, c’mon. Even if you leave aside the actual SwingBuilder libraries and other downloadable UI layers for Groovy that already exist, the entire POINT of a language like Groovy is that it is flexible enough to write those abstractions your own damn self. That reasoning is beyond flawed; its written by a salesman, who doesn’t have the faintest idea what Groovy is, or why anybody would use it. Which brings me to point #4….

The DLR

When you hear Microsoft people speak of Silverlight, they will often mention the DLR (Dynamic Language Runtime). This is the layer that replaces the IronPython bridge and RubyCLR. They’ve created a common type system for a variety of languages, including JScript, VB (the way it ought to be), IronPython, and now IronRuby. It then provides a bridge between this dynamic type system and the standard CTS. It currently runs in Silverlight, which means it will let me write my in-browser code in Ruby, which makes me happy.

In fact, I’d argue that the DLR was my favorite attempt at a new runtime for Dynamic languages except for two small items: first, the team has gone and written its own spec for dynamic type systems without really playing with the other kids on the block. Charles Nutter, for example, has been leading the charge on creating a real spec for Ruby, and Microsoft pretty much sidestepped the whole thing. The second issue is….

Microsoft might be the lamest company in existence.

Microsoft recently announced that it believes that up to 235 of its patents have been infringed by FOSS. They are laying the groundwork for a culling of the herd; they are threatening legal action, hoping that the weakest of the FOSS vendors will crawl into Redmond and pay tithe so they won’t have to go to court over the issue. Microsoft really doesn’t want to go to court. They’ve already beta tested that option by sponsoring SCO. No, Microsoft just wants to spread the FUD and pocket the low-hanging fruit. I’m with Tim on this one.

All of which means that, if Microsoft is going to go and adopt open source technologies to make their platform better, while distributing their own code under what can best be described as the Nixon-mask version of an open source license, and then spread FUD grenades around in the crowded marketplace, then their dynamic platform has very little real chance of being adopted by anybody outside of Redmond.

Groovy and Grails: Ten Pleasant Surprises

  • Posted By Stuart Halloway on May 15, 2007

After meeting Graeme Rocher at JavaOne, I decided it was time to give Groovy and Grails a second look. Here are the ten items that jumped out at me, as a Java and Ruby developer learning about Groovy and Grails:

  1. While new languages often introduce gratuitous syntactic differences, Groovy's differences are often appealing. I think I could come to like the syntax for case equality (===), hashes ([x:'y']), and open ranges (1.<10) better than their Ruby counterparts.
  2. I have often wished for the safe dereference operator (e.g. org.person?.name) when writing Ruby code. I am sure people will use this to paper over Demeter violations, but it is nevertheless worth having.
  3. Grails defaults to an in-memory HSQLDB database for development. This is even easier than Rails, setup-wise.
  4. Grails follows Rails' lead in providing a flash scope, and goes a step further in implementing a chain scope. I will be adding this feature to my Rails projects.
  5. Grails has a built-in dynamic scaffold, more like Streamlined than a static scaffold.
  6. Grails generalizes the notion of a builder library with reusable support for building arbitrary nested structures.
  7. Grails' model saving support (save/validate/discard) is more complex than Rails'. On first glance, I feared this was unnecessary complication, but actually it is quite nice. The common case is simple, and parallel to Rails. The other cases are there if you need them.
  8. As applications become more complex, Grails makes nice use of Spring's autowiring to inject supporting classes. (I find that excessive autowiring obfuscates relationships, but the Grails examples I have seen so far look just right.)
  9. The Groovy MetaClass (and its use in Grails) is very powerful. As Graeme points out, the MetaClass brings Groovy much closer to having the whole language there, all the time. Groovy still does not have open classes, but open invocation is a workable alternative for many use cases.
  10. The Definitive Guide to Grails is a very good book. If you are coming from a Java or Ruby background, this book is a perfect jump start for both Groovy and Grails.

Staying on Topic

  • Posted By Stuart Halloway on May 14, 2007

Several people have responded to my post on static typing and readability, and mostly they have missed what I actually said. I'll try again:

Thanks to the success of Rails, Seaside, Grails, and others, many developers are considering dynamic languages for the first time, or in a new light. These developers are often concerned that without static typing, their code will be unreadable. There are good reasons for static typing, but this is not one of them. Languages do not write readable code, programmers do. Good programmers can write readable code with static or dynamic typing, with "good" or "bad" frameworks.

In order to make this clear, I demonstrated some common decisions that make statically typed code less readable, despite the presence of type information. I also demonstrated some readable code without type information.

To the commenter feedback: Kabir refers me to Haskell and OCaml. Good languages, but not the point. I am not trying to prove that all static languages are bureaucratic. My issue is the assumption that dynamic language code is unreadable with type information.

Robert points out that I am comparing programming idioms, not languages. True. Robert, I completely agree with everything you have to say.

ocean thinks that my example is outdated and the argument therefore should not be taken seriously. I am glad you find the code outdated--I do too, and I said so in the original post. When we wrote R4JD, we wanted to pick examples that every Java developer would recognize. I have traveled the country asking Java developers what frameworks they use, and even today my anecdotal best guess is that over 60% are on Struts 1.x.

Norman, Slava, and Hani think I am comparing Java and Ruby, and announcing Ruby the winner. I certainly didn't say anything like that here. I have compared Ruby and Java web development before, and you can read the reviews to see if readers found the comparison fair and helpful.

Bob Lee: thanks for the on-topic comment. Bob's concerns about dynamic typing and maintainability need to be addressed more fully than I have time for here. But let me start by saying that not all code is a reusable API. And wouldn't Groovy give you what you want?

Static Typing and Readable Code

  • Posted By Stuart Halloway on May 12, 2007

Neal's post Static Typing is Communist Bureaucracy has drawn out the usual arguments on both sides of dynamic vs. static typing debate. I fielded many of the same kinds of questions at my Rails for Java Developers talk at Java University.

One of the most common questions asked by people moving from static to dynamic languages is "How can I tell what the code does without the type information?" This is a good point! Static typing makes code readable, just like training wheels make a bicycle ridable. But eventually you want more than not-falling. You want elegance and speed.

Here is a specific example from R4JD. Consider the following (old school) Struts+Spring code from a simple CRUD app.

  public ActionForward edit(ActionMapping mapping, ActionForm form,
                            HttpServletRequest request,
                            HttpServletResponse response)
      throws Exception {
    PersonForm personForm = (PersonForm) form;
    if (personForm.getId() != null) {
      PersonManager mgr = (PersonManager) getBean("personManager");
      Person person = mgr.getPerson(personForm.getId());
      personForm = (PersonForm) convert(person);
      updateFormBean(mapping, request, personForm);
    }
    return mapping.findForward("edit");
  }

There are nine static types in play here: one return type, four arguments, one exception type, and three local variables. An experienced Java developer should have no trouble reading this code. Here is the equivalent Ruby on Rails code:

  def edit
    @person = Person.find(params[:id])
  end

There are only two dynamic types in play here: the params and the @person. A novice Rails programmer should have no trouble reading this code.

Why are the two examples so different?

  1. The Struts example uses four typed arguments where the Rails example uses none (equivalent objects are available as fields on the controller instance, but they are out of sight unless you need them).
  2. The Struts example introduces two types (Exception and PersonForm) for no other reason than to make the compiler happy. This is the obvious example of Neal's Communist Bureuacracy argument.
  3. The Struts example uses two different objects to represent the same person: personForm and person. In the Java world this approach is a good thing, and called separation of concerns. Compared to a more flexible language, this is another form of the Communist Bureaucracy. Because Java classes are closed at compile time, you must get the separation of concerns right at design time. In a language with open classes (Ruby, Groovy, Smalltalk, et al) you can separate the concerns only when and if they need to be separated.
  4. The Struts example introduces a manager layer. More Communist Bureaucracy. The manager layer anticipates a future that may or may not happen. Because the language is inflexible, future-proofing is often done during initial development.

Languages do not write readable code, programmers do. Trying to bake readability into a programming language is like trying to bake poetry into grammar. A better idea is to create a flexible language and let human creativity flow.

Rails for Java in Charlottesville...

  • Posted By Stuart Halloway on May 04, 2007
If you can't make it to Java University for Ruby on Rails for Java Technology Developers, how about a shorter version of the same talk at the combined meeting of the Richmond Java Users Group and the Central Virginia Ruby Enthusiasts Group? It is great to have these communities coming together. See you May 10th.

Rails for Java Developers @JavaOne

  • Posted By Stuart Halloway on May 04, 2007
I will be giving the Ruby on Rails for Java Technology Developers session at Java University prior to JavaOne. Stop by Monday night if you are in town. You may want to come early, the official site mentioned limited capacity for the evening sessions.

Interview and Excerpt at ComputerWorld

  • Posted By Justin Gehtland on May 03, 2007

Recently, Joyce Carpenter over at ComputerWorld posted an excerpt from Rails for Java Developers at the ComputerWorld site. We ended up with part of Chapter 2 on Ruby syntax as the excerpt.

What was even more fun was that she and I did a 32 minute interview in support of the post. She originally wanted to edit it down to 12 minutes of material, but after we were through, she just edited out all the "uhhhh"s and "weeellllll"s and dead space of me trying to remove my foot from my mouth and we ended up with a 25 minute podcast attached to the article. She did a great job of making me sound good -- check it out for the Relevance position on Ruby, Rails, Java and more, straight from one of the horses' mouth.

Code-first, WSDL-first, Schema-first

  • Posted By Stuart Halloway on May 03, 2007

A problem with web services in practice is the lack of a middle ground between code-first and WSDL-first development. The former is typically misused to produce a bloated RPC interface. The latter increases the odds that you will think in terms of messages instead of methods (good!) but brings in the entire congitive load of WSDL (bad, when for many situations all you really want is Schema or less).

Craig Walls describes a third path: define the Schema, then use a tool to generate the WSDL. He also makes some good points about the meaning of "first" in phrases like "WSDL-first": An approach can be WDSL-first even if you generate the WSDL with a tool. I will definitely look at DynamicWsdl11Definition the next time I need to define a service.