Posted by Mathew Abonyi
Wed, 10 Oct 2007 02:51:00 GMT
I’m just briefly breaking my silence (which must continue a bit longer) to raise awareness about an impressive and very useful gem which has just come onto the scene: Aquarium.
Although I don’t follow Aspect Oriented Programming very closely, I know about its benefits and use it when necessary. All Rails developers, for example, employ its principles without even knowing it: before, after and around filters, proxies to alter execution, callbacks and the like. If you don’t know about AOP yet, basically it’s the practice of separating components which appear across the various classes of an application to provide system or class-agnostic functionality—for example, logging, authentication or object persistence.
Having these components intrude on, for example, calculating a bank balance really gets annoying after a while. Imagine every moderately sized script you write needing lots of diagnostic messages, custom event handlers, and the like. It gets very tedious because you know there’s the ideal of reuse just around the corner.
Clean, Ruby-esque AOP… a Pipe Dream?
Imagine methods without calls to a logger, without a litter of ‘if/then/else’ for authentication or authorisation, without calls to save an object and checking if it returns true or false… What you’ll get is the raw functionality of your class or module, which… umm, is as it should be. Wrapping a method (using cuts, wrapping or aspects from AOP) lets you extract common functionality which cuts across objects.
Until now, there’s only been the Facets libraries for AOP (‘advice’, ‘aop’ and ‘cut’ in Facets 2.0.0) and AspectR. The former is buggy at best and the latter is like returning to Java. So I wasn’t very keen on AOP in Ruby at all. Metaprogramming seemed easy enough and didn’t need the structure of AOP to follow.
Enter Aquarium. It’s a glass of clean water in a desert. Ruby-style. The most important thing it offers is a ‘Join Point Model’ which will make you wet. In other words, it is very easy to intercept method calls to wrap them and introduce functionality before or after the original definition.
Sadly, I don’t have the time for an extensive example from my own coding, so I’ll have to rip off the example from Aquarium’s own README which I think illustrates its power best (with a few modifications to show how I use it at the moment): method tracing.
Example: Method Tracing
require 'rubygems'
require 'aquarium'
require 'aquarium/aspects/dsl/object_dsl'
module Example
class Foo
def initialize *args
p "Inside: Foo#initialize: args = #{args.inspect}"
end
def do_it *args
p "Inside: Foo#do_it: args = #{args.inspect}"
end
end
module BarModule
def initialize *args
p "Inside: BarModule#initialize: args = #{args.inspect}"
end
def do_something_else *args
p "Inside: BarModule#do_something_else: args = #{args.inspect}"
end
end
class Bar
include BarModule
end
end
p "Before advising the methods:"
foo1 = Example::Foo.new :a1, :a2
foo1.do_it :b1, :b2
bar1 = Example::Bar.new :a3, :a4
bar1.do_something_else :b3, :b4
module Example
include Aquarium::Aspects::DSL::AspectDSL
around :types => [Foo, Bar], :methods => :all,
:method_options => :suppress_ancestor_methods do |jp, *args|
begin
p "Ex. 1: Entering: #{jp.target_type.name}##{jp.method_name}: args = #{args.inspect}"
jp.proceed
ensure
p "Ex. 1: Leaving: #{jp.target_type.name}##{jp.method_name}: args = #{args.inspect}"
end
end
end
module Example
class Bar
after :do_something_else do |jp, *args|
p "Ex. 2: Simply after: #{jp.target_type.name}##{jp.method_name}: args = #{args.inspect}"
end
end
end
include Aquarium::Aspects
Aspect.new :before, :method => :do_it, :type => Example::Foo do |jp, *args|
p "Ex. 3: Simply before (using Aspect.new): #{jp.target_type.name}##{jp.method_name}: args = #{args.inspect}"
end
module Example
module AllAspects
include Aquarium::Aspects::DSL::AspectDSL
before :do_it, :type => Example::Foo do |jp, *args|
p "Ex. 4: Simply before (using namespaces): #{jp.target_type.name}##{jp.method_name}: args = #{args.inspect}"
end
end
end
puts
p "After advising the methods. Notice that #intialize isn't advised:"
foo2 = Example::Foo.new :a5, :a6
foo2.do_it :b5, :b6
bar1 = Example::Bar.new :a7, :a8
bar1.do_something_else :b7, :b8
You could argue that the namespace for Aquarium needs a little work and the availability of Aspect.new system wide should be a given, but adding that oneself until Aquarium has it is no big deal. I also didn’t demonstrate pointcuts, another option to around, before and after. With a pointcut, you can encapsulate the type, scope and method names—perhaps as a constant, class variable or class method to reduce dependencies.
Overview
All in all, the DSL is already miles better than anything else out there and Aquarium was only released to the public months ago. To summarise, I think this DSL is killer because it is…
- clear about what is affected
- easy to separate from what is affected
- rich with selectors (type, scope, name, pointcut)
- able to choose whether to alter method execution
So, I would definitely suggest giving it a go and seeing how it can modularise some of your ‘cross cutting concerns’. I also suggest the Aquarium README and the reading recommended on its site, http://aquarium.rubyforge.org/.
Posted in Discoveries, Ruby | Tags aop, aquarium, aspects, discoveries, metaprogramming, ruby | 2 comments | no trackbacks
Posted by Mathew Abonyi
Sat, 28 Jul 2007 02:18:35 GMT
I don’t hear a lot about project management, even though there’s a lot about how to manage a project. Testing, deployment and source code management get the most attention, and project management seems to get the least. Maybe that’s because it hasn’t been done properly yet and all the solutions out there only address pieces of the overall problem.
So I’m going to try to clarify, for myself mostly, the kind of project management that is needed and why it is so important in development.
Getting It Right
When I say management, I mean a combination of something like Lighthouse and Basecamp, with a serious overhaul of perpsective. An integral part of good development is developing ideas hand-in-hand with the code. Management is all about keeping this communication as agile as the coding process, sticking to priorities, and addressing the right things at the right time.
Is Basecamp sufficient for managing a project? No. DHH even says it is not meant for managing Rails projects; it’s for marketers and managers. It’s only a piece of the puzzle, because it provides no way to easily track code.
Is Trac sufficient for managing a project? No. It is too much like a big todo list and a bug tracker combined. It is very developer-centric—even when the developer is also the designer and manager, there’s no way to make known the other roles. Trac too is only a piece, because it provides no way to easily communicate ideas. A wiki doesn’t cut it.
Are help desks sufficient? No. They are too customer/support-centric. They have no way to easily communicate the ideas of developers and designers.
What about Lighthouse or Unfuddle? For a hosted solution, Lighthouse and Unfuddle combine Trac and Basecamp. That’s going in a decent direction. Anything which integrates different parts of the development process is addressing the need for management. But it’s not enough, because it has no integration with the customer.
What about [insert megolithic answer to everything]? No. It’s too complicated, has too many options and forms, too much information on each page. Something as complicated as Google Analytics, for example, is pushing the boundary of what is acceptable. Complicated applications get in the way of communication and understanding, even if they integrate everything. Simplicity first.
What all of these solutions lack is a focus on the different kinds of users for a project, ways of easily communicating their needs and ways of addressing those needs. Even when the developer, designer, marketer and manager are rolled into the same person, it is important to separate the roles, make them clear and integrate each one’s concerns at the right points.
It’s all about the development process.
The Development Process
I see that there are 9 stages in the development process:
- Management: find out the next need to address
- Specification/Testing: specify how the need is addressed
- Coding: code until the specification passes
- Continuous Integration: combine the efforts of multiple coders
- Refactoring: clean up the code
- Graphic Design (if needed): make the new feature appealing
- Deployment: release the latest revision
- Marketing: advertise the latest feature
- Customer Feedback: find out what is going well and what isn’t
If you see this process as organic, the importance of management becomes much clearer. In fact, I think management is the most important stage, more important than the code itself, for a number of reasons:
- Management is the first step; without management, testing/coding is arbitrary
- Management brings everyone into the development process
- Management gives everyone an overview so they can see the wood for the trees
- Management encourages communication between everyone
- Management naturally focuses on the most important aspects
- Management reinforces and rewards good development
- Management operates organically, reflecting needs and their importance
- Management begins the specification/coding cycle
- Management draws from and feeds into all other stages of development
Disconnecting from these aspects of development is a serious mistake because it denies the organic element of development. Everything needs to converge at some point and management is the most natural way of acknowledging and converging all of a project’s members, roles, ideas, problems and concerns.
Poor management will try to force the development process into a linear pattern. It will approach things as ‘things to do’, ‘features to have’, ‘milestones to reach’, ‘deadlines to meet’, ‘code to test’. Everything will have its place, need to be addressed by a particular person… in short, it’ll look like a Trac installation. The code will feel strained, regimented and will generally be a rather boring thing to deal with. The developer is being strait-jacketed.
On the other hand, a lack of management will result in the process becoming chaotic. The developer will code whatever takes his fancy. Occasionally e-mails or posts containing feedback will find their way into the code, but mostly the code will diverge from the customer’s interests. The organic element has gone mad in this case because the developer is too isolated.
But good management acknowledges the organic aspect of development and lets the code flow. It translates ideas into specifications just as test-first translates specifications into code. Good project management will create and maintain strong channels of communication between developer, designer, marketer, manager and customer. The real needs for the project will appear of their own accord as different ideas converge in one place.
But that sounds much easier than it actually is. There isn’t yet an application out there which integrates all of those roles together, but some are closer than others. I think Retrospectiva could be the one which gets there first.
What is needed for good management
The three major aspects of project management are development, collaboration and integration. There needs to be a way to develop, track that development, and focus it. There needs to be collaboration and communication surrounding that development. There needs to be a process of integration between management and the other stages of development.
Ideally, a project management system will have the following aspects:
- Stories: isolated stories to be resolved (bug, feature, question, idea)
- Dynamic properties: status, milestone, persona, feature, assigned user, assigned group
- Reinforcement: aspects of the application NOT to change (positive feedback, robust code)
- Personae: ability to define personae, like power users, buyers, sellers, novices, etc.
- Milestones: rough organisation of stories and deadlines
- Messages: site-wide (like Basecamp) and for each milestone
- Roles: developer, guest, manager, designer, customer, marketer, administrator
- Groups: optional story development by groups
- Interfaces: different interfaces for each role and/or group
- Cross-referencing: referencing between stories, messages, milestones, source
- Testing integration: update stories with progress on tests (e.g. Tesly)
- Coverage Integration: stories for area of test coverage, whether 100% covered or not
- SCM integration: update stories through commit logs
- Continuous Build Integration: create stories for failed builds
- Error Notification Integration: create stories for application errors
- Customer Integration: create stories for customer feedback (positive & negative)
Most importantly, the interface(s) needs to be extremely clean. Lighthouse goes a long way in making a highly readable, even pleasurable interface. Most of the aspects I list above can exist on their own, meaning the application itself will have many facets, but each very easily understood. Cross-referencing is probably the most important of them all, since it will bring together the various aspects.
The shift in perspective I suggest for project management is to not focus on managing people (like Basecamp) or code (like Trac) or users, but ideas. Those ideas will never disappear from view, unlike tickets on Trac or todo lists on Basecamp. As stories grow and connect with new stories (like associating tickets), everyone will see the evolution and development of features, in which way the project is going, and be able to react better to the movement of the project. In a way, project management also begins to document the project, but more importantly, it shows in black and white how ideas become code and how they evolve. At the centre of the project should be a cloud of ideas which each role can see differently.
Just to give a little hypothetical situation: at the beginning of your project you had a simple user authentication system. Over time, users talked about adding Open ID. Management wanted an authorisation system and an admin interface. Designers wanted a cute widget that pops down with AJAX. Developers wanted to extract it into a plugin. All of these ideas would be associated and appear together in a good management system, showing the time each one was added and completed, the role which initially suggested it, and the group or user responsible for implementing it. All the bugs, notes, support questions, requests and feature stories will clump together and naturally point towards what is needed next, if anything.
This form of project management could very well revolutionise the way development is perceived. Or is it a load of bullshit?
Posted in Retrospectiva, Ruby, Rails | 3 comments | no trackbacks