Archive for the ‘Programming’ Category

Ruby Factory Following the Open-Closed Principle

February 17th, 2009 by ScottK | No Comments | Filed in ruby

I had a rather chilling idea recently, how do you create a Ruby factory that follows the Open-Closed Principle. The open closed principle simply states that your code should be open for extension but not modification. More Here. That means unless it’s a true error or needs modification for a new feature, realistically, don’t modify it to support extensions (inheritance).

The processes I want to incorporate where A.) not case statements. Case statements for class resolution are a code smell in and of themselves, plus including new types breaks open/closed principle, B.) to achieve open/closed principle and load dynamically new classes need to be loaded on the fly. The reality was that it was relatively easy to accomplish, and I’m about to show you how.

We’ve all seen the class A inherits B namespace Y, blah blah blah articles. I’m throwing that out. Here’s the deal you go to the pet shop and you are asking the pet store owner for a lion. He has one and gives it to you. So you ask for a tiger, he doesn’t have one immediately so he checks in back; maybe he has one that just came in, or alerts you to the fact he has none.

Do you see the roles here? You are the consumer of the product provided by the pet shop. If the pet shop owner knows they have one in stock then they certainly give one.

If the pet shop owner doesn’t have one in stock then they need to investgate if they have one. /At this point in time if using case statements you need to add case “Tiger” :)/. In affect though that’s like asking the store owner to shut down the shop to research, since you would need to restart the application to take the new changes. That’s also breaking the open/closed principle since you are modifying the program to change a type return and not a feature.

Ok here’s where I ask that you create the PetShop to expand our zoo!

Create a file called pet_shop.rb and place the following:

require './lion'

module PetShop
  def PetShop.factory(arg)
    unless PetShop.const_defined?(arg)
      begin
	require "#{arg.downcase.to_s}.rb"
      rescue
	raise "Giving up since there does not appear to be a class for this module"
      end
    end
  PetShop.class_eval(arg)
  end
end

Now create a lion, which the store owner has in stock. call it lion.rb in the same directory as pet_shop.rb.

module PetShop
  class Lion

  end
end

Let’s take a stop here and evaluate this code.  First, the shop keeper is importing the lion that they know they have. It’d definitely scoped to the PetShop module because as a consumer we need to go there. Certainly you can argue over the “factory” name. I’ve seen it in many forms.

Here’s where it gets good though!

Once you call the module factory method with the type of animal you want to get several checks are performed. The

unless PetShop.const_defined?(arg)

Checks that the store owner already knows about the Lion. since we included it in the first require block then Lion instance is returned to you the consumer. via the:

PetShop.class_eval(arg)

Go ahead try this by firing up irb!

irb(main):001:0> require "pet_shop"
=> true
irb(main):002:0> lion = PetShop.factory("Lion")
=> PetShop::Lion
irb(main):003:0>

Don’t EXIT!!!1

We just proved the factory part and that the shop owner (Factory) knows it can return your specified type. What I still need to show is that you don’t have to modify this code and adhere to the open/close principle, nor do you have to shutdown your application to add new types. Just as you can’t tell the shop owner what type of animals they have and/or have them shut down their business.

So with that and the previous example still running in irb please create this file “tiger.rb” in the same directory as lion.rb and pet_shop.rb.

module PetShop
  class Tiger

  end
end

Clearly this is a brand new file. We didn’t modify the PetShop.factory. Now in the very same terminal that you called the PetShop.factory(’Tiger”) is want you to call:

irb(main):003:0> tiger = PetShop.factory("Tiger")
=> PetShop::Tiger

That specific part works like this:

    unless PetShop.const_defined?(arg)
      begin
         require "#{arg.downcase.to_s}.rb"
      rescue
          raise "Giving up since there does not appear to be a class for this module"
      end
    end

The unless operator makes sure that we have not required the class in the module instance. “Lion” was imported and therefore is true, “Tiger” was not and is therefore false. When the unless sees false it attempts to import the tiger.rb file. Being successful on the import then no exception is thrown and naturally the factory (shop owner) delivers the Tiger.

However calling:

irb(main):004:0> tiger = PetShop.factory("Bunny")
LoadError: no such file to load -- bunny.rb
	from ./pet_shop.rb:7:in `require'
	from ./pet_shop.rb:7:in `factory'
	from (irb):4
	from :0

Because there is no bunny.rb file. Nor was bunny defined in the lion.rb file.

The factory pattern and open/close principle has been around for ages (OOD lifetime), yet I’ve seen so many software applications resort to everything from if/elses to case statements. I know; Refactoring these is such a huge effort that’s it’s so easy to just go along with.

I hope that in this Ruby example that factories really are easily done as well as make your code a whole lot more extensible, as well as a whole lot less refactorable!

Tags: , , , , ,

I’ve updated the PyMigrate test

February 13th, 2009 by ScottK | 7 Comments | Filed in Python

I set up the PyMigrate files on http://code.google.com/p/pymigrate/ without any tests because PyMigrate at that time was a prototype. I’ve created and refactored PyMigrate into a solid form and there the tests are included and these will continue to be maintained.

I haven’t written the tests to the library files yet because Pete’s comment about other libraries, and the sqlalchemy-migrate egg got me thinking. I’m thinking that since SqlAlchemy already supports multiple database types why should I re-invent that using a multitude of plug-ins? Why should I take on the maintenance responsibilities for doing so.

Nay I say. I’m thinking about using SqlAlchecemy exclusively, and it can deal with all the database types and queries. I’ll just create an adapter to work with it from my format.

Thoughts?

Tags:

ObjectMentor as a Reference For Pragmatic Programmers

February 12th, 2009 by ScottK | 1 Comment | Filed in Programming

In searching for something yesterday I stumbled upon the resource page of  ObjectMentor and found it a gold mine of information about software practices and systems. ObjectMentor is a company of industry experts and started in 1991 by Robert C. Martin. As a company they also helped define Extreme programming and helped form the Agile Alliance.

Luckily for us, ObjectMentor offers resources for use to look at the form of articles, books, downloads,etc. One might also assume that resources from them would be highly technical. That assumption would be incorrect.

Case and point, I highly recommend the articles in the craftman series. It’s written in the form of an apprentice programmer writing into their diary the conversions of the day between them and the journeyman programmer they paried with. I find myself learning the concepts the author is trying to instill, using a natural conversation between two people.

I personally re-thought my impression of test first in article The Craftsman #4: A Test of Patience. The article starts with the apprentice writing a very simple program and it conforms to the practices that the journeyman taught in articles #1,2,3. Then the apprentice starts to write the tests for it. The journeyman makes the apprentice delete the whole program. Which of course make the apprentice angry.

The article then proceeds to follow through writing the same program test first, then refactor until completion. The article does include the original program before testing, and includes the code until completion.

At the end of the article it shows, and instills, that testing first produces a leaner more pragmatic code base than writing the tests afterwards.

I would have included links to the mentioned articles but they open in pdf’s, so I chose not to. I highly recommend this site to everyone involved in software engineering.

Tags: , , ,