Wednesday, February 25, 2009

REST and Déjà vu

REST is getting a lot of attention. I'm still working my way through "RESTful Web Services" by Leonard Richardson and Sam Ruby.

As I understand REST, if I want to access a resource I can use the GET method and I will receive a representation of that resource that includes that resource's data. If I want to update the resource, I use the PUT method to "save" the resource's new data.

What does that remind me of? Think. Think.

Ah yes! My early days of coding in C. I would get a struct-full of data from somewhere, change one or more members, and then call some method that persisted those changes. The struct I was changing just contained data and had no behavior.

Object Orientation

Later on I learned how to encapsulate the struct's data and use functions to provide behavior for the struct. Then I learned about Object Orientation (OO). With OO, as a user of an object, I don't need to know anything about the object's data, what its members mean, valid combinations of data, etc. I let the object handle all that stuff.

I know OO isn't a panacea and that it isn't universally accepted and that those who do accept it rarely agree on what it means or how to do it right. But hasn't it taught us that encapsulation is good?

I do know that I don't want to go back to programming like I did in my early days of C programming.

Un-RESTful Web Services

I'm not saying that we need to start exposing all our objects via URIs. Objects typically have chatty interfaces (lots of fine-grained messages passed to the object) and chatty doesn't scale very well.

I do think that the Facade design pattern can be used to keep the interfaces more chunky (fewer, but coarser-grained messages passed to the facade) and our systems performing better.

This is the approach that many web services use today.

Hackable URLs

REST provides hackable URLs:

GET /book (returns all books)
GET /book/123 (returns the representation of book #123)

That's very cool. There's nothing preventing us from using hackable URLs in web services. In fact all you Smalltalkers and Objective-Cers might feel right at home with URLs like:

/book/123/delete (deletes book #123)
/book/124/loanToUser/432 (loans book #124 to user #432).
/books/addTitle/Object+Thinking/copies/4/branch/Central (adds 4 copies of a book to one branch's inventory)

Encapsulation

Another reason why we use objects is because our object's representation, the very thing that REST makes public, might change and we don't want the user of our object to be affected by a change to our object's internals.

Conclusion

I'll keep reading the RESTful Web Services book and hopefully I'll find out that I've misunderstood everything and that REST really is a step forward (or at least sideways) and not a step backwards.

Monday, December 29, 2008

Single Responsibility Principle

I really do like what Robert C. Martin has to say about OO but I just don't agree with his position on the Single Responsibility Principle. It sounds like a good principle but then when I try to apply it in my mind, problems arise.

Let's look at a few of the classes he ends up with in his paper on SRP. The Connection interface has two methods: dial (which takes a string) and hangup. Does this class really have only one reason to change? No, there are still a number of reasons why this class might need to change. There might be different ways of hanging up ("politely" for valid connections and abruptly for would-be hackers). There might be different ways of dialing (with or without the speaker, supplying credentials, selecting a protocol, specifying minimum modem speed, etc.). There might be modems that never hang up.

I would posit that most classes have more than one reason for change. Here are a few examples.

Rectangle - the data types for the coordinates may change (16-bit to 32-bit), we may want polar coordinates instead of Cartesian. We may even want non-euclidean rectangles.

String - The character set may need to change. The storage mechanism may change (e.g. list, array, linked blocks of memory). The allocation scheme may change.

Just as easily as someone can say there is only one reason for a class to change, someone can find out multiple reasons for that same class to change (with very few exceptions). It's quite subjective.

If you could split all your classes into single responsibility objects, you'd have a huge number of classes that each did very little. To do anything useful, you would need to enlist the help of many classes. This makes for poor comprehension of the system and poor usability.

I want there to be a one to one mapping between concepts and classes. If I have a concept of a file, and I want to read and write from a file, I will expect there to be a file object with read and write methods. If I have to create input streams and output streams and file-opener objects, I will not enjoy the experience. I want a file object. I don't care if, behind the scenes the file is using an input stream and a output stream and a file-opener. I just don't want to see them or need to know about them.

With this one concept per class approach, there is a greater chance of complexity if precautions aren't taken. To combat that complexity, I would consider breaking up the main concept into sub concepts (e.g. input, output, seeking, etc.) and then coding each sub concept as a separate class and then hide that class behind the facade of the main concept's class.

This approach also helps with testing. If each of the sub concept classes can be mocked and injected into the main concept's class, the class is easy to use and easy to test.

You still need to guard against combining incompatible concepts into one class (e.g. file management with searching directories) mostly to avoid confusing the user. Remember that class size and complexity can be managed by decomposing the main concept's class into other classes.

Monday, May 12, 2008

Measuring Talkativeness With Big O Notation

In addition to its commonly known uses, Big O Notation can also useful for describing a person's talkativeness. Given the number of words you say to a person, their Big O factor tells you how long their response will probably be.

The stereotypical male's Big O factor is O(1). Regardless of what you say to him, you get a constant response (which may or may not be a grunt).

A cooperative conversation would be some where in the neighborhood of O(n) meaning that both parties are contributing equal amounts.

Then we get to the chatterbox who has a Big O factor of O(n^3). I get a little nervous when I encounter a person with this kind of Big O factor. I know that even if I grunt, that will spawn a long and drawn out discussion on some topic.

I used to know a guy who was somewhere around O(n^n!). I really dreaded seeing him.

What gets dangerous is when you have two O(n^n) (or worse) folks talking with each other. Each one's response is amplified by the others until they're both talking over each other and they pass out from buffer overflows.

I've been too general up too this point. I know that based on the topic of conversation, I have different Big O factors. Here is a list of topics and my Big O factor for each topic.

  • Sports - O(1) (yes, I will grunt).
  • Politics - O(n/2)
  • Computers - O(n^2)
  • Clothing, Shoes or Purses - O(1)

Thursday, May 1, 2008

SharePoint : The Perfect Storm

Wikipedia defines a perfect storm as "the simultaneous occurrence of events which, taken individually, would be far less powerful than the result of their chance combination."

Rather than events, in the case of SharePoint, I see the elements of the perfect storm being conditions. Those conditions are:

  • SharePoint is widely accepted by CEOs, CTOs, architects, and users all around. SharePoint's user experience is very nice for the most part. I think that the product brings a lot of value to users. This is a good thing.
  • SharePoint does a lot just out of the box. It has all sorts of useful templates for sites and it has common workflows. However, beyond a certain point (as with most if not all software) SharePoint cannot do what you want without customizing it with managed code (C#, VB.NET, etc.). This too is a good thing.
  • SharePoint's developer experience is terrible. I won't go into details.
So on the one hand you have CEOs, CTOs, and architects pushing for the use of SharePoint in the company, and on the other hand you've got a terrible developer experience. The eventual result is a shortage of SharePoint developers and an increased demand for them.

Will enough SharePoint developers leave SharePoint that Microsoft will be pressured into improving the developer experience? Or will there always be enough SharePoint developers to squeak by?

CTOs and CEOs who select SharePoint and need to customize it might start feeling the effects of this perfect storm when they have a harder time hiring and retaining developers, and then have to pay them more.

If you are in the software development business for the money, SharePoint development could be a great cash cow. The only problem is that you have to develop in SharePoint.

The next time you hear a technology is hot, you may want to find out why the technology is hot.

Tuesday, April 29, 2008

The Forces of Characterization and Cohesion

Often times the first stage of enlightenment is when an original and revolutionary idea comes to me and grabs my attention. In most of those cases, the second stage of enlightenment is when I realize that I had actually heard that idea from someone else.

Regarding my latest "enlightenment", in the area of class names, I can't remember all of the sources of inspiration that came together but I experienced it while I was reading Kent Beck's book "Implementation Patterns". The book is a collection of principles that promote improved code readability.

While reading about the importance of selecting names for classes, a couple of principles that I had heard before came together into a single picture.

That picture is made up of two forces.

The Force of Characterization

The first is the Force of Characterization. It exists between a class' name and the class' code. If, and only if, the class' name properly characterizes what the class does, the Force of Characterization is in harmony.

For example, if the class' name is Account and the code for the Account class does currency conversion, the name Account is a mis-characterization of the class' code.

The Force of Characterization moves you to to examine the fit between the class' name and what the methods do and, where the fit is bad, it causes you to adjust either the name or what the methods do to bring the Force of Characterization into balance.

The Force of Cohesion

The second is the Force of Cohesion. Cohesion exists in a class' methods to the extent that the class' methods work together for a single purpose.

If some of Account's methods provide account related operations (e.g. deposits, withdrawals), and other methods perform currency conversion, the methods are not cohesive.

The Force of Cohesion moves you to examine the class' methods and how well they work together to a single end. Bringing harmony to the Force of Cohesion is done by moving methods and perhaps data from one class to another. It may also involve splitting up a single method into multiple methods.

Interplay Between the Forces

Where this gets interesting is when these two forces start interacting with each other.

As you change a class' name, you may be changing its purpose. For example, changing the name of a class from CustomerInfo to Account significantly changes the expectations that a user would have for the class' code.

Because the class' methods should be acting towards one purpose (the class' single purpose), changing the name of the class can affect the cohesiveness of the class' methods. The single purpose that the class' methods were working towards before the class was renamed might have been redefined into two or more purposes.

In other words, when you change the name of a class in an attempt to harmonize the Force of Characterization you may temporarily introduce disharmony with respect to the Force of Cohesion. The converse of this is also true.

Sometimes a disharmony in one force can be resolved without introducing disharmony in the other force. However, I imagine these two forces occasionally going through cycles of harmony and disharmony, in and out of phase with one another, until both forces are in harmony, and a stable state has been reached.

Conclusion
  1. Changing a class' name can move you to change the class' methods to restore harmony in one of the two forces.
  2. A class' name is important when adding features; it helps you answer the question, "Does this method/data member belong in this class?" If you achieve harmony between the two forces, the class name will be a helpful guide as you read and maintain the class' code.
  3. Changing a class' name may prompt you to rename methods to be more consistent with the name.
  4. A class name that is a good characterization of the class' methods can actually assist you in maintaining the cohesiveness of the class by making un-cohesive code more obvious.
Question(s):
  1. Are there other forces that interact with class names and cohesion in interesting ways?

Thursday, April 24, 2008

A Different Perspective on Web Applications

Notice that I said this perspective is different. I intentionally left out words like: smart, useful, good, and many other positive adjectives.

My goal for taking this perspective is to see if it fits, what problems it solves (or creates), if it makes reasoning about or building web applications any easier. The good thing about perspectives is that you can try them on, look around, and then take them off (or even discard them).

The perspective that I'm taking off for this post is the one that states that a web application extends from the user in front of their browser all the way back to the data layer. That perspective is nice and has been around for a while now. But it has some rough edges that I'm trying to smooth out.

The Rough Edges

1) Data Validation is spread throughout all three layers of a three-tiered web application architecture. I wrote about this here.

2) Presentation Layer activities are performed in two places: in the browser via JavaScript, CSS, HTML, etc. and on the server when the HTML is dynamically generated (e.g. JSP, PHP, etc.).

Perhaps these rough edges cannot be avoided and all my attempts to do so will fail. Maybe I'm the rough edge and I just need to accept that the nature of the web requires that similar things need to happen in different places. Or maybe I can just change the way I look at the problem so that the rough edges disappear.

Here is the different perspective. What if we equate a web application to a standalone desktop application like such:

Selecting the Application to Run

To start a desktop application, you run a program at a certain location (its path) with optional arguments

To start a web application, you enter a certain location (its URL) into your browser with optional arguments.

Application Start Up

When you start a desktop application, one or more resources are loaded from the disk into memory, a user interface is presented, and an event loop is entered.

When you start a web application, one or more resources are loaded from the web server into the browser, a user interface is presented, and an event loop is entered.

Additional Resources

As the desktop application is asked to do different things, it may load additional resources (e.g. user interface elements, XML files, DLLs, etc.) from the disk.

As the web application is asked to do different things, it may load additional
resource (e.g. HTML, JavaScript, CSS, images, etc.) from the web server.

Changing State

The desktop application user wants to save their changes so the application the writes the changes to disk.

The web application user wants to save their changes so the application sends the changes to the web server.


After drawing these parallels, would you say that a Desktop Application extends from the user in front of the screen all the way to the disk? Probably not. Yes, the disk is involved, but that's not part of your application proper.

So could we say that a web application starts at the user in front of the browser and ends inside the browser?

Is that too much of a stretch? Can we really equate the Internet, our web servers, and back end databases all to a storage device? I'm going to try. Maybe the analogy will work, maybe not.

Implications

A number of interesting things happen once we say that a web application is just what is going on inside the browser:

1) There are no more tiers to think about on the browser side (see also Tautology). Perhaps we can simply adopt a Model/View/Controller approach in the browser. It's perfectly okay to have data validation in an MVC application so I don't need to worry about spreading data validation through out all three tiers (yes, I am totally ignoring the web server and database layer for now). The browser is not self-sufficient; just as the desktop application loads resources from disk, the browser application will load resources from the web server.

2) The web server becomes less user-serving and more application-serving. A page served by the web server is not as much a page that the user will see as as it is some user interface resource that is loaded by the application. The difference is subtle but I'm going to note it anyway. Perhaps it's important.

3) The web server gives up much of the control it had once we start putting more focus on the browser as the web application. Many web server applications of old carefully created their HTML pages so that every link and button would initiate the proper request back to the server. If the browser is the web application, the JavaScript code can play a much larger role in deciding what resources to request.

I have really tightened my focus to the browser client and have forgotten all about the web servers, and database servers. In doing so, I've seen some nice properties emerge on the client side. For one, I can reason about the client in isolation. But have I created a terrible mess on the server side? Let's see.

What Does the Server Look Like Now?

As I start this section, I've isolated the browser client and abstracted away the rest of the application. Now I've got to deal with the Application Layer and the Data Layer. I'm starting to wonder if my attempt to gain a different perspective on three-tiered architecture will land me right back at a three-tiered architecture.

Let me do a roll call to see what we have left on the server.

Presentation Layer. Check. Granted it's not really presenting things to the user (as I pointed out earlier).

Application Layer. Check. But couldn't we put all of the Application Layer on the client? Yes we could, but should we. Browsers with good debuggers allow users to modify the DOM and the JavaScript environment. As a safety precaution, we need some code that the user can't tamper with.

Data Layer. Check. We haven't gotten rid of that either.

Conclusion

I tried on a different perspective. At first it seemed promising, and then the three tiers appeared again on the server side.

In addition, the rough edges remain although the presentation rough edge is slightly different as we have two different parties we're presenting to (i.e. the browser application and the user).

I like the way that the client looked in this perspective. The only way to see if it really works though is through using this perspective to develop some web applications.

Monday, April 21, 2008

Objects and Data Validation

I've written a lot of objects that do data validation but I have yet to come up with a standard approach to data validation for objects.

When should the validation occur?

I have usually taken the approach that as soon as something goes wrong, I want to know about it. If you call a setter method passing in invalid data, I want to catch it immediately and reject it by throwing an exception.

Ken Pugh, in his book Prefactoring mentions the use of specific data types. He would say that your setPhoneNumber() method should not take a string but it should take a PhoneNumber object. The PhoneNumber class' constructor would parse whatever string you tried to initialize it with and throw an exception if you didn't pass it a proper phone number. In this way, you can't even pass an invalid phone number to setPhoneNumber().

Delayed Data Validation

There are some cases where delayed data validation is the only way to go. Consider a very contrived but simple class whose "lower" attribute must be the lower case version of its "upper" attribute. If "lower" is 'a' then "upper" must be 'A'. If the class provides only setLower(char c) and setUpper(char c) these methods cannot do data validation. Either the class must supply a setBoth(char upperC, char lowerC) method or there must be a way to delay the data validation.

A less contrived example would be a Location object that has a City and a State property. If the object tries to make sure that the City value is always a city in the State value and that the State value always has a city by the name of the City value, users will find it difficult to use.

Not A City

Let's try something. If you had a special City value (e.g. NaCity resembling NaN for not a number) and a special State value (NaState) and setting the City would always set the State to NaState and vice versa, the validation could be simplified. If the City value is NaCity don't validate it. Hmm... but now you can have locations that don't contain City or State information. That doesn't sound very valid.

Try To Be More Accepting

Let me make things a little more complicated. Alan Cooper in his book "About Face" talks about data validation in the user interface. He thinks that a user should be able to enter incomplete information. Why should you have to discard your work if you don't have every required field filled in? Perhaps data validation should only be done in select situations? For example, I should be able to set attributes in my Customer object to whatever the data types will allow and save that invalid data. But when I want to send out some invoices to my customers, I should only send out invoices to customers that pass data validation. That way, I'm not sending mail to Fooville, or to Mars. This approach would probably require some report or view that showed all customers who were in an invalid state. That way folks can keep an eye on all of the Customers they can't yet bill.

Reporting what is actually wrong might involve a wee challenge. A Customer object might fail validation due to one of the Customer's aggregated objects. It's up to the programmer to make sure that the source of the validation failure is reported correctly.

Taking this on demand approach to validation in the business logic tier and not in the data tier puts you in a bind. Now you've got all of these invalid objects in memory, and you can't save any of them because of some database constraint. The moral of the story is to synchronize your data validation approaches throughout all of the tiers of your application.

Changing My Mind

The more I go on about data validation, the more I like the on demand approach. The nicest thing about it is that it separates data modification from data validation. You're always performing validation on stationary data.

Now when I put on my user hat, I like to know if I've made a mess of something even if I can't fix it at the moment so flagging a Customer as invalid in the user interface is probably a good idea.

There are some situations where this on demand approach to data validation won't work. For example, if we were writing a code generator for Eclipse, and we allowed the user to create a class named "<:^)" we would be doing them a disservice as the code would not compile and there may be many references to "<:^)" that they would need to change.

One Way of Data Validation

I'm sure there's not One True Way of Data Validation. You may have a legacy database that has bullet proof constraints and is guarded by German Shepherd attack stored procedures. You may have an object model that must be 100% valid at all times (e.g. Air Traffic Control systems, SDI, a super safe lethal injection device, etc.).

For future projects, I think that I will start off with the on demand approach and see if that works.

Exercises Left to the Reader

1. Consider mixed models (e.g. strict data validation mixed with an on demand validation approach). Would the mixture of data validation models be too confusing?