| Zen Refactoring
|
|
24 May 05 |
|
[print
link
all
] |
Alex Chaffee posted this to the xp-list.
Yesterday I was pairing with Patrick, our new intern. He's great,
smart as a whip, and willing to learn. (When I told him we write tests
first, he laughed, incredulously, but then I said No, really, I'm
actually serious, and he listened, and later, he said, Oh, now I see.)
At the end of a long successful refactoring (turning a clutch of
static methods into instance methods), we were sort of buzzing and
didn't want to stop, were casting about for other refactorings to do
in the same class. I suggested a technique I only just then gave a
name to, that I've done occasionally on my own for a long time, but
hadn't yet taught: Zen Refactoring.
"Just let your eyes unfocus and scroll through the code and look for
refactorings. Look for duplication; look for too-long or
too-deeply-indented code blocks. When you notice something odd, don't
read it, just select it, hit Extract Method (ctl-alt-M), and hit
random keys for the name. Then focus your eyes again and see what
you've done."
I demonstrated. The first time we hit a bunch of print statements with
repeated formatting -- it worked, but the refactoring was tedious,
with marginal payoff. But the second time was golden. I saw a blurry
if-else block; the first arm meandered for 15 or 20 deeply-indented
lines, the second for fewer; their logic appeared opaque and disjoint.
But after extracting the first block as a method, lo and behold:
if (something() || other()) {
customerId = sdlfjds(x, y, z);
} else {
user = someOtherExistingMethod();
customerId = user.getUserId();
}
IDEA had figured out that the result of that meander was a single
value, and returned it from the new method. It was instantly clear
that we should rename the extracted method
customerIdForSomethingOrOther", and extract the whole conditional as
"getCustomerId". Shift-F6, ctl-alt-M, high five.
Then it was Patrick's turn. Not quite as much of a slam-dunk but still
a worthy refactoring. I can't wait to get an incredulous laugh from
the next one I spring this on...
|
| AutrijusRaisingPerl6IntoARealPuppy
|
|
18 May 05 |
|
[print
link
all
] |
|
Perl6 in Haskell after 100 days .. :-) Enjoy the link redhanded.hobix.com/inspect/autrijusRaisingPerl6IntoARealPuppy.html
|
| When talking to CEO and CFO types ..
|
|
16 May 05 |
|
[print
link
all
] |
Ron Jeffries posted in the xp-list:
When I talk with CEO and CFO types, I generally emphasize that XP /
Agile projects focus on the delivery of running, tested, actual
software, along the lines of my article /A Metric Leading to
Agility/, http://www.xprogramming.com/xpmag/jatRtsMetric.htm
|
| Good article about Tiger
|
|
08 May 05 |
|
[print
link
all
] |
|
My girlfriend told me to get a computer that makes less noise .. so I took
the opportunity to buy a Mac-Mini and to have a nice computer to play with
:-).
Thanks to Sven for emailing me this link .. a good overview article about
Tiger. arstechnica.com/reviews/os/macosx-10.4.ars
|
| Nice graphics
|
|
06 May 05 |
|
[print
link
all
] |
|
Joao made this nice graphics and posted it in his blog
|
| Link of the day
|
|
04 May 05 |
|
[print
link
all
] |
|
links.userfriendly.org/lotd/http://www.delltechforce.com/
Die Larry Ellison Puppe k?mpft gegen "Big Iron" und sagt
"Let’s go in and kick some proprietory ass!"
ROTFL
|
| Sin City Comic-to-Screen Comoparison
|
|
24 Apr 05 |
|
[print
link
all
] |
Very nice link
about a cool movie.
|
| Seeing Metaclasses Clearly
|
|
19 Apr 05 |
|
[print
link
all
] |
why wrote a nice article.
I've written a very nuts+bolts article on metaclasses (aka virtual
classes or metaobjects), since they still lurk under a shroud of fear
and enigma.
whytheluckystiff.net/articles/seeingMetaclassesClearly.html
I'm hoping this will help uncover the truth. If anything is unclear,
please report it. Shed a light.
|
| 300 engineers take forever writing anything
|
|
19 Apr 05 |
|
[print
link
all
] |
Nice post by Elizabeth D. Rather
Heh, that reminds me of a time in the late 70's, when IBM came out with a
new "mini-computer". We put Forth on it for a customer. Our standard
system came with a database capability, multitasker, multi-user support,
lots of other features. Another customer was considering this machine, and
we made a presentation on our software. Some IBM engineers were also there.
They said, "This machine has only been on the market for a few months. We
have 300 engineers writing software for it in Boca Raton (Florida), and they
only have a macro assembler and simple executive running so far. How could
you have done all this with only one engineer?"
Well, I said something about having a standard design implemented in high
level that was easy to port, but of course the real answer is that 300
engineers would take forever writing anything!
|
| Enterprise software
|
|
11 Apr 05 |
|
[print
link
all
] |
|
Software development and software buying in big companies can be rather
sick. This is a nice report about the madness in a common enterprise. link
I think I have to read my daily Dilbert now, before making yet another
Powerpoint presentation for work, instead of fixing my bugs.
|
| wee: More novel than popular
|
|
30 Mar 05 |
|
[print
link
all
] |
Avi posted a nice entry
about seaside, rails and wee.
Rails ... doesn't have any novel ideas. I'm not
trying to talk it down, that's just the reality of what
Rails is -- it's not Seaside or Wee (and if it was it
wouldn't be so popular anyway).
*More novel than popular; I can live with that.*
|
| Making videos to show off your latest software
|
|
28 Mar 05 |
|
[print
link
all
] |
|
xvidcap is a great tool to to
capture things going on on an X-Windows display to either individual frames
or an MPEG video.
A big thanks to Michael Neumann who pointed out this too to me. He made his
great wee-videos with xvidcap.
|
| Packet sniffing and replay
|
|
27 Mar 05 |
|
[print
link
all
] |
|
I just came across this most useful ksnuffle. It will
help us to automate some more work.
|
| RubyScript2Exe 0.3.3 is released!
|
|
26 Mar 05 |
|
[print
link
all
] |
|
RubyScript2Exe transforms your Ruby script into a standalone, compressed
Windows, Linux or Max OS X (Darwin) executable. You can look at it as a
"compiler". Not in the sense of a source-code-to-byte-code
compiler, but as a "collector", for it collects all necessary
files to run your script on an other machine: the Ruby script, the Ruby
interpreter and the Ruby runtime library (stripped down for this script).
Anyway, the result is the same: a standalone executable (application.exe).
And that’s what we want!
gegroet, Erik V.
link
|
| Rake 0.5.0 Released
|
|
26 Mar 05 |
|
[print
link
all
] |
It has been a long time in coming, but we finally have a new version of
Rake available.
Changes
- Fixed bug where missing intermediate file dependencies could cause an abort
with —trace or —dry-run. (Brian Chandler)
- Recursive rules are now supported (Tilman Sauerbeck).
- Added tar.gz and tar.bz2 support to package task (Tilman Sauerbeck).
- Added warning option for the Test Task (requested by Eric Hodel).
- The jamis rdoc template is only used if it exists.
- Added fix for Ruby 1.8.2 test/unit and rails problem.
- Added contributed rake man file. (Jani Monoses)
- Fixed documentation that was lacking the Rake module name (Tilman
Sauerbeck).
What is Rake
Rake is a build tool similar to the make program in many ways. But instead
of cryptic make recipes, Rake uses standard Ruby code to declare tasks and
dependencies. You have the full power of a modern scripting language built
right into your build tool.
Availability
The easiest way to get and install rake is via RubyGems
…
gem install rake (you may need root/admin privileges)
Otherwise, you can get it from the more traditional places:
Thanks
Lots of people provided input to this release. Thanks to Tilman Sauerbeck
for numerous patches, documentation fixes and suggestions. And for also
pushing me to get this release out. Also, thanks to Brian Chandler for the
finding and fixing —trace/dry-run fix. That was an obscure bug. Also
to Eric Hodel for some good suggestions.
— Jim Weirich
|
| .. that sounds like real life
|
|
13 Mar 05 |
|
[print
link
all
] |
|
I was once on a project where the customer realized only after 1.5 months
that they want us to modify an application that does not even exist at that
company. You really makes you wonder what goes on in big companies .. Great
Dilbert comic
|
| How to start a startup?
|
|
10 Mar 05 |
|
[print
link
all
] |
|
Nice article by Paul
Graham.
You need three things to create a successful startup: to start with good
people, to make something customers actually want, and to spend as little
money as possible. Most startups that fail do it because they fail at one
of these. A startup that does all three will probably succeed.
And that’s kind of exciting, when you think about it, because all
three are doable. Hard, but doable. And since a startup that succeeds
ordinarily makes its founders rich, that implies getting rich is doable
too. Hard, but doable.
If there is one message I’d like to get across about startups,
that’s it. There is no magically difficult step that requires
brilliance to solve.
|
| A cool job announcement
|
|
07 Mar 05 |
|
[print
link
all
] |
.. seen this in today’s ruby-talk
#!/usr/bin/env ruby
# Warning this is a job announcement!
# Run it/Read it if you are interested.
# Lack of comments and robust input handling are intentional.
class Company
attr_accessor :name, :location, :web_site, :description
attr_accessor :available_jobs
def initialize(name = nil, location = nil, web_site = nil)
self.name = name
self.location = location
self.web_site = web_site
self.available_jobs = Array.new
end
def ask_for_interview?(job_applicant)
available_jobs.each do |ajob|
return true if ajob.meets_requirements?(job_applicant)
end
false
end
def describe
puts "Company : #{name}"
puts "Location : #{location}"
puts "Web site : #{web_site}"
puts "","Brief description :"
puts description, ""
end
def announce_job_availability(good_match, not_so_good_match)
return if available_jobs.empty?
describe
puts "Available jobs:"
available_jobs.each_with_index do |job, idx|
puts "", "#{idx + 1} ) #{job.name}", job.description, ""
end
job_applicant = ask_for_job_applicant_information
return if job_applicant.nil?
if ask_for_interview?( job_applicant )
puts good_match
else
puts not_so_good_match
end
end
def ask_for_job_applicant_information
job_applicant = nil
puts "Would you like to apply for a job? Y/N"
res = gets.chomp
if res =~ /Y/i
msg = "Great! Please follow the prompts to input your profile"
msg<< " to see if there if a job matches."
puts msg, ""
job_applicant = JobApplicant.new_from_interactive_shell
else
puts "Well thanks for reading/running the program! Good Bye!"
end
job_applicant
end
end
class Job
attr_accessor :name, :description, :requirements, :threshold
def initialize(name = nil, description = nil,
threshold = 100, requirements = [] )
self.name = name
self.description = description
self.requirements = requirements
self.threshold = threshold
end
def meets_requirements?(job_applicant)
points = 0
requirements.each do |req|
points += req.check_requirement(job_applicant)
end
points >= threshold
end
end
class JobApplicant
attr_accessor :name, :resume, :location
attr_accessor :spoken_languages, :computer_languages_skills
def initialize
self.spoken_languages = Array.new
self.computer_languages_skills = Array.new
end
def JobApplicant.new_from_interactive_shell
applicant = JobApplicant.new
puts "What is your name?"
applicant.name = gets.chomp
puts "Where do you live? (City, Country)"
applicant.location = gets.chomp
note = " [One entry per line. Press CTRL-D to stop input] "
puts "What languages do you speak?", note
applicant.spoken_languages = readlines.map { |d| d.chomp }
cq1 = "What computer languages are you proficient in?"
cq2 = "And what other computer skills do you have?"
puts cq1, cq2, note
applicant.computer_languages_skills = readlines.map {|d| d.chomp }
puts ""
applicant
end
end
class Requirement
def initialize(points = 1, &proc)
@points = points
if proc
@requirement_calc = proc
else
@requirement_calc = Proc.new { |x| true }
end
end
def check_requirement(job_applicant)
points = 0
if @requirement_calc.call(job_applicant)
points = @points
end
points
end
end
ubit = Company.new("Ubit", "Tokyo, Japan", "http://ubit.com")
ubit.description =<<EOF
Ubit is a Japanese company focusing on mobile phone services and
content aggregation both in Japan and abroad.
EOF
developer = Job.new("Software Developer")
developer.description =<<EOF
Become knowledgeable in the inner workings of our
product platform and work as a team with other developers to implement
new features and improve our current capabilities. Ideally, you are
willing to work under dynamic conditions and communicate well with
others.
EOF
loose_find = lambda do |data, reg_match|
data.find { |v| v =~ match }
end
reqs = Array.new
reqs<< Requirement.new(25) do |ja|
ja.spoken_languages.include?("English")
end
reqs<< Requirement.new(25) do |ja|
ja.spoken_languages.include?("Japanese")
end
reqs<< Requirement.new(5) do |ja|
sub = ["English", "Japanese"]
(ja.spoken_languages - sub).size > 0
end
reqs<< Requirement.new(50) do |ja|
ja.computer_languages_skills.include?("Ruby")
end
reqs<< Requirement.new(25) do |ja|
ja.computer_languages_skills.include?("Databases")
end
reqs<< Requirement.new(10) do |ja|
ja.computer_languages_skills.include?("Mobile Technologies")
end
reqs<< Requirement.new(5) do |ja|
ja.computer_languages_skills.include?("*NIX")
end
reqs<< Requirement.new(5) do |ja|
(ja.computer_languages_skills - ["Ruby", "Database"]).size > 0
end
reqs<< Requirement.new(25) do |ja|
ja.location =~ /Japan/i
end
developer.requirements = reqs
developer.threshold = 125
ubit.available_jobs<< developer
good_match =<<EOF
Your profile looks promising!
If you are interested in working with us,
please send your resume to Zev Blut at rubyzbibd@ubit.com
EOF
nsgm =<<EOF
Sorry, at the moment we are in need of people who meet our specific
needs. But if you feel that you can meet them then go ahead and send
your resume to Zev Blut at rubyzbibd@ubit.com
EOF
ubit.announce_job_availability(good_match,nsgm)
> Now that is just too cool :-)
>
> Cheers,
> Tim
Hi, I found a few ways to improve your program.
--- tokyo_job.rb.orig 2005-03-07 12:41:23.457936200 -0500
+++ tokyo_job.rb 2005-03-07 13:16:14.736811208 -0500
@@ -101,11 +102,11 @@
applicant.location = gets.chomp
note = " [One entry per line. Press CTRL-D to stop input] "
puts "What languages do you speak?", note
- applicant.spoken_languages = readlines.map { |d| d.chomp }
+ applicant.spoken_languages = readlines.map { |d| d.downcase.chomp }
cq1 = "What computer languages are you proficient in?"
cq2 = "And what other computer skills do you have?"
puts cq1, cq2, note
- applicant.computer_languages_skills = readlines.map {|d| d.chomp }
+ applicant.computer_languages_skills = readlines.map {|d|
d.downcase.chomp }
puts ""
applicant
end
@@ -157,42 +158,55 @@
reqs = Array.new
reqs<< Requirement.new(25) do |ja|
- ja.spoken_languages.include?("English")
+ ja.spoken_languages.include?("english")
end
reqs<< Requirement.new(25) do |ja|
- ja.spoken_languages.include?("Japanese")
+ ja.spoken_languages.include?("japanese")
end
reqs<< Requirement.new(5) do |ja|
- sub = ["English", "Japanese"]
+ sub = ["english", "japanese"]
(ja.spoken_languages - sub).size > 0
end
reqs<< Requirement.new(50) do |ja|
- ja.computer_languages_skills.include?("Ruby")
+ ja.computer_languages_skills.include?("ruby")
end
reqs<< Requirement.new(25) do |ja|
- ja.computer_languages_skills.include?("Databases")
+ ja.computer_languages_skills.grep(/database/).size > 0 or
+ ja.computer_languages_skills.grep(/\bdb\b/).size > 0
+ ja.computer_languages_skills.grep(/sql/).size > 0
end
reqs<< Requirement.new(10) do |ja|
- ja.computer_languages_skills.include?("Mobile Technologies")
+ ja.computer_languages_skills.include?("mobile technologies")
end
reqs<< Requirement.new(5) do |ja|
- ja.computer_languages_skills.include?("*NIX")
+ ja.computer_languages_skills.grep(/linux|unix/).size > 0
end
reqs<< Requirement.new(5) do |ja|
- (ja.computer_languages_skills - ["Ruby", "Database"]).size > 0
+ ja.computer_languages_skills.find_all do |lang|
+ case lang
+ when /ruby/, /database/, /\bdb\b/, /sql/
+ false
+ else
+ true
+ end
+ end.size > 0
end
reqs<< Requirement.new(25) do |ja|
ja.location =~ /Japan/i
end
+reqs<< Requirement.new(5) do |ja|
+ ja.name =~ /Ben/i
+end
+
developer.requirements = reqs
developer.threshold = 125
With these changes, it doesn't require '*NIX', but will accept "Linux"
or "Unix", and it is a bit more accepting of various database keywords.
(Oh yeah, and it assigns bonus points for cool names)
Ben
(P.S. !Japan, !Japanese, !"Mobile Technologies", and !currently_looking?
but that was too much fun to pass up. :) )
|
| ANN: IHelp 0.3.0
|
|
26 Feb 05 |
|
[print
link
all
] |
|
Announcing the release of IHelp 0.3.0.
fhtr.org/projects/ihelp/ fhtr.org/projects/ihelp/doc/
fhtr.org/projects/ihelp/releases/ihelp-0.3.0.tar.gz
This release brings with it custom help renderers, which you can leverage
to render help whenever you want, wherever you want and however you want.
Also included are a couple experimental renderers (no guarantees):
- #rubydoc_org opens the corresponding ruby-doc.org class help file using the
program defined in IHelp::WWW_BROWSER
- #rubytoruby_src uses Ryan Davis’ RubyToRuby class to print out the
source for the method.
blog.zenspider.com/archives/2005/02/rubytoruby.html
for more info about RubyToRuby.
Ri bindings for interactive use from within Ruby. Does a bit of
second-guessing (Instance method? Class method? Try both unless explicitly
defined. Not found in this class? Try the ancestor classes.)
Goal is that help is given for all methods that have help.
Examples:
require 'ihelp'
a = "string"
a.help
a.help :reverse
a.help :map
String.help
String.help :new
String.help :reverse
String.help :map
String.instance_help :reverse
String.instance_help :new # => No help found.
a.help :new
help "String#reverse"
help "String.reverse"
a.method(:reverse).help # gets help for Method
help "Hash#map"
Custom help renderers: The help-method calls IHelp::Renderer’s method
defined by IHelp.renderer with the RI info object. You can print help out
the way you want by defining your own renderer method in IHelp::Renderer
and setting IHelp.renderer to the name of the method.
require 'ihelp'
class IHelp::Renderer
def print_name(info)
puts info.full_name
end
end
IHelp.renderer = :print_name
[1,2,3].help:reject
# Array#reject
# => nil
|
|
|