|
August 2005
[
tirsen
]
06:31, Friday, 19 August 2005
Joel is writing about how much he likes BDUF and in doing so reveals exactly how little he understands of XP and what XP-practitioners refer to as Big Up Front Design or in short BDUF. Downloading and reading through the linked PDF which is the specification for his Project Aardvark or Copilot reveals a functional specification which is a perfectly sound document to have in a "true" XP project. At ThoughtWorks very few projects start without a document of at least the same magnitude (disregarding maybe from some smaller details). We split it up into stories, estimate and rate them and run it through some clever Excel spreadsheet employing various statistical analysis. Out comes a pretty good estimate of how long the projects going to take and what it's going to cost. We call it inception and it's a perfectly "acceptable" thing to do at an XP project. It is the next step after that in a typical waterfall project that we skip and go straight to development. This step is what we refer to as BDUF. Here fancy "designers" and "architects" go through the functional specifications and using various CASE tools start designing every single component in the system. Down to each class and method. This is what we call Big Design Up Front and Joel, honestly, not even you would be so crazy to do that. We wouldn't say you're doing BDUF Joel, you're doing EDUF, Enough Design Up Front. We XPers like to do that too.
[
tirsen
]
04:14, Thursday, 18 August 2005
It was when I for the umptenth time broke another unit test in script.aculo.us that I decided that it just had to be enough! We need continuous integration for these buggered JavaScript unit tests. Rake to the rescue! After some hacking around on the ferry to work I had the solution!
desc "Runs all the JavaScript unit tests and collects the results"
JavaScriptTestTask.new(:unittest) do |t|
t.mount("/lib")
t.mount("/src")
t.mount("/test")
t.run("/test/unit/unittest_test.html")
t.run("/test/unit/ajax_inplaceeditor_test.html")
t.run("/test/unit/string_test.html")
t.run("/test/unit/builder_test.html")
t.browser(:safari)
t.browser(:firefox)
end
This will start a WEBRick server with the specified files mounted, run all the combinations of browsers and tests and report back the results: beatrix:~/Projects/rails/spinoffs/scriptaculous tirsen$ rake unittest (in /Users/tirsen/Projects/rails/spinoffs/scriptaculous) /test/unit/unittest_test.html on Safari: FAILURE /test/unit/ajax_inplaceeditor_test.html on Safari: ERROR /test/unit/string_test.html on Safari: SUCCESS /test/unit/builder_test.html on Safari: FAILURE /test/unit/unittest_test.html on Firefox: SUCCESS /test/unit/ajax_inplaceeditor_test.html on Firefox: SUCCESS /test/unit/string_test.html on Firefox: SUCCESS /test/unit/builder_test.html on Firefox: SUCCESS Coming to a script.aculo.us SVN repository near you soon! (Caveat: Only works on the Mac at the moment. Maybe it's time to switch like the rest of the world.)
[
tirsen
]
06:37, Tuesday, 16 August 2005
I’m pleased with how the best practices of doing remoting are emerging in Ajax. Most Ajax libraries have ditched the RPC approach to remoting and are instead using a very specialized form of distributed computing. Please allow me to explain… Simple call, simple return The simplest form of remote interchange in Ajax can be seen in for example the in place editor of photo titles and descriptions at Flickr (here's a demo of an upcoming control in script.aculo.us that implements this, be warned though it still very much pre-release quality). It’s a simple REST style call, a url is constructed with the updated title or description as a simple parameter. Any return value is sent verbatim in the body of the response and used directly by the JavaScript code in the browser. This can be compared to an ordinary RPC call. Simple call, snippet returned The next step in complexity is when a more complex value needs to be returned (like as a list of values or multiple named values). An example of this is the script.aculo.us auto completing text fields. The text is once again sent in simple REST style with the parameters encoded in the URL. The result of the call is where the interesting bits come in, instead of returning a serialized data structure that needs unmarshalling and interpretation on the client side the server simply returns the HTML snippet of the result pane. All the client needs to do is use the browsers built in HTML parser (the result is in fact already parsed by the XmlHttpRequest) and update the DOM of the result pane. The remote call is completely adapted to the client, which is almost the opposite of CORBA-style remoting or web services where the remote interface is supposed to be completely generic and it is the client responsibility to figure out how to handle the result. Simple call, behaviour returned The last approach is even more interesting (and could be called agent oriented by the widest stretch of the definition). It’s used a little bit by Gmail and is implemented by the evaluate_remote_response in Ruby on Rails. This technique also encodes arguments as URL query parameters but the result at this time is neither a simple value nor an HTML snippet, it is a JavaScript snippet which is directly evaluated by the client! The server can return any number of HTML snippets, execute graphical effects, update different cells in a table, navigate to a different page and so on. Is this good? I can hear some of you protest: “But the client becomes tightly coupled to the server! This is horrendous!” A lot of people feel that there are compelling reasons to make an abstraction layer along the same lines as the distribution layer. There are reasons to do this, but personally I don’t buy it; the only way to effectively handle a distribution boundary is by specifically designing both sides of the boundary to accommodate to each other. Ultimately designing the remote interface directly according to how the user will interact with the application. One single user transaction may span several conceptual transactions with the system, in a traditional RPC-style remoting design this would mean multiple remote calls which is quite ineffective. In Ajax it would be one single call using one of the three methods as described above. Much more effective. Another reason for making the remote interface generic and system-driven (as opposed to user-driven) is because in a traditional client/server scenario there’s much less control of the client. The server may for example need to support multiple versions of the client or different clients at the same time. This is not the case in an Ajax-enabled web application, the server has a pretty strong control over the client. The browser does cache some stuff (according to specification by the server) but nothing is ever installed on the client. There is only ever one version of the client and when the server gets upgraded so does the client. Finally remember that this is not about integrating two different systems, it’s one single system with a distribution boundary in the middle. If we're talking system-to-system integration then CORBA, EJBs, web services, messaging, SOA or whatever's the latest trend are all valid candidates. The approach used by many Ajax applications also means that a lot more of the presentation logic executes at the server. Paradoxically this stems from the fact that web applications in the end actually don't have very strong control of the client. There are a lot of differences between different browsers and in terms of security the server can never depend on something getting executed in the browser. Instead the best practice seems to be to delegate a lot of the logic to the server that returns pre-baked responses that require very little logic to handle on the client. The end result is that many Ajax applications has an extremely tight collaboration between client and server, so tight that the distribution boundary is in fact conceptually blurred and the conceptual presentation layer could be said to run both on the server and the client. Or in other words... The conceptual division between presentation logic and business logic does not coincide with the physical separation of client and server. So are Ajax developers guru software designers for coming up with this? I don’t think most Ajax developers are aware of all this. The good ones are simply pragmatic programmers that are more focused on the user experience than theoretical mumbo-jumbo like this article (which kinda explains why PHP could've ever been so popular, the horrible language that it is). So the special approach to remoting that is used in many Ajax applications has developed in a much more pragmatic (and I would say healthier) fashion than with for example CORBA or Web services. If you permit me to interpret and extrapolate this a little bit then I would even say that this could mean that Ajax web applications may soon become a very serious competitor to desktop applications. The best practices and frameworks in the "AJAX community" is simply better positioned to delivering compelling applications instead of complying to various pretty theoretical dogmas. So, well, I’m pretty pleased about it… Post scriptum: What about more complex calls? All these designs use a simple REST style call from the client, which only allows for simple values or name/value encoded pairs. I have yet to observe a more complex call from the client "in the wild". There's the drag-and-drop list reordering callback in script.aculo.us which is essentially a list of ids but it's still pretty simple. If anyone has a good example of a more complex call I'd love to hear about it! Post scriptum 2 Sorry for mainly using examples from script.aculo.us, it's simply the Ajax framework I know best.
[
tirsen
]
09:46, Sunday, 7 August 2005
From Jim Weirich (the maker of Rake, make for Ruby) comes an excellent presentation of dependency injection and whether it's needed in Ruby: http://www.onestepback.org/articles/depinj/index.html I just love when a technology or pattern grows up, passes the buzz stage and you can really get a grip on what it's about and what to use it for. |