http://blogs.thoughtworks.com/
Planet TW - http://blogs.thoughtworks.com
Last checked 7 months ago.
6 people have subscribed to this feed.
post frequency (last month)
PostRank™
From Planet TW, 8 months ago,
0 comments
(The title quotes Joshua Grahamтs comment here) I agree completely with Josh. In a casual conversation with Tim Cochran of Thoughtworks, we both felt that using RESTful controllers does not mean exposing all of your model objects, or database tables. Thoughts still need to go into designing the right interfaces.
In Rails, examples of RESTful controllers are usually CRUD controllers of ActiveRecord objects. (and the ActiveRecord objects are just straight mapping to database columns). My given example in the previous post is exactly like that, and thatтs because script/generate and scaffolding just make it so easy.
However, thatтs not an excuse not to think about what to expose, and what to hide. In our current project we have a rails app (say an HR app) that needs to obtain/update the Account information on another rails app (say an sales app). On the sales app side, letтs say Account is an ActiveRecord that has the following fields:
id: integer
number: integer
name:string
description: string
balance:integer
sales_person_number: integer
and there is already an AccountsController, with associated HTML forms, for CRUD-ing all the fields on an Account.
On the HR app, we are interested only in the sales_person_number of the account. So we instead implemented a brand new SalesPersonAssignmentsController on the sales app, to assign a sales person, so that
POST http://sales.app/sales_person_assignments params => {:sales_person_number => 666} # Give sales_person an account to look after
returns an empty HTTP response, with status code 201 CREATED, and the тLocationт header : "/sales_person_assignments/123"
# The sales app had given account #123 for the salesperson to look after
We havenтt implemented any security measures yet, to prevent the HR app to hit other actions on the sales appтs AccountsController. But at least the intention is that the HR app will only hit the SalesPersonAssignmentsController only, and nothing else, on the sales app. That hopefully limits the integration points, and make the change on one app have less impact on another app.
Conclusion: I think encapsulation, loosely-coupled systems, are good ideas. They donтt call me Captain Obvious for nothing :)
From Planet TW, 8 months ago,
0 comments
From Planet TW, 8 months ago,
0 comments
From Planet TW, 8 months ago,
0 comments
From Planet TW, 8 months ago,
0 comments
Via Rosie, Max, 19 is the funniest thing I've read in ages.
Of course, he's nineteen, so of course he's a tosser. Had this been up on facebook, it would blend in perfectly. It's just on the Grauniad travel front that he's going to attract such opprobrium.
From Planet TW, 8 months ago,
0 comments
Post := IoRecord {Actually, this looks almost readable, right? It's all valid Io code. The question is, how do we get it to do what we want? Without further ado, here's an implementation that gives us enough:
has many authors
belongs to blog
belongs to isp
}
Author := IoRecord {
has many blogs
has many posts
has one name
}
IoRecord := Object clone do(Since I'm a bad person and really enjoys metaprogramming, I had to get rid of most of the duplication the first implementation contained. Let's say it like this: the first version didn't have the collector and appender methods. And boy do they make a difference. This is real metaprogramming. Actually, these two methods are actually macros, almost as powerful as Common Lisps. Notice that the words we send in to collector doesn't actually get evaluated. This is one of the reasons we don't need to use symbols - we can just take the unevaluated messages and take their name. In the appender macro we're doing something really funky where we use setNext.
init := method(
self belongings := list
self hasOnes := list
self hasManies := list
self hasFews := list
)
appender := method(msg,
blk := block(
call sender doMessage(msg) append(call message next name)
call message setNext(call message next next)
)
blk setIsActivatable(true)
)
collector := method(
meths := call argCount / 2
waiter := Object clone
for(index, 0, meths-1,
waiter setSlot(call argAt(index*2) name,
appender(call argAt(index*2+1)))
)
waiter
)
belongs := collector(
to, belongings
)
has := collector(
many, hasManies,
one, hasOnes
)
curlyBrackets := method(
current := self clone
call message setName("do")
current doMessage(call message)
)
)
From Planet TW, 8 months ago,
0 comments
From Planet TW, 8 months ago,
0 comments
Selenium is a great tool for web acceptance testing, but working on tests can be laborious. In addition to the general slowness of actually testing through the browser, starting a SeleniumDriver takes about 6 seconds on my MacBook.
require "rubygems"
gem "Selenium"
require "selenium"
benchmark = Benchmark.measure do
driver = Selenium::SeleniumDriver.new(
"localhost", 4444,
"*firefox", "http://localhost:3000"
)
driver.start
driver.stop
end
benchmark.to_s
#=> " 0.000000 0.000000 0.000000 ( 6.294741)"
If the selenium driver could stay open between test runs, running a test could be much faster. Fortunately, DRb makes this easy. Here are the rough steps.
First, start a SeleniumDriver and place it in a DRb service.
require "rubygems"
gem "Selenium"
require "selenium"
require "drb"
SERVER = "druby://:51785"
driver = Selenium::SeleniumDriver.new(
"localhost", 4444,
"*firefox", "http://localhost:3000"
)
driver.start
DRb.start_service SERVER, driver
puts "Ready"
DRb.thread.join
The DRb.thread.join call at the end of this script means the script won't exit. Run it from a terminal, use Ctrl+C to stop it.
The next step is to use this instance when running tests. DRb provides a class that functions as a proxy to the object running in the server. In this case, that's the selenium driver.
DRb.start_service
driver = DRbObject.new(nil, SERVER)
class << driver
# make sure type hits method_missing to delegate to driver
undef_method :type
end
Using the DRbObject as a proxy to the SeleniumDriver requires hacking the type method to make sure it delegates properly.
Here's the benchmark for this version:
benchmark = Benchmark.measure do
DRb.start_service
driver = DRbObject.new(nil, SERVER)
class << driver
# make sure type hits method_missing to delegate to driver
undef_method :type
end
end
benchmark.to_s
#=> 0.000000 0.000000 0.000000 ( 0.070634)
The time to start the driver is now negligible.
I've been using this for a few days, and it is working well. If you actually want to try this, here are a couple tweaks to the code that you'll want to make.
To stop the SeleniumDriver when stopping the process, wrap DRb.thread.join like this:
begin
DRb.thread.join
rescue Interrupt
begin
puts "Stopping..."
driver.stop
rescue Exception
puts "failed stopping selenium driver"
end
end
DRbObject does not check the connection when it's first initialized. You may want to force it to check the connection by doing something like this:
begin
DRb.start_service
driver = DRbObject.new(nil, SERVER)
driver.respond_to?(:anything?)
rescue DRb::DRbConnError
# do something
# fail over to non-DRb driver?
end
A call to respond_to? will check to see if the DRb server is available. You may want print out an informative message or fail over to using a non-DRb driver if it cannot connect.
From Planet TW, 8 months ago,
0 comments
From Planet TW, 8 months ago,
0 comments

From Planet TW, 8 months ago,
0 comments
About Mary Poppendieck:: Mary is a former programmer and IT manager turned Lean Software Development Evangelist, Author and Trainer. Mary, with her husband Tom, is the author of the award winning books Lean Software Development: An Agile Toolkit and Implementing Lean Software Development: From Concept to Cash.
Q. What does the term Lean software development mean to you?
Lean software development is applying lean principles to software development.
Q. What level of improvement have you seen from teams transitioning from traditional waterfall software development models to Lean software development models?
I never even heard of the word waterfall until 1998 when I retired from my job at 3M and got involved in my first government software project â which was âwaterfall and proud of itâ. It was also pretty much of a disaster. So itâs hard for me to think of âwaterfallâ as traditional. And in fact, I havenât seen many waterfall models in action â except for that one I ran into in 1998. So Iâm not quite sure how to answer your question. I can say that when organizations start using a disciplined test-driven development process combined with short iterations, they often report 30-50% defect reduction and dramatic productivity improvements. But productivity is tricky to measure â so I wonât put a number on that.
Q. To date within the IT community we have applied Lean to the software development process to gain efficiencies. Do you feel that there is an opportunity to use this knowledge to work with our business partners to apply Lean principles to improve the processes that our applications automate?
I find it often works the other way around. People with lean operational processes need software to support the process and urge the software development group to become lean so as to provide them with better support. In fact, I did a workshop at a bank which processed mortgage papers. The paper handling process was vastly improved through lean techniques, but the teams were unable to get software changes they needed â even though their process was driven by workflow software. In another case, an insurance company, the IT department was unable to support business teams. At both companies, I suggested that a couple of developers simply be assigned to each lean team to make the software changes the team needed in a Just-in-Time manner.
Q. Hand-offs are viewed as being wasteful. There is often a hand-off from business to IT but there is also a common hand-off from IT to operations and support. Do you have any suggestions on how this second hand-off can be handled?
Both handoffs are equally harmful. The very words âbusinessâ and âITâ indicate that people think (moreâŚ)
From Planet TW, 8 months ago,
0 comments
My goal as a developer is to deliver a system that behaves in a particular way. Whether or not it has tests is an interesting metric, but not the core purpose. âTest-drivenâ development will cause me to have lots of tests, but it wonât necessarily get me nearer the goal of delivering business value through software. So you can use goal-oriented vocabulary in your development process as well as your code to help maintain perspective on what you are trying to achieve.
From Planet TW, 8 months ago,
0 comments
From Planet TW, 8 months ago,
0 comments
From Planet TW, 8 months ago,
0 comments