Showing posts with label dynamic. Show all posts
Showing posts with label dynamic. Show all posts

Sunday, June 05, 2011

Tips from Rails Anti-Patterns

Another good Ruby book is out, Rails Anti-Patterns. The book is loaded with good tips on everything from following the Law of Demeter to cleaning up your views with the use of helper methods.

Here are some things I picked up from the book.

delegate can take a :prefix argument

The delegate method from active_support is used for delegating calls to another object without having to write out the full delegating methods. It can take a prefix option to customize the name of the delegating methods.

class Address
  @attr_accessors :street, :zip
end

class Person
  attr_reader :address
  # prefix => true, results in the model name being used as prefix
  delegate :street, :zip, :to => :address, :prefix => true
  #@person.address_street, @person.address_zip
end

class Person
  attr_reader :billing_address, :delivery_address
  # prefix => string, uses the string as prefix
  delegate :street, :zip, :to => :address, :prefix => delivery
  #@person.delivery_street, @person.delivery_zip
  delegate :street, :zip, :to => :address, :prefix => billing
  #@person.billing_street, @person.billing_zip
end

Transaction Scope

The code executed in the ActiveRecord callbacks execute in the same transaction as the actual call to save, create, update, or delete. Knowing this helps to eliminate unneccessary explicit transactions.

# Using a before filter
class Drink
  before_create :remove_ingredients_from_bar

  def remove_ingredients
    ingredients.each do |ingredient|
      Bar.remove(ingredient)
    end
  end
end

# Is better than using an explicit transaction
class Drink
  def create_drink
    transaction do
      remove_ingredients
      create
    end
  end

  def remove_ingredients
    ingredients.each do |ingredient|
      Bar.remove(ingredient)
    end
  end
end

Association Methods

It is possible to add methods directly on the activerecord associations. This is especially handy if the method uses information from both sides of the relation.

class Drink
  #has_field :minimum_drinking_age
end

class Customer
  #has_field :age

  has_many :drinks do
    def allowed
      # proxy_owner is the object defining the relation, Customer
      where(['minimum_drinking_age < ?', proxy_owner.age])
    end
  end
end

When to make a model active

If there is no user interface for adding, removing, or managing data, there is no need for an active model. A denormalized column populated by a hash or array of possible values is fine.

This is really just the application of the KISS principle, Keep It Simple Stupid, but I have never seen it as clearly described before reading this book.

Haml []

A nice feature of Haml that I didn’t know about, is the [] operator. When given an object, such as [record], [] acts as a combination of div_for and content_for, outputting a tag with the id and class attributes set appropriately.

-# This Haml
%span[@team]
<!-- Results in this HTML -->
<span class='team' id='team_1'></span>

RESTful actions

When using resources in Rails there are seven methods that are used.

index, create, show, update, delete, edit, and new. The first five naturally map to get(collection), post(collection), get(singular), put(singular), and delete(singular), but what isn’t as obvious is that.

The new and edit actions are really just different ways of representing the show action.

This is of course obvious when you think about it, but once again Chad and Tammer has written it down in plain simple English.

Rake Tasks

How should you treat your application specific Rake tasks on order to test them easily. Once again the solution is very simple.

Write the domain specific code as a class method on the appropriate model associated with the task.

Then all you have to do is call the method from the task.

task :fill_bar_with_ingredients do
  Bar.fill_with_ingredients
end

It is not always appropriate to add this functionality to the existing models. This is a clue that another model is needed in your domain.

task :fill_bar_with_ingredients do
  LiquorStore.order_ingredients
end

Database Index

Since most applications have far more reads than writes, you should add indexes to every field that appears in a WHERE clause or an ORDER clause. You should also add indexes for every combination of fields that are used that are combined with AND.

As always, don’t follow this advice blindely, if a table only has three rows then perhaps the index is overkill…

Conclusion

Apart from these tips, there are tons of other useful information, making this book a must-read if you are doing Rails development.

Sunday, January 09, 2011

Dynamic For The Win

Everything passes, everything. -- Anthony de Mello, Awareness

Take a look at what is happening around you. Relational databases are replaced by NoSQL databases. SOAP is replaced by REST, Javascript is dominating web development. The only place where dynamic is not winning is in the world of programming languages. But even if you take a look at programming languages, you can see that many of the largest most vital sites, such as Facebook and Wikipedia, are using dynamic languages. Why?

Dynamic is Better

It's not the strongest of the species that survives, nor the most intelligent, but those who are most responsive to change. -- Charles Darwin

What I mean when I say that dynamic is better is that dynamic systems are more responsive to change. And change, as they say, is the only thing that we can be sure of!

  • If I need to add a new field to a NoSQL database, I just do it.
  • If I need to add new field to my RESTful web service, I just do it.
  • If I need to alter the behavior of my Javascript UI, I change it, reload the page, done!

Soap vs. REST

REST is beating the hell out of SOAP nowadays, but you may have noticed that most "RESTful" web services aren't really RESTful. They don't follow the HATEOAS rule, they are just "Accessible over HTTP". So why the big fuss about "REST" if no one is using it as intended? Because there are no contracts for REST! You are not constrained by WSDL and all the other bloated specifications. You can just publish your services without contracts, write some documentation and be done with it.

Relational vs. NoSQL Databases

NoSQL is the new rave, and most people think that it is because they allow us to handle large amounts of data, fast. I don't think that is the main reason. I think the main reason is that they are schemaless. It is easy to add or remove fields without changing the data of all the other items of similar type. The problem with relational databases is not, in most cases, that they are slow, it is that they have a rigid contract that make them painful to work with. This effect is also, often, amplified by having O/R-mappers wrap the tables in static types.

Javascript vs. RIA Plugins

Javascript is the clear winner as the programming language of the web. Silverlight finally threw in the towel and Java is only living in ancient bank applets. Javascript is one of the most dynamic languages that you can imagine and it has won the battle of the web! Cool!

Programming Languages

In the area of programming languages, both client (not web) and server, dynamic is not winning, yet. Even though languages like C# and Objective-C are becoming more and more dynamic, they are still nowhere near Ruby and Python. Java has stagnated and Scala is even more typeful than Java, although type inference relieves you from having to declare most of the types. Clojure is an interesting dynamic JVM language but it suffers since you still have to compile the code.

But dynamic will win when it comes to programming languages too. Why? For the same reasons that dynamic is winning everywhere else. They are more suited for solving ever changing problems. The problems I try to solve everyday, always has to do with integrating with something else, and it is much easier to do with dynamic programming languages.

So why is dynamic not winning in the area of client and server programming? I think there are a few reasons.

  • Education, most of us have been taught programming at a university that propagates for statically typed, compiled languages. We have been taught that dynamic languages are bad and that they may be suitable for scripting but nothing else. It has been hammered into us, so hard that we have a hard time letting go of this.

  • Tradition, the folklore says that dynamic programming languages are too slow. The fact that they are not, has not changed this. You may remember that the argument was the same against Java fifteen years ago.

  • And then there is the main reason, dynamic is harder!

Dynamic is Harder

So why isn't everyone using dynamic programming langugages? Because, it is harder. It is easier to write really bad code in dynamic languages. But, on the other hand, it is also easier to write really good code in dynamic languages.

It is harder to develop large systems, because when you are using convention over configuration, it is really important to know the conventions and most people don't take the time to learn what they use properly, they rely on the IDE for guiding them down the right path. If you are suffering from IDEitis, the transition to dynamic languages is going to be tough until you realize that the help you get from the IDE is also what is holding you back.

The problem is moved from the programming language to me, the programmer, architect or whatever title I feel entitled to. If I am using a dynamic language and I screw up, it is my fault. If I don't organize the code in a way that can be understood by others, it is my fault. If I make changes to core classes, and the system stops working, it is my fault. I am responsible! I am in control!

An example, third party libraries in Ruby

I remember a comment from one of my colleagues, when he found out that I had a problem with a library (a Ruby Gem) that didn't behave the way I wanted it too.

Ah, you're using Ruby, then you can just fix it. -- Mattias Arthursson

Right on Mattias, I can just fix it!

Almost every Ruby Gem lives at Github. The flexibility this brings is tremendous. If a library is not working the way I think it should, I can just fix it. The process goes something like this:

  • Fork it
  • Make the appropriate changes
  • Push it back up to Github (to my fork)
  • Change the Gemfile, that holds my project dependencies, to use my fork instead.
  • Optionally, I may also send a pull requests of my patch to the maintainer of the library.
  • The maintainer takes a look at it and pulls it in, relieving me of the burden of keeping my fork up to date.

The process is so simple, it is almost seamless.

I'll finish with another quote.

It is vain to do with more, what can be done with less. -- William of Occam

It's a new year, it is time to prepare for the future, a dynamic future! Here are some books that I can recommend, they are about Ruby and Javascript, since they are my current favorites. But if you like other dynamic languages better, knock yourself out!

Books

The books are ordered, by increasing level of complexity.

Ruby

Rails

Javascript

jQuery