UPDATE: If I did this again, I would consider packaging the code as a Concern
I recently wanted to DRY up some repetitive Rails association code, similar associations used in multiple models. This gave me the opportunity to figure out a few tricks, like creating a module Class method and using metaprogramming to add dynamically named accessors.
Anyway, here is the Module:
...and the client model...
codecraft blog
by john troxel. code, software architecture, and rapid development
Wednesday, October 31, 2012
Using a module to share common association logic in Rails
Labels:
Metaprogramming,
Modules,
Rails,
Ruby
| Reactions: |
Tuesday, August 28, 2012
Building procedures with composition
Often developers need to model a multi-step process. Also common is the need to reuse pieces of the process: maybe the steps are the same but the execution of the steps vary for different contexts, or maybe the step flow changes slightly in some cases but the logic of the steps is largely reused.
One common way developers address this situation is to implement a Template Method pattern. For example, an insurance system might have several similar flows for processing feeds from different sources--partner EDI, consumer web site, provider applications--where many of the steps involved are largely reusable.
A Template Method basically uses inheritance to share common logic, while varying the implementation of steps by overriding methods representing particular steps. However as the GOF posited and leading developers believe today, one should "favor composition over inheritance." Inheritance abuse is a common and natural side effect of trying too hard to reuse logic the OO-way, but we can do better.
The essential problem with using inheritance with the Template Method is that the class tree can get pretty ugly if one needs to vary the implementation of steps AND the flow of steps. Also, more often than not, the is-a relationship between common and specialized processors is restrictive and faulty. For example if a processor implementation wanted to extend something else like ActiveRecord.
What if, rather than using a template method, one could compose flows of steps, where the steps are pluggable members? Another way to build processes that can be reused and extended is with the Strategy pattern, where the algorithm (or steps thereof) are pluggable. Using this approach, the developer creates the structure of the flow in one class but delegates the execution of steps to collaborators.
Now what if there was a fluent interface for building flows of plugable steps, as well as machinery and conventions for coordinating between steps? Well, that is the idea of Flo: https://github.com/jtroxel/flo
Some of the ideas from Spring Batch and Apache Camel have also inspired my thinking here, but Flo is much simpler and less specialized. I was also motivated by the Unix programming model, little tools that do one thing well, strung together with pipes.
Note that Flo is a work in progress, awaiting her first real application.
| Reactions: |
Monday, June 18, 2012
Controlling Rails mass-assignment with whitelists and :as
Rails 3.2 has some flexible features for controlling mass-assignment. A little Gist I put together demonstrates:
whitelisting and roles: https://gist.github.com/2948700
whitelisting and roles: https://gist.github.com/2948700
Labels:
Ruby Rails Mass-Assignment
| Reactions: |
Tuesday, June 12, 2012
Objects in Practice - Testing Objects
Test Doubles in Ruby and Groovy: https://github.com/jtroxel/Objects-In-Practice/blob/master/test-objects/readme.md
Labels:
Ruby Groovy Java Tests TDD
| Reactions: |
Tuesday, November 29, 2011
Search as Data Store
A while back I came across Solandra, and began wondering about using it as a general purpose store for a typical content-heavy webapp. The idea was based on a pretty vague notion that combining search with NoSQL would be powerful. What Solandra does is bolts the SOLR search engine onto Cassandra instances, resulting in a distributed search with all the data persisted in a NoSQL store.
In poking around, I've found that it is not unheard of to use SOLR as a web backend. Perhaps the most prominent example would be The Guardian's use of SOLR for their "Content API." There was also supposedly a twitter-like example that "uses the Lucandra store exclusively and does not use any sort of relational or other type of database", though the link did not work as I wrote this (Lucandra is the predecessor to Solandra).
Why not just stuff everything into SOLR? It is effectively a document store with powerful and fast queries. Sure it does not support transactions and the data is not normalized in a relational sense. But do you need those things for content? What I mean by content is dynamic stuff that might be edited by humans or updated by feeds: articles, comments, tags, product descriptions, locations; data that is viewed a lot but edited infrequently, not super structured or requiring crazy integrity. With the Cassandra backing, you should at least get durability and eventual consistency on the data that you shove into SOLR (Solandra).
I guess now I will have to give it a try, see where the trade-offs are in practice between search, NoSQL, and Relational stores on a real content project. Who's got one for me? :)
In poking around, I've found that it is not unheard of to use SOLR as a web backend. Perhaps the most prominent example would be The Guardian's use of SOLR for their "Content API." There was also supposedly a twitter-like example that "uses the Lucandra store exclusively and does not use any sort of relational or other type of database", though the link did not work as I wrote this (Lucandra is the predecessor to Solandra).
Why not just stuff everything into SOLR? It is effectively a document store with powerful and fast queries. Sure it does not support transactions and the data is not normalized in a relational sense. But do you need those things for content? What I mean by content is dynamic stuff that might be edited by humans or updated by feeds: articles, comments, tags, product descriptions, locations; data that is viewed a lot but edited infrequently, not super structured or requiring crazy integrity. With the Cassandra backing, you should at least get durability and eventual consistency on the data that you shove into SOLR (Solandra).
I guess now I will have to give it a try, see where the trade-offs are in practice between search, NoSQL, and Relational stores on a real content project. Who's got one for me? :)
Labels:
solr solandra search NoSQL Java
| Reactions: |
Tuesday, November 15, 2011
Objects in practice: class basics in Java and Ruby
This post looks at basic class and inheritance mechanisms in both Java and Ruby. I might to decide to expand this into a series, illustrating basic programming building blocks using Java, Ruby, and Scala; we'll see how it goes.
For this post, we are modeling employees of a software company, something like:
(via YUML:
edit)
NOTE: This is NOT a good design--doesn't allow employees to fulfill multiple roles, doesn't account for changes over time--but I'll show better designs in later Howtos.
So, the general idea is that we want to reuse some behavior and also provide some specialized behavior. Probably the most simplistic way to do this in OO languages is to set up concrete inheritance and leverage polymorphism. I'll show how this is done in Java and Ruby, and the complete code can be found at github
JAVA
A simple parent class, provides startDate member and monthsOnJob to subclasses:
Ruby
Now the parent class in Ruby
For this post, we are modeling employees of a software company, something like:
(via YUML:
edit)
NOTE: This is NOT a good design--doesn't allow employees to fulfill multiple roles, doesn't account for changes over time--but I'll show better designs in later Howtos.
So, the general idea is that we want to reuse some behavior and also provide some specialized behavior. Probably the most simplistic way to do this in OO languages is to set up concrete inheritance and leverage polymorphism. I'll show how this is done in Java and Ruby, and the complete code can be found at github
JAVA
A simple parent class, provides startDate member and monthsOnJob to subclasses:
public class Employee {
private Date startDate;
public Integer monthsOnJob() {
Integer months = 0;
// Do the math
return months;
}
public String jobDescription() {
return "New employee"; // Default description, will be overriden by subclasses
}
}
A simple subclass, adding behavior to the super and overriding the description
public class Developer extends Employee {
@Override
public String jobDescription() {
return "Developer: " + listTechnicalSkills();
}
private String listTechnicalSkills() {
String skillStr = "";
// TODO get skills from getTechnicalSkills and build string
return skillStr;
}
private Collection technicalSkills;
public Collection getTechnicalSkills() {
return technicalSkills;
}
public void setTechnicalSkills(Collection technicalSkills) {
this.technicalSkills = technicalSkills;
}
}
Another specialization, Manager has Employees as reports
public class Manager extends Employee {
Collection reports;
@Override
public String jobDescription() {
return "Suit";
}
public Collection<Employee> getReports() {
return reports;
}
}
Ruby
Now the parent class in Ruby
class Employee
attr_accessor :start_date # method that creates accessors
def initialize(start)
@start_date = start
end
def months_on_job
# Math is easy
(Date.today.year*12 + Date.today.month) - (@start_date.year*12 + @start_date.month)
end
def job_description
"New employee"
end
end
A Ruby Developer class
class Developer < Employee
attr_accessor :technical_skills
def initialize(start)
super(start)
@technical_skills = []
end
def job_description
ret = "Developer: "
@technical_skills.each {|skill| ret << " ${skill"}
end
end
The Manager
class Manager < Employee
attr_accessor :reports # accessor
def initialize(start)
super(start)
@reports = []
end
def job_description
"Suit"
end
end
| Reactions: |
Monday, October 24, 2011
John's Independent Forray v3.0
After 3.5 years with Rearden, I decided to go back to freelancing, for the 3rd time.
This time around I am going by codecraft solutions. I am presently subing with Marty Haught and intend to continue for some time. Eventually though I intend to run my own projects too.
That's the plan, stay tuned.
This time around I am going by codecraft solutions. I am presently subing with Marty Haught and intend to continue for some time. Eventually though I intend to run my own projects too.
That's the plan, stay tuned.
| Reactions: |
Subscribe to:
Posts (Atom)