Subbu says that JSF is Not Fixable. His he right or his he wrong? That is the question!
I've been wanting to write about JSF for a while now. I was an early adopter and big proponent of JSF when it first appear at the surface of Java land. Since then, I've worked on many projects that used this framework and slowly but surely, my opinion changed about this framework.
In Subbu opinion, JSF is not fixable because it was not designed with web architecture in mind. The framework is not RESTful and requires POST for everything. JSP proponent argue that RESTful is coming to JSF and it is even already supported right now when you use JBoss Seam.
It's true, that JSF is getting better. Facelets will become part of JSF (it should have been there from day though - why make a brand new framework and use broken things like JSPs). JSF 2.0 will make some space for GETs and JBoss Seam fixes a lot of other issues with JSF.
However, if JSF is not Fixable, it is not solely because it is not RESTful. JSF is broken at many places.
The JSF request processing life-cycle is one of the worst thing about JSF. There is so many steps in the life-cycle, different ways to exit the normal processing and this gives something many entry points for custom components (one for each steps in the life-cycle). Things can go wrong at many places without even touching your application code.
Closely related to the request processing life-cycle, is the component model. In JSF, components are a kind of black box. But when you think that black box should be mostly independent on the framework (beside the connecting part with the framework), there is so many implementation leak in JSF, that your component must be ported to every JSF implementation. I say ported and not tested... Because the order in which the component tree is processed can make you component fail. You have to make so many assumption based on the JSF implementation (things that are not present in the specification) that you actually need to choose your JSF implementation carefully and will never be guaranteed that your component will survive even minor updates in the JSF implementation.
Want to add to functionality to an existing component? There is no easy way to do that. The best way, is to take the source code (if available) for the component and refactor it with some new name and then hack you way through it. And when I say hack, I mean it in a bad way! I've never saw a component source code that was easily readable and understandable. Large component sets like ADF Faces are notably ugly. Even the Swing component model (which is quite complex) is super simple compared to JSF component model.
It looks like in JSF, the worst thing about leaking abstractions made it into the framework and the good thing about encapsulation where left out.
And before I get flamed that you will be able, with JSF 2.0 - which is still in draft, to create composite components soon... I have to respond that soon is not now.
One of a good indication that JSF is broken beyond fixable, is that you cannot do simple thing simply. Want to create a new component, then you have something like 3 files to edit. Want to create a new converter, again, three files needs to be edited. I know that good thing came in sets of three, but this is not the kind of good I want.
Another good indication that JSF is broken beyond fixable, is when thing go wrong. Good luck finding you problem... Facelets help you a bit by giving you a more precise location of the issue. But it does not always work. When you look at stack trace, you have to scroll hundreds of line before you see the line from you application. But what the hell do you do when you don't even have any of you application code in the stacktrace? Why on earth, you are have a stacktrace that is 30-40 level deep before even reaching an action method? Just to process a fringing POST.
In JSF, the framework is everywhere except where you need it.
Yes, there is some good things about JSF, I like the expression language (even is it is a bit inconsistent and not powerful enough to my taste). But the bad things are so deeply rooted. If you are just a user of the framework and that you are writing really simple applications, then it does look like JSF is great, but whenever you start digging a bit and adding a bit of complexity (Ajax anyone? Without another component set that takes a few MB?), the framework start eating up your nerves.
So would I ever recommend JSF again? Maybe maybe not, in the Java world, there is so many framework to choose from, that your cannot recommend one with the certainty that it will still be around one or two years from now. The only sure thing, is that JSF will be there because it is the standard... And this is very sad!
10.30.2008
10.20.2008
Making Mr Bones work with jRuby
UPDATE : The fixes outlined bellow where incorporated by Tim in the main Mr Bones distribution. If you update to the latest gem, it will work out of the box with jRuby.
Want to make some GEM, Mr Bones (github) is going to help you setup your directory structure and comes with Rake tasks to package your application into a nice little Gem. The great thing about Mr Bones is that it does not add any dependencies to your Gem (like hoe does).
To create a new project, you just type bones [project_name] and you can start developping your application or library. You are done? type bones gem:install and your code is packaged and installed.
Want to do the same using jRuby instead of plain old Ruby (MRI)... You do just the same... But as of version 2.1.0, all you would just get errors when using Bones. The reason is that Mr Bones does things slightly differently dependings on the RUBY_PLATFORM value.
For example, if Bones detected that the platform was win32, it does it's redirection to nul: instead of /dev/null.
The problem with running Bones under jRuby, is that there is no win32 string in the value of RUBY_PLATFORM. Instead, you have java. So if you run Bones with jRuby under Windows, it does not beleive it's running under Windows and it does thing like it would if running under Unixes.
I really wanted Bones to work under jRuby, so I started working on a patch... Here is what I've done...
In lib/bones.rb, the existing code set a WIN32 constant to true if RUBY_PLATFORM contains win32. It then uses this constant to set DEV_NULL constant to the proper null device for redirection. I believe a more appropriate way of doing this is to check for the existence of /dev/null and then set DEV_NULL depending on the result. So on all Unix based OSes, the value would be /dev/null because it exists, else it would be nul: (these days, only Windows is not Unix based).
I also set a HOME constant that will point to the user home directory. To do this, I assign the value of the HOME environment variable and if its not set, I use the value of the USERPROFILE environment variable. Again, no need to check the platform, just check for things that should be there one way or another.
Finally, Bones will run things like rake or gem. It does so by using the system(...) method or Rake sh(...) method. This is fine if you have only one installation of Ruby on your system. But if you have many installation like I does, it will use the one it find in the PATH. So I use the same trick as Rake to find the ruby intepreter we are running on and set it to the RUBY constant. We will use this later on to make sure we use rake or gem for the same interpreter.
Here is the patch for lib/bones.rb :
Now onto lib/bones/main.rb. In main.rb, there are calls to rake. This is one place I use the RUBY constant mentionned earlier to execute rake from the same interpreter location and not from the system PATH. To do that, I just dodiff --git a/lib/bones.rb b/lib/bones.rbindex 50a63b6..35dcd75 100644--- a/lib/bones.rb+++ b/lib/bones.rb@@ -4,8 +4,9 @@ module Bones# :stopdoc:VERSION = '2.1.1'PATH = File.expand_path(File.join(File.dirname(__FILE__), '..'))- WIN32 = %r/win32/ =~ RUBY_PLATFORM- DEV_NULL = WIN32 ? 'NUL:' : '/dev/null'+ HOME = File.expand_path(ENV['HOME'] || ENV['USERPROFILE'])+ DEV_NULL = File.exist?("/dev/null") ? "/dev/null" : "nul:"+ RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']). sub(/.*\s.*/m, '"\&"') # Ruby Interpreter location - taken from Rake source code# :startdoc:
# Returns the path for Mr Bones. If any arguments are given,@@ -16,6 +17,7 @@ module Bonesargs.empty? ? PATH : File.join(PATH, args.flatten)end
+# call-seq:# Bones.require_all_libs_relative_to( filename, directory = nil )#@@ -46,7 +48,7 @@ module Bonesload bones_setup
rakefiles = Dir.glob(File.join(Dir.pwd, %w[tasks *.rake])).sort- import(*rakefiles)+ import(*rakefiles) unless rakefiles.empty?end
# TODO: fix file lists for Test::Unit and RSpec
system("#{::Bones::RUBY} -S rake ...") instead of just system("rake ...").
Ther was also a place in this file that the old WIN32 constant was used to find the user home directory. So I replace this with the HOME constant we talked a bit earlier.
Here is the patch for lib/bones/main.rb :
diff --git a/lib/bones/main.rb b/lib/bones/main.rbindex b7ec28b..1cc074a 100644--- a/lib/bones/main.rb+++ b/lib/bones/main.rb@@ -181,9 +181,9 @@ class Mainif test(?f, File.join(output_dir, 'Rakefile'))beginFileUtils.cd output_dir- system "rake manifest:create 2>&1 > #{::Bones::DEV_NULL}"+ system "#{::Bones::RUBY} -S rake manifest:create 2>&1 > #{::Bones::DEV_NULL}"@io.puts "now you need to fix these files"- system "rake notes"+ system "#{::Bones::RUBY} -S rake notes"ensureFileUtils.cd pwdend@@ -363,7 +363,7 @@ class Maindef mrbones_dirreturn @mrbones_dir if defined? @mrbones_dir
- path = (::Bones::WIN32 ? ENV['HOMEPATH'].tr("\\", "/") : ENV['HOME'])+ path = ::Bones::HOMEpath = File.join(path, '.mrbones')@mrbones_dir = File.expand_path(path)end
It was now lib/bones/tasks/setup.rb b/lib/bones/tasks/setup.rb turn to get dissected. There, it was again seting the value of a WIN32 constant with a slightly different logic than in bones.rb. It used this constant to set DEV_NULL again and then to use diff.exe instead of just diff when running under Windows. I removed the WIN32 constant. Got rid of the if used to add the ".exe" extension as they are not necessary. If ther is a diff.exe on Windows, system("diff ...") will work just nice. When checking for an appropriate diff utility, the existing code does some system commands inside a quiet context. the quiet(...) method just changed the stderr and stdout to the null device before running the block. There is a problem when calling the reopen() method under jRuby that made the quite method effect stay there until the end of the program. So I removed that method and used redirection in the system(...) call to acheive the same result.
I then set the value of the RCOV, RDOC and GEM constant to "#{RUBY} -S rcov", ... so that these commands execute under the same interpreter we are currently running.
Here is the lib/bones/tasks/setup.rb b/lib/bones/tasks/setup.rb patch :
diff --git a/lib/bones/tasks/setup.rb b/lib/bones/tasks/setup.rbindex 27d659b..a722c13 100644--- a/lib/bones/tasks/setup.rb+++ b/lib/bones/tasks/setup.rb@@ -5,7 +5,7 @@ require 'rake/clean'require 'fileutils'require 'ostruct'
-class OpenStruct; undef :gem; end+class OpenStruct; undef :gem if defined? gem; end
# TODO: make my own openstruct type object that includes descriptions# TODO: use the descriptions to output help on the available bones options@@ -123,36 +123,17 @@ import(*rakefiles)%w(lib ext).each {|dir| PROJ.libs << dir if test ?d, dir}
# Setup some constants-WIN32 = %r/djgpp|(cyg|ms|bcc)win|mingw/ =~ RUBY_PLATFORM unless defined? WIN32--DEV_NULL = WIN32 ? 'NUL:' : '/dev/null'--def quiet( &block )- io = [STDOUT.dup, STDERR.dup]- STDOUT.reopen DEV_NULL- STDERR.reopen DEV_NULL- block.call-ensure- STDOUT.reopen io.first- STDERR.reopen io.last- $stdout, $stderr = STDOUT, STDERR-end+DEV_NULL = File.exist?("/dev/null") ? "/dev/null" : "nul:"++DIFF = if system("gdiff '#{__FILE__}' '#{__FILE__}' > #{DEV_NULL} 2>&1") then 'gdiff'+ else 'diff' end unless defined? DIFF++SUDO = if system("which sudo > #{DEV_NULL} 2>&1") then 'sudo'+ else '' end
-DIFF = if WIN32 then 'diff.exe'- else- if quiet {system "gdiff", __FILE__, __FILE__} then 'gdiff'- else 'diff' end- end unless defined? DIFF--SUDO = if WIN32 then ''- else- if quiet {system 'which sudo'} then 'sudo'- else '' end- end--RCOV = WIN32 ? 'rcov.bat' : 'rcov'-RDOC = WIN32 ? 'rdoc.bat' : 'rdoc'-GEM = WIN32 ? 'gem.bat' : 'gem'+RCOV = "#{RUBY} -S rcov"+RDOC = "#{RUBY} -S rdoc"+GEM = "#{RUBY} -S gem"
%w(rcov spec/rake/spectask rubyforge bones facets/ansicode).each do |lib|begin
There is one last change that should be done to be able to run the specifications, we need to require 'rubygems' so the trick we took from Rake to get the current ruby interpreter work :
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rbindex 5a60dc1..1965e1c 100644--- a/spec/spec_helper.rb+++ b/spec/spec_helper.rb@@ -3,6 +3,7 @@unless defined? BONES_SPEC_HELPERBONES_SPEC_HELPER = true
+require 'rubygems'require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib bones]))
--
We can nw enjoy Bones with jRuby on Windows just like we would enjoy it under MRI.
I've submitted this patch to Tim, the auther of Mr Bones. While he review it, you can download it from here and apply it to your source tree to check it out.
9.09.2008
Google Chrome... One week after.
I've now been using Google Chrome for one week. And here is an update on my first impression.
Chrome is still my default browser, this is good :-) The browser did not crash once in that week. And it is almost always open. I use a laptop and shutdown/log off rarely (standby/hibernate most of the time). So I guess I can say that Google Chrome is very stable (better that Firefox). I did not even got one crash in a tab. I really like the speed and responsiveness of Chrome.
Other things I like :
- I assigned a shortcut for GMail. It now lives in its own window. What I like, is that when I'm in the GMail window and press Ctrl-T to open a new tab, instead of opening it in the GMail window, the tab is opened in my browser windows. This is how it should work. Great!
- In the rare cases when I close the browser and reopen it, all my tabs reload quickly without bogging down my system like Firefox did.
- Google Apps works better in Chrome that in Firefox... especially when the browser reload the tab when it's being opened.
All is not nice and dandy in Chrome though, here are some gripes I have with the browser :
- Lack of extensions. They say they will address the issue in a later version. In the meantime, bookmarklets are alleviating a bit the lack of extensions,
- Full page zoom please! The zoom feature of Chrome only increase font size. This is lame. Give me full page zoom like in Firefox 3,
- Directly open PDF and some other file types. When I download some file and the server set the content-disposition to attachment, Chrome absolutely want to save the file. Please give me the option of just opening the file with the associated application (saving it to a temporary location),
- They really should encrypt and password protect saved password. They cannot claim better privacy without this. I feel that should have done it from the start,
- Going to http://askville.amazon.com/ give me a page telling me that I'm not using a supported version of Safari,
- I encountered some layout issues. Most of them are minor. But when I access my internal time-sheet application (Oracle Applications), Some buttons used to submit the time-sheet are invisible.
- First week, first security update... Maybe this should go in part in the pros, but there is no notification (if you leave your browser open all the time) unless you go to the Tools | About Google Chrome menu.
None of the cons are really showstopper for me. So I guess I will continue to use Chrome for a while.
9.03.2008
Google Chrome First Impression
Yesterday, Google released their own browser. This release was like a little surprise. While it has been rumoured to be in work for a while, it was announced only the day before.
I don't know how many people downloaded it yesterday, but I'm one of them. I saw the little comic book explaining how the browser work and wanted to put my hand on the product. After a few hour playing with it, here are y tought on the browser :
- It's fast! Right when you start it, it really scream... It feels faster that Firefox 3. When you click, it looks like your actions are instantanious. For some reason, I'm even able to watch some higher definition movien in Flash that I were constantly pausing when using Firefox 3 (I don't beleive the browser makes Flash run better, but thats the feeling I get). Switching between tabs is also instantanious.
- Damn my screen look larger. The minimalist user interface make your browsing surface a bit larger. Granted, you could do that with IE and Firefox in Kiosk mode. But here, you have no choice... Just a big browsing area.
- Where are my mouse gestures? I was using a mouse gesture extension in Firefox. There seem to be no extensions and no way to write them for Chrome (I'm probably wrong here... I guess the APIs are not realsed yet but they'll be coming in a futher release).
- Better Privacy. Not so fast. They claim better privacy... But their password manager is not encrypted nor password protected! I don't realsy care about the other privacy features they offer. I don't believe they are much better that the ones in Firefox. I don't feel that the Internet is a dangerous place anyway.
- Gears bundled in. The Gears API are natively supported in the browser. They even automatically grant www.google.com the necessary rights. They shouldn't do that. However, they don't grant docs.google.com the Gears rights.
- I already miss extensions.
Overall, I feel this is a solid beta realease. I will keep using Chrome as my default browser for at least a few days. Maybe I'll get back to Firefox to get my extensions back.
Subscribe to:
Posts (Atom)