Tuesday, November 24, 2009

Lessons learned from Impact pitch competition

By this time everyone can probably guess that GoEyeball did not win the pitch competition at Impact National 2009 conference. Otherwise you probably would have seen me flashing the giant check of 10K ;-) (although not in cash but in service with KPMG). Today I am writing this blog to share some of the experience and lessons learned from this competition, so I guess we can score a few wins from this loss.

#1 Pitch an idea especially a new one that involves innovation in technology in 5 mins elevator pitch is not a easy task

We actually received feedbacks in conversations after the pitch that a lot of the audience, including the judge, did not understand or realize that we have invented a new technology to provide a service that is not available from our competitors

#2 You need to be clear on what you are asking for

After the competition, my business partner and I regrouped and did some retrospective on the performance and realized we were not clear on the message. Here is what we believe a better format for our pitch could be:

  • Who we are?
  • What problem do we solve?
  • Why will we be successful?
  • What do we need? Funding? Mentor?
  • What is in there for you? Exit strategy for investors.

We did not win the top prize, but we still had a great time at Impact. This is only our first appearance for public pitching; we will continue working on it, but most importantly we will continue to have fun after all that was why I quite my full time job in the first place - to have FUN. So far it has been a journey of every bit of fun I could have ever imagined :-D

Thursday, November 19, 2009

GoEyeball is one of the finalists for Impact National 2009

I am very proud to announce that GoEyeball.com is one of the 4 finalists at Impact National Conference 2009 pitch competition hosted from 3:30-5:00pm on Saturday Nov 21 at:

Westin Harbour Castle
1 Harbour Square
Toronto, ON M5J 1A6

We are also an Exhibition Sponsor for the conference with a booth in exhibition hall on Friday afternoon to showcase our technology and answer any question from users, potential investors, and any one who is interested in our idea. If you are attending the conference or know some one attending please come check out our booth and show your support at the competition.

Will keep everyone updated with the result on this blog.

Monday, November 02, 2009

JointSource is open for business in a new office

We are now open for business in our new office near Yonge and Eglinton (3 mins walk from the subway station). Our new address:

120 Eglinton Ave East, Suite 1000
Toronto, ON Canada M4P1E2

Phone: 416.322.2931 Fax: 416.322.2877

Email: nzhu@jointsource.com
Website: www.jointsource.com




View Larger Map

Monday, October 26, 2009

My New Business Venture

Last week after a long talk with my wife and with her blessing I made one of the most important decisions I have ever made, other than marrying the woman I love :-), to quit my individual consulting career and start working full-time to develop my own software business specializes in what I call “UnSourcing”. I have been doing independent consulting on and off for the last 6-7 years, the outsource experience I had in Siemens, Rogers, and many other firms convinced me something I have always suspected

“With a highly capable team equipped with a proper Agile process, it should be able to build high quality custom software with much less TCO comparing to a typical off-shore outsourcing vendor“

The reasons are simple. The outsource model works great in manufacturing because of the revolutionary work done by Federick Winslow Taylor (Scientific Management) and Henry Ford (Assembly Line) and many others like them throughout the 20th century. The manufacturing process is virtually optimized to the limit; the only way left to reduce cost is by simply reduce the cost of labor. Furthermore because the process is so streamlined and well defined outsourcing it to a different country literally has no major impact to neither the quality nor productivity of the process at all. In software industry despite how much we have been trying to fit the manufacturing model, we are not manufacturing software and coding is not an act of manufacture or construction but rather an on-going design process.

“Source code itself is a major part of the design. The construction of the software is done by the compiler and machines cheaply and flawlessly, but not by the developers.”

Since coding is more a design activity than manufacturing, more of a craft than engineering, that’s why a master programmer can be up to 28 times more productive than a not-so-experienced counterpart. With that in mind, its not difficult to understand before we go for off-shore outsourcing there are actually huge amount of optimization we can do in other parts of the system to lower the cost. The recent Agile movement in the industry is a perfect example of how much waste we can cut out before we resort to the labor cost.

I am starting my business with my business partner in the hope of being able to help companies who have suffered from outsource mess to actually deliver high quality software and solutions with true business value and most importantly with much less TCO. In the next a few months I will record our journey here in my blog, and of course we appreciate anyone who would like to share their experience, advices, and leads with us if you would like to see this somewhat quality obsessed software shop to survive this largely manufacture minded industry out there :)

Wednesday, September 30, 2009

DuctTape Guy or Craftman?

I just finish reading The DuctTape Programmer from Joel Spolsky and Uncle Bob's response this morning, and I have to say what a contrast in their views of how to define a good programmer. I completely agree with Joel as a programmer for business in a real world especially if you are running or working for a startup company where you believe there are only a few months window to achieve what you set out to achieve before somebody else eats your lunch, over engineering or pre-mature optimization over business functionality is definitely stupid and sometime even lethal. If you can achieve the same functionalities with a simpler design or a simpler tool or both then stick with the simpler version. Remember

"Simplicity is the ultimate sophistication." -- Leonardo da Vinci

Once you have been trying to make everything you bulid as simple as possible but not any simpler, you will probably realize its actually not a "simple" goal to achieve sometimes even turning out way more difficult than using the complicated alternative. However like Uncle Bob I strongly disagree with Joel's constant bash on Unit Testing, since unit testing is not really a technology or even a technique of choice but next step in the evolution of programming. Its not like a decision about multi-threading vs. single-threading or even using a certain design pattern or not, either way you can implement the functionality so there is no arguement here ship the single thread implementation. When it comes down to unit testing there is no alternative, different technology or framework for implementing your test cases but not the principle itself. On top of that when you use unit test in a TDD way it actually has not much to do with testing, but instead a brand new way (compare to the triditional non-TDD way at least) to materialize your design, drive your implemetation, and a core enabler for many other useful Agile practices such as Refactoring.

I believe when you are building a product, just like building a company, carrying some debt (in this case the technical debt) is healthy and beneficiary to the growth, but the balance is essential here don't declare technical bankrupcy before you can even ship something. By the way, even if you are working in a startup, don't put too much emphasize to the First-Mover Adavantage since its just a marketing myth. The recent success in Google and Apple's iPod are the perfect examples of why the first-mover advantage is highly overrated. For startup I truly believe the vision, innovation and quality are the key building blocks for any enduring success.

Tuesday, September 22, 2009

Technical mess is a one way ticket to Technical Bankrupcy

I just finished reading Uncle Bob's new post A Mess is not a Technical Debt. Lack of understanding of this key differentiation is so common in the industry. I have witnessed many projects and businesses creating a mess thinking that is a way to produce something under tight budget and timeline. They did not realize this debt (if you consider debt way beyond your affordability is still a debt) is so overwhelming, it basically turns out to be a one way express ticket to technical bankrupcy. It's an especially popular view among startups. Many startup entrepreneurs are very cautious when it comes taking on finicial debt however reckless when it comes to technical debt. When the debt accumulates to a certain turning point then it is no longer debt but a suicide. I consider a suboptimal algorithm is a technical debt or even unit test coverage from 90% to 80% is a debt however unwise, but 0% unit test coverage is not a debt but a bandrupcy, a train wreck in slow motion resulted many slow and painful deaths I witnessed in my almost a decade long career.

One thing still perplex me is I have also witnessed a few companies enjoyed some pretty decent finicial success while creating a big technical mess...

Monday, August 24, 2009

Install PHP 5.3 on CentOS

A couple days ago I compiled and installed PHP 5.3 with MySQL and SOAP support on a CentOS box since its not available in Yum repo. Here is some notes and problem I encountered. My configuration:

./configure --with-mysql=shared --enable-pdo --with-pdo-mysql=shared --with-mcrypt=shared --with-mhash=shared --with-gd=shared --enable-soap=shared --with-config-file-path=/etc/ --with-jpeg-dir=/usr/lib/ --with-apxs2 -–with-mysqli --enable-zip -–enable-shared


The only problem I ran into other than installing all the dependencies is libxml2 library that PHP depends on is currently not available in Yum repo you will have to download it and install manually.

wget ftp://xmlsoft.org/libxml2/LATEST_LIBXML2
tar -xf LATEST_LIBXML2
cd libxml2-x.x.x
./configure
make
sudo make install

Wednesday, August 19, 2009

Redirect AntBuilder output in Groovy

In Groovy you can use the following code to redirect default AntBuilder output to a log file:


def ant = new AntBuilder()
def logOutput = new PrintStream(logFile)

// redirect std out and error output
System.out = logOutput
System.err = logOutput

// redirect ant output
ant.project.getBuildListeners().each{
it.setOutputPrintStream(logOutput)
}

Tuesday, July 28, 2009

The specified module could not be found

The title of this blog is an error message I got while installing PHP 5 and Aapache 2 on a Windows XP workstation. Due to project need at work I needed to setup a local PHP environment at work. I have to confess I haven't touched PHP in probably more than 7 years and first thing I noticed was "O boy! It has come a long way". The windows installer for PHP is very well designed and implemented, almost everything was a breeze until I spot this error message in the apache error log:

PHP Warning: PHP Startup: Unable to load dynamic library 'c:\\php\\ext\\php_mysql.dll' - The specified module could not be found.\r\n in Unknown on line 0

For some unknown reason certain php modules could not be loaded properly. So like anyone who is new to a certain environment I suspected that I did something wrong during the installation process and immediately started investigation and researching on google. After following many different threads and trying various fixes like adding dll folders to the $PATH, moving php.ini, checking phpinfo(); output, or even reinstall php engine but all efforts to no avail, I ended my day in discouragement and frustration.

This morning when I was fully charged on coffee and ready to take another crack at this problem, miraculously everything is working all of sudden. Right away I remembered this advice I got from a very wise friend years ago "Take a break and reboot your machine usually is the best solution if you are stuck with a problem, especially if the problem is on a windows machine". Sign~~~ how am I gonna get my wasted 3 hours of life back.

Friday, May 29, 2009

Grails TransactionManager Config

Today I was asked by one of my colleague "why grails does not ship with a default transaction manager?" I was kind of confused since I am very certain that Grails ships with a HibernateTransactionManager since Gorm is built on top of Hibernate 3. After a little bit discussion I realized the culprit is this message generated by Jetty:

INFO: No Transaction manager found - if your webapp requires one, please configure one.

Since Jetty does not recognize the Spring transaction manager therefore this message is generated, so to verify that Grails does use transaction manager fire up a Grails shell console and type the following:

println ctx.transactionManager

You should see something like this in the output:

org.springframework.orm.hibernate3.HibernateTransactionManager@12f40eb
===> null


So rest for sure all those transactional = true declaration in your service class are not just for show ;-)

Friday, April 17, 2009

Performance Tuning Daylog for Hydra Cache M4

After almost 7 months (wow can't believe its been more than half year already) of hard work finally Hydra Cache project is reaching its Milestone 4 - Feature Completion, and very close to its public debut v1.0 RC1. You can find the official Project Wiki Site and the new Maven Project Portal for the code snapshot, javadoc, and various reports. Hydra Cache was built so far without performance tuning in mind. Yes you heard it right, performance tuning was not our focus at all throughout the entire development for the first 4 milestones. Our focus so far are on code quality, testability, architecture, and maintainability. We intentionally picked techniques that make our code succinct and readable over high performance ones, for example we used:

HashCodeBuilder.reflectionHashCode(this);

in hashcode() method instead of hand crafted bits shifting magic. Why? because its shorter and more readable. But.. but its using reflection! I know, but trust me you can write much slower code (a few order of magnitude slower) just a few blocks away from here with a simple log.debug(...) so why focus on this one, plus the more you delay the optimization the more options you will have to throw at a performance problem even if this one actually becomes a real bottleneck.

* Thanks to my team mate David Dossot to constantly reminding me at the beginning of the project to hold off the nerd inside of me that craves for high octane performance and some fancy hash code algorithms.

But now to reach RC1, one of the task is to actually optimize the performance since one of the goal for Hydra Cache is to provide highly scalable and fast caching system. First thing first, lets build a performance test tool kit so we can have a consistent and controled environment to benchmark Hydra. I picked Apache JMeter an open source performance testing tool as our testing framework since I have worked with JMeter before and plus of course its open source. Two JMeter Samplers were created for GET and PUT operation respectively, and a throughput test plan designed to stress the server in an artificial manner so we can measure the throughput and the cpu usage under stress. Lets fire it up and see what we got here. Since this is a not a real performance test to actually measure the throughput but rather a test designed to identify performance bottleneck, therefore it was being executed on my laptop (Intel Centrino Duo Core 2Ghz with 2Gb of RAM running on Sun JDK 1.6.0_13). 4 local Hydra servers were launched with 64MB of heap memory configured each, and the Hydra space configuration for each server node is identical with the following parameter: N=3, W=2, R=1. What this means is each PUT operation has to be sucessfully multi-casted and propogated to at least 1 (W) servers before the PUT operation is considered to be succesful and eventually up to 3 (N including the initial server that received request) servers will store the same replica in the space. However the GET operation will be performed by a single node only without multi-server consolidation. This is a typical configuration to offer reliable writes and redundency but optimized reads for better performance. Here is the performance with 10 test threads and 1000 writes/reads each.


GET Throughput Chart



PUT Throughput Chart

49k read/minute (800 read/sec) and 9k write/minute (150 write/sec) this is not too bad considering till now performance optimization is not even attempted nor considered during coding.

* I am going to stress here again this is not a throughput test but rather a test specially designed to pin-point performance bottleneck, so do not take the number here as the maximum throughput number for Hydra Cache

Now to find out what's hogging all the CPU cycle we need to do some profiling. Thanks to the fantastic EjTechnologies JProfiler and their much appreciated support on open source effort; here is the profiling result.


As you can see the top two hotspots are the toString() and hashCode() methods on Identity class. Aha~ remember the reflection based builder I have shown you at the beginning of the post? It was used in both of the these methods. But before you are going to tell me "I told you so", I need to explain that the same reflection builder was used in almost every model class, and a premature optimization would result in wasted energy on hand writing these methods for a lot of classes that is no way near the hotspots. Alright enough stalling lets roll up the sleeve and create a kick ass super fast implementation then, but hold on a second I remember the Identity class is a pretty special one. What? It is Immutable! Really? That changes the whole picture. If its immutable instead of computing the hashCode and toString every time we can just simply cache it and eliminate the cpu cost almost entirely. This shows another positive aspect of delaying optimization since the more you delay it the smaller you can pin-point the scope therefore more customized the solution can be tailor which usually means more effeciency. If we had applied a general optimization strategy up-front, most likely it would have resulted in a broad-stroke hand-crafted hashCode and toString for every class strategy, and we would have probably missed this caching opportunity since we were busy hand coding 50 different hashCode and toString. A few lines of code... taa daa ... done. Lets profile it again.


Alright much better now the top 5 hotspots each only contribute to 1% of the cpu time. Lets also fire of the JMeter to see the improvement in action.

GET Throughput Chart


PUT Throughput Chart

36k reads/minute and 12k writes/minute. Hmm... much better write throughput and slightly lower read throughput. Its a bit strange but considering the small test sample size and all the other craps running on my laptop this kind of fluctuation is in the margin, and since I am not really measuring the throughput I dont really care too much. Run all unit test cases, nothing is broken, feeling good and check all the changes in. Now its time to start the next iteration. Took a second look at the hotspot list and some numbers immediately caught my attention - the number of invocation for the top 5 hotspots, they seem to be a bit higher than my expectation. So whats causing all these invocations? Scan through the code and the references, ahaa the debug statement is the culprit this time. Although the debug logging is turned off to mimic production environment, however the statement is still getting executed. We are using Log4j so a regular debug statement looks like this:

log.debug("Something useful: " + object.getValue());

This statement will not produce a log but the string concatenation still happens and getValue() method still gets executed. A common approach to address this kind of performance penalty is to add a Code Guard like this:

if(log.isDebugEnabled())
log.debug("Something useful: " + object.getValue());

This way when the debug is turned off none of the code will actually get executed. Now once again delaying the optimization gave me the opportunity to identify and guard only the expensive debug statement without enforcing everyone to follow this practice throughout the project which is much cheaper and just as efficient. Once again a few lines of code I am done, lets profile it again.


Great! 4 out of 5 top hotspots were demoted to less than 1% cpu time. Alright time to look at it from a different angle now. Lets look at the aggregated cpu time per methods.


Bingo! There is a big cpu hog - JGroupSpace.findSubstancesForLocalNode(). Hmm... make sense this is a pretty expensive computation and it happens every time a PUT or GET operation is invoked. After looking at the code I realize there is already a layer of abstraction introduced to on top of that but it currently does not have the capability to compute the substances for the local node thats why everyone is calling this method to compute everything from scratch at the space level. It makes sense to pull it up into the intermediate layer since we can cache the computation result there when the space is stable and only recompute when member node leave or join the space, and even better the intermediate layer is already getting the notification for this kind of membership change for other functions anyway. Alright sold! thats the plan. Start with some new test cases and refactoring, a few iteration later, done! All test cases pass, a miracle :) Quickly check them in. Profile it again ...



MultiplexMessageReceiver.receive() dropped from 25ms for 4k invokation to 4ms, not too shaby at all. Now lets put everything together and see it in action. Fire up the JMeter!


GET Throughput Chart


PUT Throughput Chart

A whooping 81k reads/minute and 11k writes/minute, so overall reads are 2-3 times faster now and writes are about 20-30% faster. Not too bad for an afternoon session heh? Fire off the integration test cases and nothing is broken, great mission accomplished. My next step is to observe and profile the memory usage pattern to first of all make sure there is no memory leak and secondly optimize the garbage collection behavior. Maybe its also time to put Hydra in a real performance testing lab to find out the actual throughput ceiling.

Stay tuned and Hydra Cache RC1 will be available for download this summer.

Wednesday, March 25, 2009

Implement Harmony Oriented Programming in Hydra Cache: A real world project

In this post I would like to share some experience and lesson we learned when applying concepts and principals inspired by the Harmony Oriented Programming (HOP) in Hydra Cache project. Hydra Cache is an open source project created to implement Amazon’s Dynamo system in Java in order to provide highly reliable and scalable distributed in-memory cache. The system itself is essentially like a giant hash table which gets partitioned and distributed to a number of servers (we call this partition aware server cluster a Hydra Space) and with all servers working together to provide a unified and transparent storage for the client code. One of the core objectives we are tackling in this project is to provide reliable in-memory storage by partitioning, distributing and coordinating all GET and PUT operations to multiple servers hence offering redundancy and enhancing reliability. Let’s look at the following parameters used to describe Dynamo:

  • T – Total number of servers in the space.
  • N – Total number of replica that eventually will receive the replication
  • W – Minimum number of replicas to acknowledge for a successful write operation
  • R – Minimum number of replicas to consolidate for every successful read operation

To achieve reliability each PUT operation invoked on any of the node will be replicated to minimum W number of servers and eventually N number of servers, for example if I store my shopping cart data to the cache when W=3, N=6 then in theory the same data will be at least replicated to 3 servers before the PUT is considered to be successful, and eventually 6 servers. Similarly each GET operation will require minimum R number of servers to cooperate and consolidate the data they have in order to perform a successful reliable GET. Usually a system like Dynamo or Hydra Cache will be configured with the following characteristics T > N > max(W,R) and W >= R to make sense, and when you have W+R > N then you have yourself a basic quorum system which guarantees strong consistency. On the other hand, when you have W+R <= N configuration the system will produce weak consistency (in this case eventual consistency) since it’s not guaranteed to read most recent version written; however unsafe it might sound this is actually a widely deployed configuration when the performance penalty of strong consistency is not desirable when eventual consistency especially during failure can be tolerated, and moreover according to the CAP theorem only two of the three properties Consistency, Availability, Tolerance to network Partition can be achieved at the same time. It is common for large internet based service to sacrifice consistency for high availability and tolerance.

* In Hydra Cache the consistent hashing algorithm and partition-aware client help minimize the inconsistency window when weak/eventual consistency is configured meaning although still constraint by CAP theorem Hydra Cache delivers consistent data most of the time when there is no node or network failure.

While designing the system, initially I experiment driving design directly from this model and found the implementation sort of rigid and lacking of metaphor. Personally I always found powerful metaphor the best help you can get when designing a system, so whenever I code the first thing I do is to search for a metaphor with good fit for the problem at hand. Struggling with the design one speech at the OOPSLA caught my attention. The speech it self is about Harmony Oriented Programming. Although I was not so interested at the programming level, but fascinated about how the idea of basic Harmony Orientation principals and practice can be leveraged as a powerful ally for modeling the reliability framework in Hydra Cache project.

Harmony Orientation Principals

  • Balance – For a HOP system the ultimate goal is to achieve balance (harmony) as a whole. No single member of the system should selfishly perform at the cost of its neighbors. This principal pretty much describes the essence of the Hydra Cache since none of the node should out perform or under perform much comparing to their peers and as whole (Hydra Space) should always maintain the equilibrium even when node/connection failure happens or new node is introduced.
  • Code Fragmentation – In HOP the dominant decomposition of a program is a code fragmentation with minimal encapsulation; in a simplest case a fragmentation could be just a single line of statement. For Hydra Cache this principal perfectly maps to the two core operations the Hydra Space supports GET and PUT both can be simplified to almost a single statement from the client’s point-of-view.
  • Code Positioning - The code positioning principle states that every part of a program is assigned to one and more locations in a virtual space. Related parts of a program are positioned close to each other to form a specific context. In Hydra Space all code (node) are positioned in a consistent hash ring with related nodes positioned close to each other based on their hash value.
  • Information Sharing - The information sharing principle suggests that all data is readable (or can be queried) by any part of the program. This is the core feature that Hydra Cache offers - to be able to query any data stored anywhere in the space from pretty much anywhere.
  • Information Diffusion - The information diffusion principle states that data or a description of the data (meta data) generated by any part of the program is diffused throughout the virtual program space. Data has an associated intensity that decreases the further it is diffused. The concept of information diffusion is expressed in HOP using the concept of substance, which I will illustrate further; this concept maps nicely to the N/W/R values we discussed in the beginning of this post.

Enough principals and dry ideas, now let’s see how HOP (more accurately Harmony Oriented Design - HOD) is implemented in Hydra Cache. In Hydra Cache each server node is considered as a code fragmentation holder that resides in a HOP space, see the following illustration for a 4 server space deployment.

* In this diagram Hydra space is illustrated as a 2 dimensional space however in implementation the space is structured on a Consistent Hash Ring (a.k.a a Continuum) using a well uniformly distributed consistent hashing algorithm inspired by Ketama project, therefore the distance between server nodes as well as the radius of the substances are measured using the difference between each node’s hash value.

As you can see in this diagram Server A emits a substance to include both Server B and D hence any code fragment resides on Server A will diffuse its information to both B and D. In other words, every time when a PUT operation is invoked on A the same operation will be invoked on both B and D. Now it becomes obvious that the size of the substance is the N value, and on top of that Hydra Cache also allow server admin to configure the W and R parameter to fine tune the consistency level. Server A is not the only one that emits substance but rather all servers in the space do, here is a bit messy diagram showing all 4 substances.

Let’s see it in action. Based on the above example the Hydra space would be configured with N=2. To optimize read you can configure W = 2 and R = 1 which means every PUT operation will be only considered successful when the data gets diffused to at least one server (either D or C) in the substance, and eventually reaches both servers (most likely D and C but could be B if one of them crashes during the diffusion). For reads the server will just simply return the local copy since R is 1. As we have demonstrated here these parameters can be a very flexible and powerful tool to tune the space to focus and balance on different priorities: consistency, reliability, fault-tolerance, read vs. write, and performance.

HOD offered an almost perfect metaphor for solving and modeling our problem domain which in return made it extremely effective to communicate our design in human language and code. In our version 1.0 release the Hydra space is implemented through reliable multi-cast using JGroups. If you are interested to know more about Hydra Cache please visit our website http://www.hydracache.org.


References:

  1. Harmony Oriented Programming
  2. Towards harmony-oriented programming
  3. Byzantine fault tolerance
  4. Fault detection for Byzantine quorum systems
  5. Amazon Dynamo
  6. Project Voldemort
  7. Consistent Hashing and Random Trees
  8. Eventual Consistency

Thursday, February 12, 2009

GoEyeball.com

Last year me and my family moved to a new home mid-town Toronto, and among endlessly packing and unpacking we also found ourselves wrapped with a big shopping list; some electronics need to be upgraded and new furniture need to be purchased. At that time because it was almost the Christmas timeframe we did not buy anything right away since we were betting on that some of those items on our wishlist will go on sale for sure during Christmas time. What we end up doing for the next month and so was continuously going back to 6-7 different sites checking the price for roughly 10 different items on my list almost everyday hoping some of them would be on sale. After about a week my wife complained that she spent so much time browsing the web looking for deals everyday, and it would be really cool if a website could allow her to create a robot monitoring those pages for her so she can be freed from this repetitive work and just get notified when the price has dropped. My initial reaction was that's a good idea but there gotta be a site out there does this, but after some research I realized there is actually not a single site that does exactly this.

I found some sites do crowl the web and record prices for different products but they only supports a narrow range of sites so lets say if you want to monitor something on Walmart.ca then you are out-of-luck since they don't support the site. And some other ones only allow users or their sponsors to advertise deals manually so if what you want is not in the deal list then you still have to go back everyday to check. Most of the retail site do not provide this kind of price change notification service since the main purpose of sale and discount is get the customer to browse through the site thus triggering impulsive purchase since the profit margin for the on sale items are slim, its against their best interest to provide service like this. Eventually I decided to create a website www.GoEyeball.com to do one and only one simply thing:

You can create an Eyeball (robot) for a product (on the detail page) on pretty much any site and getting notified when the price drops below your threshold.

We launched the beta version of the web site this week. Its completely free of charge and free of advertisement. Come check it out and let us know what you think. In the next a few posts I will share some of the creative ways our users have figured out how to use the site, and you are always more than welcome to let us know your findings and experience.

Wednesday, January 07, 2009

Exception vs. Error Code - round 2

This post is a follow up of my previous post on the same topic Exception vs. Error Code - round 1. Here I would like to discuss what Uncle Bob and other Object Mentors' view on this topic which was explained in the their book Clean Code.

First of all their view is definitely pro exception, and the two major reasons given against returning error code were:

a. Returning error code is a subtle violation of Command-Query-Separation (CQS) principle. (page 46)

Take a look at the following code sniplet:


if(connection.close() == IO_ERROR){
handleIoError(connection);
}


The close() method is clearly a command but by returning the error code this method offers both query and command style invocation thus violates the CQS principle.

b. Returning error code clutter the caller code and since its easy to miss handling certain type of error code therefore it is also error prone. (page 104)

This point is consistent with Kent Beck's view which I have discussed in the previous post.

As Unble Bob mentioned programming is sort of like martial art. Different master will form their own style and some one can choose to practice certain style exclusively or a mix of styles, but when certain practice is criticized by more than one master then you better take it seriously and rethink your practice because there is probably something wrong with that.