Archive for June, 2008

Netflix Demonstrates Customer Relationship Mastery

Monday, June 30th, 2008

Everyone makes mistakes. It’s what you learn from them, and how you deal with them, that matters.

Two weeks ago, Netflix decided to discontinue one of their features: Profiles. I was annoyed by this, but not enough to make any noise about it, or even tell Netflix. Truth is, I assumed that the decision was final, and that nothing I could say would matter. Well, Netflix proved me wrong, and has once again demonstrated their dedication to customer satisfaction, by reversing their decision in response to customer feedback.

I just found this message in my inbox:
Netflix Profiles Apology Email Screenshot.png

The tone of the message is perfect, just perfect. I’m very impressed, and I sincerely hope that we at Arc90 can do half as well in our customer interactions – particularly if we’re ever as big as Netflix.

Enabling A Drop Shadow On A Flex Container

Thursday, June 26th, 2008

To set a drop shadow on say a VBox or HBox component you simply set the boolean property dropShadowEnabled to “true” — but this is not enough to make the drop shadow appear. An example:

  1. 

To have the drop shadow appear (with its default shadow color) you need to specify a value for borderStyle since the default is none. Setting the borderStyle property doesn’t necessarily mean you have to display a border, but it is needed for the drop shadow to appear. So if the border is not desired, simply set the style property borderThickness to 0. An example:

   1. 

The above sample will display a drop shadow for the HBox component without a visible border.

In praise of System.Object

Wednesday, June 25th, 2008

In this Quick Tip, I show you how to make a method that deals with System.Object parameters more type-safe by converting it to use generics. Last year I had written a wrapper class to talk to the ASP.NET caching system for me. It returned cached objects as System.Object for maximum flexibility. The client would cast to the desired type, but it always bugged me, because it wasn’t very type-safe. Consider the following chunk of code:

Cache.Set("WhenDidIDoThis", DateTime.Now);
...
int numberOfTicks = (int) Cache.Get("WhenDidIDoThis");

It will compile just fine, but it will blow up when I run it, because silly me, WhenDidIDoThis contains a DateTime, not an integer. It’s far safer to rewrite my code to use generics:

Cache.Set<datetime>("WhenDidIDoThis", DateTime.Now);
...
int numberOfTicks = Cache.Get<int>("WhenDidIDoThis");

Hmm. Actually, that same logic error still compiles just fine, but hey, at least my code now signals its intent more clearly. The bigger problem is now I’m getting a compiler error elsewhere. Let’s see why.

Continue reading»

Introducing Kindling, the first product from Arc90

Tuesday, June 24th, 2008

Ideas are everywhere, but how do I find them?

It’s been often said that the best ideas come from within an organization, as the people closest to the action are best positioned to see untapped value.  However, in practice some businesses seek new ideas, whether they be process changes or the next product line, from the outside – from hired consultants or strategic management firms. 

For those that do seek this out from within, often the problem is actually tapping into this potential wealth of ideas.  If there was only a tool that allowed all members of an organization or community to submit, discuss, refine and vote on ideas?  The net effect of all of this activity would be a well-vetted list of ideas, those that by the nature of being exposed and vetted have the support of the group.

Kindling, a new product by Arc90, is just such a tool.  The product has been within our company for over a year, as well as by a handful of organizations during our private beta, and is available today, as we widen our scope to a public beta.  More on that below, but first, since when is Arc90 a product company?  As cryptic as our web presence might be, it is pretty clear that Arc is a services company, so how did we get here?

Continue reading»

Building RESTful Web Apps with Groovy and Restlet, Part 2: Resources

Friday, June 13th, 2008

In Part 1 of this series, we set up a development environment for our apps, and created and tested a simple “Hello, world” example. In this installment, we’ll make our app more realistic and useful.

If we revisit the current makeup of restfulapp.groovy, we see that there are two elements: the class RequestHandler, and the line which creates and starts an HTTP server. RequestHandler has only one method: handle(), which is called for every request. handle() checks whether the request method is GET, which is the only method supported by the app at this stage, and responds with “Hello, world!” if it is, and with an error response if it isn’t.

It works, but there’s definitely some key elements missing from the picture at this point – namely resources and representations. While our RequestHandler is indeed responding to requests and is therefore doing actual work, it’s not particularly RESTful. There’s no clear resource specified, and no representations of the state of that resource transferred back and forth. So that’s what we’ll add to the app now.

Let’s update RequestHandler so it’s no longer a generic “request handler” class, but instead models a resource. I’m not going to go into REST theory here to discuss what a resource is; if you could use a primer see your favorite REST tutorial or reference, or refer to the relevant section of The Dissertation.

So what resource should our class model? For the purposes of this article, we could choose almost anything. But we’ll want something that’ll allow us to demonstrate some important RESTful concepts, and to build something that resembles real-world resources in transactional software systems.

How about a mailbox? It’s a good candidate because it has state of its own, which would be retrieved with GET, might support both PUT to update its own state, and POST to accept entities for processing, and maybe even DELETE. It also might have “child resources“: messages.

Let’s try changing the name of RequestHandler to MailboxResource and see what it looks like:

class MailboxResource extends Restlet
{
void handle(Request request, Response response)
{
if (request.method == Method.GET)
{
response.setEntity("Hello, world!", MediaType.TEXT_PLAIN)
}
else
{
// The request method is not GET, so set an error response status
response.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED)
response.setAllowedMethods([Method.GET] as Set)
}
}
}

Next, let’s change the handling of GET to return a meaningful representation of the current state of the mailbox:

if (request.method == Method.GET)
{
response.setEntity("access: closed; messages: 0;", MediaType.TEXT_PLAIN)
}

OK, it’s primitive. But it’s a plausible representation of the current state of the mailbox – and that’s all we need at this point.

Next, let’s add support for PUT, which a client might use to update the open/closed state of the Mailbox, and POST which a client might use to put a message into the Mailbox.

A first attempt to do so might look like this:

switch (request.method)
{
case Method.GET:
response.setEntity("access: closed; messages: 0;", MediaType.TEXT_PLAIN)
break
case Method.PUT:
if (request.attributes.access)
{
this.access = request.attributes.access
}
else
{
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "The request representation must include the parameter 'access'.")
}
break
case Method.POST:
if (request.attributes.messageContent)
{
createMessage(request.attributes.messageContent)
}
else
{
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "The request representation must include the parameter 'messageContent'.")
}
break
default:
// The request method is not allowed; set an error status
response.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED)
response.setAllowedMethods([Method.GET, Method.PUT, Method.POST] as Set)
}

This code would work, as long as we implemented the field this.access set on line 10, and the method createMessage(), called from line 21. But as you can see, our once-svelte method is getting fairly unwieldy, and at this point we’re still only doing very basic processing for our requests. You can imagine that once we need some more complex processing, our method could become impossible to work with.

OK, no problem, we all know what to do in situations like this: create class methods to handle each of our allowed HTTP methods. After which, MailboxResource might look something like this:

class MailboxResource extends Restlet
{
void handle(Request request, Response response)
{
switch (request.method)
{
case Method.GET:
handleGet(request, response)
break
case Method.PUT:
handlePut(request, response)
break
case Method.POST:
handlePost(request, response)
break
default:
// The request method is not allowed; set an error status
response.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED)
response.setAllowedMethods([Method.GET, Method.PUT, Method.POST] as Set)
}
}
void handleGet(request, response)
{
response.setEntity("access: closed; messages: 0;", MediaType.TEXT_PLAIN)
}
void handlePut(request, response)
{
if (request.attributes.access)
{
this.access = request.attributes.access
}
else
{
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "The request representation must include the parameter 'access'.")
}
}
void handlePost(request, response)
{
if (request.attributes.messageContent)
{
createMessage(request.attributes.messageContent)
}
else
{
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "The request representation must include the parameter 'messageContent'.")
}
}
}

Definitely easier to read, but still fairly verbose. That switch statement is looking kinda dumb at this point; it’s not doing much.

So let’s use some dynamic Groovy magic to get rid of it:

void handle(Request request, Response response)
{
def allowedMethods = [Method.GET, Method.PUT, Method.POST] as Set
if (request.method in allowedMethods)
{
def handleMethodName = "handle" + request.method.name.substring(0, 1).toUpperCase() + request.method.name.substring(1).toLowerCase()
this."$handleMethodName"(request, response)
}
else
{
// The request method is not allowed; set an error status
response.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED)
response.setAllowedMethods(allowedMethods)
}
}

OK, now we’re getting somewhere! Easy dynamic method invocation – pretty cool.

Thing is, our handle() method is at this point barely doing anything – just figuring out whether the requested HTTP method is allowed, and calling the appropriate class method if it is, or returning an error if it isn’t. We shouldn’t have to implement this standard logic in every single one of our resources, that’d be pretty redundant.

Thankfully, the developers of Restlet realized this, and they created a very useful class which takes care of much of this sort of overheard for you. It’s named, simply, Resource.

Let’s convert MailboxResource to extend Resource. We’ll do this in a few steps, to illustrate some of the work that Resource does for us.

Let’s start MailboxResource from scratch:

#!/usr/bin/env groovy -classpath org.restlet.jar:com.noelios.restlet.jar
import org.restlet.*
import org.restlet.data.*
import org.restlet.resource.*
class MailboxResource extends Resource
{
static String access = 'closed'
static int messageCount = 0
def MailboxResource(Context context, Request request, Response response)
{
super(context, request, response)
variants.add(new Variant(MediaType.APPLICATION_WWW_FORM))
modifiable = true
}
}
// Create a Finder which will create new instances of MailboxResource as needed
finder = new Finder(new Context(), MailboxResource.class)
/* Create a new HTTP Server on port 3000, pass it the Finder,
to which it will pass all incoming Requests, and start it. */
new Server(Protocol.HTTP, 3000, finder).start()

As you can see, there’s a new import on line 5, because Resource is in a Restlet sub-package. Now’s also a good time to add some static fields to store the state of the resource, on lines 9 and 10. Normally we wouldn’t store state this way; this is just more convenient for now than using a real persistent data store.

Next, you’ll see that MailboxResource now has a constructor. This may seem like annoying overhead, but trust me, it’ll be worth it. For example: the framework will pass the request and response to the constructor, which passes them to the super constructor, which stores them in class fields. This means there’s no more need to pass the request and response around to every method – we can just refer to this.request and this.response.

There’s some other good things going on in the constructor. On line 15 we add a Variant to the variants collection; this is used for HTTP content negotiation – which Resource does for you. That’s right – one of the trickiest aspects of implementing a sophisticated RESTful web app, and you get it for free just by using Resource. Good deal! I’ll demonstrate content negotiation in a later article in this series.

The last line of the constructor sets the resource as modifiable; by default instances of Resource only allow GET; setting modifiable to true allows PUT, POST, and DELETE.

We don’t want to allow DELETE for now, so let’s add this method:

def boolean allowDelete()
{
return false
}

It’s time to add our request handling logic back into the application. Let’s add this method:

def Representation represent(Variant variant)
{
def form = new Form()
form.add("access", access)
form.add("messages", messageCount as String)
return form.webRepresentation
}

Notice that the new method isn’t named “handle” or “handleGet”; instead it’s represent(). There are many good and useful reasons for this, but I’m not going to go into all of them at the moment. I’ll just point out one for now: after processing a PUT or POST request, a common behaviour is to return a representation of the new, altered, state of the resource. So it’s not only when responding to GET that we need to construct a representation of the resource; it’s also frequently needed for other methods. Therefore, a specific method for this need makes a lot of sense.

All we need to do now is implement PUT and POST. Here’s PUT:

def void storeRepresentation(Representation representation)
{
def form = new Form(representation)
if (form.getFirst("access"))
{
access = form.getFirstValue("access")
response.entity = represent()
}
else
{
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "The request representation must include the parameter 'access'.")
}
}

And as you can see, the HTTP method PUT is handled by a method named storeRepresentation(). This is because Restlet attempts to model REST semantics in its API. The framework passes the request representation into the method, because it is the main input of the operation.

On line 3 we see another useful Restlet class: Form. As you might guess, this is convenient for working with web forms.

Finally, let’s add support for POST:

def void acceptRepresentation(Representation representation)
{
if (access != 'open')
{
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "A message can only be put into the mailbox if it is open.")
return
}
def form = new Form(representation)
if (form.getFirst("message_content"))
{
messageCount++
response.entity = represent()
}
else
{
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "The request representation must include the parameter 'message_content'.")
}
}

Normally, an operation like this would create a sub-resource, and the URL of that resource would be returned as a response header, along with the response status 201 Created. This will be illustrated in a later article in this series.

And that’s it, we’re done with our first Resource! We just need to make one last change to our script to make it all work; we need to change the last line to:

// Create a Finder which will create new instances of MailboxResource as needed
finder = new Finder(new Context(), MailboxResource.class)
/* Create a new HTTP Server on port 3000, pass it the Finder,
to which it will pass all incoming Requests, and start it. */
new Server(Protocol.HTTP, 3000, finder).start()

I’ll explain the Finder class in a later article.

As the comments indicate, a new instance of MailboxResource will be created for every single HTTP request. At first this might seem inefficient, but it means that every Resource class is inherently threadsafe – no small value there. And it’s still plenty fast: my ab script from Part 1 now yields 688 requests per second.

Tests!

Let’s update testfulapp.groovy to test our new resource:

#!/usr/bin/env groovy -classpath org.restlet.jar:com.noelios.restlet.jar
import org.restlet.*
import org.restlet.data.*
client = new Client(Protocol.HTTP)
mailboxResourceUrl = "http://localhost:3000/mailbox"
/*** Test 1: at first, access to the mailbox should be closed ***/
response = client.get(mailboxResourceUrl)
assert response.status.code == 200
assert response.entity.mediaType.equals(MediaType.APPLICATION_WWW_FORM, true)
assert response.entityAsForm instanceof Form
assert response.entityAsForm.getFirstValue("access") == "closed"
/*** Test 2: we shouldn't be able to post messages when the mailbox is closed ***/
form = new Form()
form.add("message_content", "whatever")
response = client.post(mailboxResourceUrl, form.webRepresentation)
assert response.status.code == 400
assert response.isEntityAvailable() == false
/*** Test 3: change the mailbox access to "open" ***/
form = new Form()
form.add("access", "open")
response = client.put(mailboxResourceUrl, form.webRepresentation)
assert response.status.code == 200
assert response.isEntityAvailable() == true
assert response.entityAsForm instanceof Form
assert response.entityAsForm.getFirstValue("access") == "open"
messageCount = response.entityAsForm.getFirstValue("messages") as Integer
/*** Test 4: we should be able to post a message now that the mailbox is open ***/
form = new Form()
form.add("message_content", "whatever")
response = client.post(mailboxResourceUrl, form.webRepresentation)
assert response.status.code == 200
assert response.isEntityAvailable() == true
assert response.entityAsForm instanceof Form
assert response.entityAsForm.getFirstValue("access") == "open"
assert response.entityAsForm.getFirstValue("messages") as Integer == messageCount + 1
/*** Test 5: change the mailbox access to "closed" ***/
form = new Form()
form.add("access", "closed")
response = client.put(mailboxResourceUrl, form.webRepresentation)
assert response.status.code == 200
assert response.isEntityAvailable() == true
assert response.entityAsForm instanceof Form
assert response.entityAsForm.getFirstValue("access") == "closed"
println "\nAll tests passed successfully!\n"

That’s all, folks!

And that’s it! We’ve now used Restlet to implement a truly RESTful resource. And we used some Groovy goodness as well: switch, Groovy Truth, dynamic method invocation, casting, and more.

I hope this second installment in the series has been interesting and valuable for you, and I look forward to your feedback, comments, critiques, and constructive criticism.

Coming up in Part 3: Routing. And it’ll be shorter than this monstrosity, I promise.

Full source of restfulapp.groovy

#!/usr/bin/env groovy -classpath org.restlet.jar:com.noelios.restlet.jar
import org.restlet.*
import org.restlet.data.*
import org.restlet.resource.*
class MailboxResource extends Resource
{
static def access = 'closed'
static def messageCount = 0
def MailboxResource(Context context, Request request, Response response)
{
super(context, request, response)
variants.add(new Variant(MediaType.APPLICATION_WWW_FORM))
modifiable = true
}
def boolean allowDelete()
{
return false
}
def Representation represent(Variant variant)
{
def form = new Form()
form.add("access", access)
form.add("messages", messageCount as String)
return form.webRepresentation
}
def void storeRepresentation(Representation representation)
{
def form = new Form(representation)
if (form.getFirst("access"))
{
access = form.getFirstValue("access")
response.entity = represent()
}
else
{
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "The request representation must include the parameter 'access'.")
}
}
def void acceptRepresentation(Representation representation)
{
if (access != 'open')
{
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "A message can only be put into the mailbox if it is open.")
return
}
def form = new Form(representation)
if (form.getFirst("message_content"))
{
messageCount++
response.entity = represent()
}
else
{
response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, "The request representation must include the parameter 'message_content'.")
}
}
}
// Create a Finder which will create new instances of MailboxResource as needed
finder = new Finder(new Context(), MailboxResource.class)
/* Create a new HTTP Server on port 3000, pass it the Finder,
to which it will pass all incoming Requests, and start it. */
new Server(Protocol.HTTP, 3000, finder).start()

Using ColdFusion and LCDS in AIR-powered Flex Applications

Thursday, June 12th, 2008

Previously, I’ve discussed how to use ColdFusion Components (CFCs) in AIR-powered Flex applications but I never got a chance to follow up on how to use CF8’s integrated LiveCycle Data Services ES in AIR.

I’ve figured out that all I need to do is specify a ChannelSet component that is reused in both the Consumer and Producer. Since I was developing locally, I set up my AMFChannel to use my local server. You can see in the following example:



cf-polling-amf




I know there are other channels, such as RTMP, but I have not used them yet. Since I was learning how to use CF/LCDS in AIR, I used it in an AIR version of a simple Chat application. I was quite impressed how easy this was to do. By simply setting up the ChannelSet, I had a working LCDS powered AIR application.

Layers of Java Logging

Wednesday, June 11th, 2008


The Java Logging API is great for tracking the internal workings of your application, both during development and after it goes to production. The API is based on a highly flexible configuration model that gives you complete control over what gets logged and where it gets logged.

I recently started using the API after some time away, and it took a bit to get reacquainted with some of its concepts. In my first few attempts, I ended up with either all logging statements output or none, when what I really wanted was output from only a few specific classes.

I think my problem stemmed from confusion between the various ways to filter output. In the end, I found it easiest to think of the API as two separate layers – a filtering layer that answers the question “What should be output?” and a handler layer that answers the question “How should it be output?”

Below is an example configuration divided into two sections. Although they both end up in a single logging.properties file, I’ve broken them up to demonstrate the concept of separate layers. In the first, I define a default filter level for the entire application, as well as custom filter levels for select packages and classes.

Filter Layer

# Set the global filtering level to INFO. By default all statements below the
# INFO level will not be logged.
.level = INFO
# Set the filtering level for a few packages to ALL. This overrides the
# global level, so all statements in these packages will be output.
# This is good for limiting output to a section of code you're currently
# working with.
com.arc90.package1.level = ALL
com.arc90.package2.level = ALL
# Set the filtering level for a few individual classes. Again, this overrides
# less specific settings. In this case, all statements of level FINE and
# higher in ClassA will be output, and all statements of level FINER and
# higher in ClassB will be ouput.
com.arc90.package3.ClassA.level = FINE
com.arc90.package3.ClassB.level = FINER

Next, I’ll define the handlers that will be used. In addition, I’ll specify filters for the handlers themselves. This performs high level filtering on the final output from the filtering layer. Here, I say that I want only INFO level and higher statements sent to the console, and all statements sent to the log file. The important thing to remember is that these levels apply to the output from the filter layer only – if statements were already filtered out in that layer, they will never make it this far.

Handler Layer

# Specify the handlers to be used. Multiple handlers can be specified
# in a comma separated list.
handlers = java.util.logging.ConsoleHandler,java.util.logging.FileHandler
# Specify the formatters that will be used for each handler
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
# Specify the log file location for the FileHandler. In this case the log will
# be written to my home directory, in a file named example.log.
java.util.logging.FileHandler.pattern = "%h/example.log"
# Finally, specify the filtering level for each handler
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.FileHandler.level = ALL

Thinking of the Java Logging API this way has helped to clear things up for me, and I hope it will for others as well. If you haven’t used the API, you can try it out for yourself by dropping the above text into a logging.properties file (make sure there aren’t spaces at the end of the lines or it won’t work), which must be palced into your JVM’s lib directory or a path specified as a -Djava.util.logging.config.file VM argument. Finally, just add some logging statements to your Java code and you should start seeing output to the console and the log file.

Deposit-friendly Development

Wednesday, June 11th, 2008

Yesterday I had to deposit a check. My bank, Chase, has begun rolling out new “deposit-friendly” ATMs that require neither envelope nor deposit slip for check-only deposits. The process is shockingly simple. Here’s what I had to do:

  1. Select Deposit from the on-screen menu
  2. Insert the endorsed check into a slot, just as I would insert a dollar bill into a vending machine
  3. When I saw an image of the check on-screen, enter its amount [2008/07/02 UPDATE - It gets even better. I discovered today that it actually OCRs the check amount! After I inserted a handwritten check this morning it magically asked me to confirm whether the amount it read on it was correct. It was! I deposited two other checks and it asked me to enter the check amount, indicating that it couldn't read the amounts or it didn't have a high degree of confidence in its scan, so it didn't waste my time asking me to confirm them. I assume OCR would work nearly 100% of the time on machine-generated checks.]
  4. Repeat for any additional checks
  5. Press Done
  6. Get receipt showing an image of my check(s)

Here’s what I DIDN’T have to do:

  1. Fill out a deposit slip, which means I didn’t need to…
  2. Find a working pen, which I would need if I could…
  3. Remember my checking account number, which I never do, so I used to have to…
  4. Wait in line for a teller to give me my checking account number, before I could…
  5. Check the under-copies of the deposit slip to make sure nobody leaned hard and smushed their deposit info down into my slip or surreptitiously wrote in their account number to scam me into depositing my check into their account. (And to think some people trust paper.)

Chase saw a process where a machine that is already operating in a high-security and high-knowledge context asked me to write down the account number it already knows on a piece of paper it can’t read and seal it into an envelope it can’t open. What a wonderfully archaic set of steps to get rid of!

For me the customer, life is now clearly simpler, but what about the poor machine? Like all banks, Chase is very comfortable with ATM software and hardware, but surely the addition of machine-reading and imaging each check makes the ATM vastly more complicated and error-prone, yes? Well, no. Every check in the U.S. banking system has the issuing bank’s routing number, account number, and check number printed along the bottom in a standard Magnetic Ink Character Recognition (MICR) format designed for accurate high-speed scanning. Banks have been whipping checks around and reading those numbers all day every day for decades. And the check image I saw onscreen and printed on my receipt? They’ve been doing that for years as well. When’s the last time you got actual cancelled checks back in your statement? What might seem like an incredibly complex and high-risk project for you or me was to Chase essentially sticking together a few very familiar Lego pieces they’d used a million times.

Any time you see a business process that asks for information it either already knows, already should know, or can easily find out for itself, there is an opportunity for vastly improving the user experience. When you further see that you can do so with technologies you already live and breathe, to me it reads like the story of the perfect development project. Let’s review:

  • First, there was a clear customer benefit: Customers will spend a lot less time doing tedious and error-prone steps that do not benefit them.
  • Second, there was a clear client benefit: Bank staff will spend a lot less time looking up account numbers, opening envelopes and deciphering handwriting on incorrectly filled out deposit slips, and making sure the ATM kiosk is stocked with envelopes and deposit slips. Chase will also spend a lot less money buying and almost immediately disposing of NINETEEN MILLION deposit envelopes a year.
  • Lastly, from an IT standpoint, the requirements are clear and the risk is low: Get rid of all that paper by gluing together all these things we already know very well.

Dare I say it, this project sounds fun! Unfortunately, not all IT projects are such no-brainers. It’s not uncommon for a project to be approved with only two of those three stars, or sometimes even one. Maybe it benefits the client and the customer, but it’s going to be a huge and risky endeavor to implement. Maybe it will be a huge pain to implement and actually infuriate the customers, but the cost savings make it worthwhile (“Your call is important to us. Please listen carefully as our menu items have changed”).

In my experience, the one-star and two-star projects tend to come from an incomplete understanding of the business problem, either by IT or frequently from the business itself. Sometimes clients don’t really know what they want. Sometimes they’re too close to the action to think long-term. Sometimes they don’t understand technology at all. And sometimes we in IT just don’t ask, because we’re too busy trying to keep production up and running while watching Twitter feeds of the iPhone 3G announcement. I’m just saying.

No matter how it happens, if you simply treat isolated problems as isolated technology projects, you’ll get paid for your work, and life will go on. However, a deeper relationship with your client lets you do so much more. Understanding your client’s business plans and long-term goals lets you and your client both see the big picture. You’ll be surprised to see how this wider worldview leads to a more holistic approach to these seemingly tactical technical problems (“the ATMs fill up with deposit envelopes by 11:30. Make it hold more.”) When you do that, you’ll see that those one and two star problems can often be rearranged into three star solutions that make everybody happy. Sometimes so happy that they’re inspired to stay up late writing paeans to something as mundane as a deposit-friendly ATM.

Getting started with PDO_MSSQL

Monday, June 9th, 2008

The Zend framework requires that if you want  your application to work on both Windows and Linux, and take advantage of Zend’s ORM (DB_Table_Abstract) functionality, you have to install and use the PDO_MSSQL driver.

You can first try to install via PECL (however this didn’t work in our case):

bens@arc90-dev-02:~/PDO_DBLIB-1.0$ sudo pecl install PDO_DBLIB
pear/PDO_DBLIB requires PHP extension “pdo” (version >= 1.0)
No valid packages found
install failed

bens@arc90-dev-02:~/PDO_DBLIB-1.0$ sudo pecl install PDO
Skipping package “pecl/PDO”, already installed as version 1.0.3
No valid packages found
install failed

Instead, download the source and use phpize (which prepares the extension compiling) in the root directory of PDO:

bens@arc90-dev-02:~/PDO_DBLIB-1.0$ phpize
Configuring for:
PHP Api Version:         20041225
Zend Module Api No:      20060613
Zend Extension Api No:   220060519

Then execute the configure script to build the pdo module.

bens@arc90-dev-02:~/PDO_DBLIB-1.0$ sudo ./configure 
checking for grep that handles long lines and -e… /bin/grep
checking for egrep… /bin/grep -E
checking for a sed that does not truncate output… /bin/sed
…[removed for brevity]….
———————————————————————-
Libraries have been installed in:
   /home/bens/PDO_DBLIB-1.0/modules

If you ever happen to want to link against installed libraries
in a given directory, LIBDIR, you must either use libtool, and
specify the full pathname of the library, or use the `-LLIBDIR’
flag during linking and do at least one of the following:
   – add LIBDIR to the `LD_LIBRARY_PATH’ environment variable
     during execution
   – add LIBDIR to the `LD_RUN_PATH’ environment variable
     during linking
   – use the `-Wl,–rpath -Wl,LIBDIR’ linker flag
   – have your system administrator add LIBDIR to `/etc/ld.so.conf’

See any operating system documentation about shared libraries for
more information, such as the ld(1) and ld.so(8) manual pages.

———————————————————————-

If all went successful, you should see a similar message. Now, copy the module (pdo_dblib.so) from the build directory to your php directory:

bens@arc90-dev-02:~/PDO_DBLIB-1.0/modules$ sudo cp pdo_dblib.so /usr/lib/php5/20060613+lfs/
Then, copy the pdf_dblib.so to /usr/lib/php5/20060613+lfs/

Make a backup of your php.ini file and add the following to the php.ini file:

extension=pdo_dblib.so

Restart apache add the following to your config.ini in the Zend project you would like to use the PDO driver (on Linux):

database.adapter          = “pdo_mssql”
database.pdoType        = “dblib”

PDO should be setup and working. Enjoy.

An Easy Way to Implement Namespaces in JavaScript

Friday, June 6th, 2008

(Object-Oriented JavaScript Series)

Namespaces are a great way to uniquely distinguish objects from different projects. Unfortunately, JavaScript does not have native support for namespaces, but we can approximate it, by putting our objects inside other empty objects.

For example, to create a namespace called arc90.components, we would first define arc90 as an empty object:

arc90 = {}

If an object called arc90 already exists, we don’t want to erase it; so we will check for it first, then create an empty object only if the arc90 object doesn’t already exist. We can do that like so:

if (typeof(arc90) == "undefined")
arc90 = {}

The type of operator returns the type of an object as a string. If the object does not exist at all, a value of “undefined” will be returned. This is what we are checking for:

Now that arc90 is defined as an object, we can go ahead and define the next level of the namespace, arc90.components. We basically repeat what did for the arc90 part of the namespace:

if (typeof(arc90.components) == "undefined")
arc90.components = {}

By now, you must be thinking, “Boy, we’re repeating a lot of code here. There must be an easier way.” Well, don’t worry, there is. There are two options. You can use the YUI Library, which already contains a namespace function, or we can create a simple namespace function ourselves. Since I don’t want my tip to consist of just a link to Yahoo!, I will do things the long way and show you how to create a namespace function.

The most important part of the function is the use of the eval operator. This lets you pass in JavaScript code as text, allowing you to dynamically create object names. This is important, because normally, object names must be hard-coded, which would prevent us from creating new objects dynamically, if not for the eval operator.

Now, we will create a function, which will create a namespace object out of the string you pass in. For example, calling:

createNamespace("arc90.components");

will create an object called arc90.components. It also returns the object that was created, so that you can create an alias. For example, calling the function this way:

var alias = createNamespace("arc90.components");

will create the namespace object and set alias to reference the same value. Now, if we were to define a new object called Checkbox within the namespace, we can either use the fully qualified name, like so:

arc90.components.Checkbox = function() {}

or we can use the alias:

alias.Checkbox = function() {}

You can use either the fully qualified namespace or the alias to reference the same objects. The only thing you must be aware of is that you cannot give your alias the same name as any part of the namespace. For example, if you have a namespace called arc90.components, you cannot name your alias arc90, or components. This will overwrite the object in the original namespace.

Now, let’s create the createNamespace function:

function createNamespace(ns)
{
// First split the namespace string separating each level of the namespace object.
var splitNs = type.split(".");
// Define a string, which will hold the name of the object we are currently working with.  Initialize to the first part.
var builtNs = splitNs[0];
for (i = 0, i  0) ? ("." + splitType[i]) : "";
// Check if the object we want to add exists, and add a new empty object if it doesnt.
eval(builtNs + " = typeof(" + builtNs + ") =='undefined' ? {} : " + builtNs + "; ");
}
return eval(ns);    // Return the namespace as an object.
}

The above code first splits the namespace string into parts, so that a namespace called arc90.components will be split into two strings, arc90, and components. The function then loops, adding the next string to the first as it goes. On the first iteration, we have only arc90, which will then be created as an object by the line:

eval(builtNs + " = typeof(" + builtNs + ") =='undefined' ? {} : " + builtNs + "; ");

This is essentially the same code we wrote at the beginning, rewritten using a one-line ternary operator, and wrapped in an eval statement. After the eval statement runs, the code generated would look like this (on the second iteration):

arc90.components = typeof(arc90.components) == 'undefined' ? {} : arc90.components;

So, there we have it; a function to create JavaScript namespaces. Enjoy.