Jazz platform development
Like many "knowledge workers" these days, I primarily work from home, dialing into conference calls and connecting to IBM's intranet via a virtual private network (VPN) client.
This has some advantages, e.g. you save time driving to and from work and you save money on lunches and coffee.
But sometimes it's challenging.
The other day I got a box in the mail containing the Xbox video game "Star Wars: Knights of the Old Republic II: The Sith Lords" (which I naturally bought on the web in used condition for 35% off retail).
One of the advantages of working on site is that you don't have to walk by your HD TV and your Xbox and see the case of the new video game you just bought staring at you saying, "Play me Bill. Just for a few minutes. No one will notice. Just leave a message on Sametime that you're on a call".
But this path leads to the dark side. For even though I'd only intend to play for 20 minutes, soon it would be an hour, then two, and pretty soon I'd be writing my farewell blog entry.
bhiggins at us.ibm.com[Read More]
One week until I leave China and head back to the US. Today I got sort of stranded at my brother-in-law's house. It's too cold to go outside and I somehow forgot all of my books and my journal at my parent-in-law's house. No one else is around, so I find myself with the following options:
Well, if you're reading this you've figured out which of the above options I chose. Because reading news articles and technical articles gets tiring after a few hours, I decided to look for something a little more meaty. I found it in The Art of Unix Programming by Eric Raymond, which is available to read online.
The book is really interesting and has many insights that I wasn't familiar with, which is unusual, since most books on computers tend to hit 80% of the same well-trodden topics and stories.
The book is pretty hostile to Microsoft (in a very one-sided manner) which may be a turn-off to some readers, but I guess I just look at it as the artistic license of a true believer.
One part that I've found particularly interesting is the write-up on the Unix maxim that "silence is golden"; i.e. if your program doesn't have anything interesting to say, then don't say anything. This was one of the "features" of Unix that really caused me problems when I first started programming at Penn State University. I never knew what the hell was going on because the command-prompt would say nothing, whether I simply moved a file or accidently overwrote a programming assignment due the next day (which is funny ... in hindsight). Reading Raymond's arguments, I think that the "silence is golden" rule holds up somewhat better in a command-line world than in a GUI world. In a GUI world there are many subtle mechanisms to provide feedback without being obtrusive about it.
On a related personal note, my technically-proficient wife sometimes calls me "Mr. Unix" because I occaisionally forget to provide re-assuring "uh huh"s to statements she makes that I don't disagree with.
PS - I would personally pay $100 to watch Raymond and Donald Norman debate the merits of software providing constant feedback to the user. But perhaps "celebrity deathmatch" would provide a more appropriate forum.[Read More]
I said in the last post that I was going to review Bruce Schneier's book Secrets and Lies which is Ted Neward's (and now my) essential primer on digital security.
Schneier introduced me to the term "countermeasure" which is simply some mechanism that either attempts to prevent or effectively respond to a security incident.
I had to think of this while watching Weird Science (the movie) on cable this weekend. For those of you who weren't a young boy in the 1980s, Weird Science is about a couple of high-school nerds, Gary and Wyatt, who use their computer skills to create a woman they name Lisa who has supermodel looks (played by Kelly LeBrock), magic powers, and who will do whatever Gary and Wyatt want her to do (yes, this was a movie squarely targeted at adolescent males).
They create her through a computer program that simulates the creation of a woman, both physical and mental characteristics. They hack into a government facility to get more computer power, wire a Barbie doll up to their computer and voil, there she is.
Anyhow, it's a movie worth seeing, if only for the performance of Bill Paxton as Wyatt's incredibly obnoxious brother Chet, but the reason I mention it here is because of something to do with computer security.
As mentioned before, through a circa 1985 personal computer, Wyatt and Gary hack into a government facility to "steal more computer power". Ok, fair enough. But what was really cool to me then and hilarious to me now was the government system's response to being hacked. I have never attempted to hack a system but I imagine that if you got user access to a computer you hacked, you would either see a command prompt or a typical Windows / Linux / whatever GUI. But not the government computer that Wyatt hacks. When Wyatt bypasses the security program he is treated to a vivid artsy display of 3-dimensional graphics including freaky faces and whirling clocks - sort of suggesting that they've entered a secret wonderful computer world that they didn't know existed.
I realize that this is a movie so I'm not criticizing it for not being realistic. It's just that after working as a programmer it's funny to imagine a scenario that would lead to the existence of such a "feature". Say you're a system designer for the National Security Agency (NSA) and security is of utmost importance. You're in a meeting discussing what should be the response to a system security breach.
I wonder if the NSA sub-contracted to a graphics programming shop to improve the quality of the break-in graphics? And what was the budget to design and implement said graphics?
Ah, movies that involve computer programming are funny. But I guess in a movie that's based on the premise that using 286 PC, a modem and a Barbie doll, you can generate a living breathing woman resembling Kelly LeBrock who can perform magic ... then in comparison displaying fancy graphics in response to a security breach is pretty believable!
Then again, Microsoft Excel 1997 included a hidden flight-simulation video game, so perhaps it's not so far-fetched to have such a feature![Read More]
Warning: for the experienced software engineer, the following may be a long-winded explanation of the blindingly obvious; it is more intended for people newer to software engineering.
In software engineering you often find yourself talking to another designer or programmer to learn more about some system you either have to work on or use. This is often difficult because the designer / programmer has been working with the system so long and he has spent so much time with the system that no longer thinks in terms of "why" the system does things or "what" it does, but rather only in terms of "how" it works.
This is usually fine within a tight development team because they've been working together for a long time and have a shared implicit context of the "why's" and can therefore talk in terms of "how's" without getting lost in the forest.
A trivial but useful example of this is making coffee. If my use case was "make a pot of coffee" here are three different levels:
why: "I'm a little tired and need to get more work done".
what: "Make a pot of coffee".
how: "Grind coffee beans, put coffee beans in filter, put water in tank, hit 'On' button".
Say I started grinding beans and for some reason my wife in the other room didn't recognize the noise - in reality she would because she's heard it enough. But for the sake of this blog she says "what is that noise?" and I reply "I'm grinding coffee beans!". She implicitly knows the "what" (that I'm making coffee) and probably doesn't think about the "why" (that I'm tired, because I drink coffee even when I'm not tired). This is because she has a shared context with me. If she was one of the five English-speaking humans on Earth who had never heard of coffee, just telling her that I was grinding coffee beans would leave her equally clueless.
Where is this going you may be wondering?
Well this is something I struggled with mightily. Reading all the books on software design a common theme kept popping up in a couple of different guises:
In other words people would always make the point that if you're either writing a specification or programming against some service or library, think about the "what" and try to ignore the "how".
But this always seemed arbitrary to me because any process or activity can be decomposed almost ad infinitum. For instance, if I decide to make a pot of coffee that answers the question "what will you drink?" but does not answer how I will get it. I decide to make myself coffee although I could also go buy a cup of coffee from Barnes and Noble (more on that later). But now that I've committed to this "how" I need to come up with a couple of concrete "what's" to end up with a pot of coffee. This is where the decompositional aspect comes in. The first what is "grind coffee beans". This is now a "what". But how are the coffee beans ground? I really don't know. I put them in this device, push a button and magically they become coffee grounds. This is a key insight. I don't care "how" the coffee is ground because I don't have to do it. I have a machine which provides the grinding service for me as a black box (well in reality a white cylinder).
So the truth is that any process (in the business sense) or procedure (in the computing sense) can be rolled up or drilled down as much or as little as you like. The hard part if you're a software or designer is "What level do I expose to other programmers who will use my service or API"? You could but shouldn't tell them not only what your service does but how it does it. The negative consequence of this is that the is typically arbitrary from a functional perspective and at some point you may wish to change how you do it for non-functional reasons (e.g. better performance, more robust security, etc.) But if you've published your implementation to the world, people may have coded to your service with assumptions about that implementation in mind and therefore changing it might break them.
So now you can happily agree that you should not let implementation details bleed through either your API specification or use case specification.
Happy? No. Because how the heck do you determine what level of decomposition your specification should be at?
I didn't know the answer to this for a while but it turns out it is pretty simple. Simon Johnston explained it to me during a mentoring session on business process modeling and its relationship to use cases. He was drawing a simple use case diagram on the board and making a point about only stating "what the system does not how it does it" so I went off on the same spiel above about how a "what" is just a higher-level summation of a bunch of "how's". And then he said, "well, you determine the 'what' by asking 'what does the actor care about?'".
It turns out that this whole thing is subjective and there is never a definitive answer. It all depends on the nature of who is using the service. Back to the coffee example. Say my wife asked me for a cup of coffee. Her desire for drinking coffee is the 'what' and she delegates to me how it is done. My 'what' is now procuring coffee for her. She doesn't care if I make it or drive to Barnes and Noble to buy it. I decide to make it and so now I also have to care about 'how' it is made. My first 'what' in the making process is 'get coffee grounds'. Since I have beans I need to grind them and since I have a coffee grinder I don't have to worry about how this grinding is accomplished.
It's the same in programming or use case writing. Depending on what your goal is, you may have very different levels of specification vs. implementation. Specification is the what, and implementation is the how. If you're responsible for an implementation, you will come up with a design which will leave you with a new set of what's that need to be further decomposed, perhaps by your own code, perhaps by a Java library class.
You can navigate these levels with the following tools:
The point is that whenever you're either writing code that other people might use (i.e. an API) or if you're drawing a use case diagram to say what a system does, think in terms of what the client / actor / user (whichever term is relevant to you) is trying to do - his goal. That is the magic formula for figuring out what the right level of detail is to create a specification that omits unnecessary implementation details.
These set of principles are what underlie the object-oriented notion of "polymorphism" which is the big impressive jargon word which basically means that some specification may have different implementations but you don't care because you're happy with the behavior specified by the more abstract type.
In Java a good example of this is the Collections framework. If you write a method that needs to return a collection of non-duplicate elements but don't really care about anything else, you should return the Set interface. Inside your method you may implement it as a HashSet or TreeSet or whatever suits your needs, but since you haven't shown this implementation to your client, you can change it at a whim.
There's more to it, but that's more than enough for one blog. For the two or three of you who have survived my rambling this long, I offer to provide you with a hot cup of fresh coffee if we should ever meet in Raleigh-Durham. But I refuse to specify whether I will brew it or buy it for you :-)
PS - Later I found that Alistair Cockburn talks about this very thing in his excellent book Writing Effective Use Cases under the section "Raising and Lowering Goal Levels" on page 69.
PPS - Dave Parnas wrote the seminal paper on this topic way back in 1972. You can read a copy of it here (note parts of it are now pretty low-level and hard to understand). As Bass and Clements say, "if you think you've thought of something new in Software, you should first check Parnas's stuff to make sure he didn't already think of it back in the 1970s".
PPPS - This idea is also found in the Strategy design pattern which can be found in the ever-popular book by Gamma, Helm, Johnson and Vlissides.[Read More]
billhiggins 1000006JUS 287 Visits
I'm working at home today and had CNN on in the background. At 1:46 PM Eastern US time, CNN announced that CIA Director Porter Goss is resigning. Just for fun, I immediately went to the Wikipedia entry on Porter Goss. It didn't mention his resignation. A couple of minutes later I hit refresh and it was updated to reflect that he was "a former CIA director". I looked at the version diff and it turns out someone updated Wikipedia within 2 minutes of the news breaking.
I know Wikipedia often catches flack from people like Nick Carr who lament spotty content quality, but I am still amazed that there's a valid encyclopedia that can be updated within two minutes of a surprise announcement. When I was little growing up in Hershey and Harrisburg Pennsylvania, for the longest time we had a 10 year-old set of Encyclopedia Britannica, and I remember thinking that was pretty cool!
My kids are definitely going to laugh at me some day... :-)
- Bill[Read More]
I've written a second article on Ajax, this one titled "Meeting the challenges of Ajax software development". Here's an excerpt:
The newness of the Ajax/REST architectural style presents challenges to organizations that have traditionally used the server-side Web application style. Though Ajax has several compelling architectural advantages over the traditional model, an immediate and total transition to a pure Ajax/REST architecture isn't realistic for all organizations. Those that lack Ajax development skills can begin their Ajax exploration by incrementally adding Ajax functionality to existing server-side Web architectures. As these organizations begin to gain experience with Ajax/REST, they can confidently attempt more interesting and ambitious projects.
As always, if you have any comments or questions on the article above, I'd appreciate if you would leave a comment to this blog entry. I'm really interested to know if other folks who have developed Ajax applications agree or disagree with the judgements and conclusions of this article.
PS - If you haven't read the first Ajax/REST article, I provide an excerpt and a link in this older blog entry[Read More]
In my last post I went through a long-winded explanation of how to enable and disable capabilities within Rational Application Developer (RAD) and Rational Software Architect (RSA). I notified Emeka Nwafor, product manager for RSA, about the blog and found out from him that there is a much simpler (and ingenious!) way to enable/disable capabilities.
When you launch RAD/RSA (or any of the other products listed below) go to the Welcome screen (Help -> Welcome). In the lower-right hand corner of the Welcome screen, you'll see an abstract icon of a person, with a number of smaller icons to the left of him. If you put your mouse over this little man, you'll see text to "Enable Roles". Click the little man icon and you'll see a number of possible roles that you can enable. One of these days we'll be able to post pictures on our dW blogs and I'll be able to show you these things!
A role basically corresponds to a set of capabilities that are required by that role. The roles are very self-descriptive ... e.g. "Requirements Manager", "Modeler", "Java Developer" etc. Often a person plays multiple roles in their work, so simply enable the roles that you play and disable the roles that you don't play. The whole "capabilities" discussion gets abstracted away.
This is a really, really cool feature, which greatly improves "user experience scalability". The only shortcoming of which is its somewhat inconspicuous location on the welcome screen. Emeka's looking into perhaps getting the role-enablement/disablement function a more visible place in the RAD/RSA real estate.
I have to give a complement to the user-centered design practice within IBM which have really changed the way we design products, internal systems and customer systems. When I look at RAD/RSA v6 and think about the way I initially struggled with WSAD v4, I am really impressed by the gains we've made in usability - keep it up folks!
This makes me think that I really have to post on user-centered design in general ... an area I've been studying more and more lately and have come to appreciate as much as technical architecture and design.
Update! Here's a screenshot. Hosting courtesy of ImageShack
Role enablement widget in Rational Software Architect welcome screen[Read More]
I just read and really appreciated Nicholas Carr's blog entry "The amorality of Web 2.0". Like Carr, I get very uncomfortable when I read Tim O'Reilly and others speak of Web 2.0, or just the web for that matter, in quasi-religious language.
Is the web a culturally-transformative phenomenon? Undoubtedly. Should we try to assess this phenomenon objectively? Absolutely. Should we approach the web like religious zealots? Perhaps only after many, many beers.
I must admit, it's nice to read a fellow Web 2.0 skeptic - it seems that many of the bloggers I read are almost obsessed with Web 2.0, and it makes me feel uncomfortable to read it.
But then again, for the last eight years up until May, I was obsessed with the new Star Wars movies, so who am I to judge? :-)
contact me: email@example.com[Read More]
So having used RSS for a few months, here's the three styles of feed items I've noticed, ordered by how much I like the style, descending:
I understand the business motivation to force readers to click a hyperlink to view a full entry - it's the most straightforward way to measure relative and absolute interest in your entries. But sometimes the "summary" sent via the feed is not so much a summary as a vague excerpt. Maybe it's just me, but frequently reading the short form of a blog entry, there's not enough there to even determine if I should follow the link and read more.
But then there's the Fast Company "quote summary" which is truly in a league of its own. Here are a few recent (real) examples:
The New Lure of Internet Marketing
"What better form of personalization is there than hearing something from a friend?"
-Scott Griffith, CEO, SoftLock.com
The Man From CHAOS
"Americans like reorganization. They don't like technology."
-Richard Morley, Founder, Modicon
Are You Being Coached?
"Figure out what behavior needs to change and how to change it."
-David Thomson, Vice President, Hewlett-Packard
So you can see the pattern emerging:
Uninteresting, sometimes unrelated, title
Underwhelming quote with two instances of bold.
-Name of person I've not heard of, title, company
As I become aware of this pattern in the Fast Company RSS feed, I went through the following phases:
If you want to share in the fun of the occasional Fast Company quote summary RSS item, you can subscribe here.
-Bill Higgins, frustrated blog reader, IBM
billhiggins 1000006JUS 300 Visits
A couple of weeks ago I wrote about the Genographic project that aims to understand the paths that the human race took from our origins in Africa to migrate and populate the world.
A few new items:
According to a recent internal report, 6,000 IBMers have participated in the Genographic project so far. Anyone, IBMer or not, can participate, so if you'd like to, go here.
CorporateBlogging.info has a short article discussing IBM's internal blogging system, including a couple of screenshots. Unfortunately it didn't include the logged-in view of the internal blogs, which shows a personalized view of recent posts, responses to posts, and responses to comments.
As I mentioned last week, our internal blogging system runs on a customized (and horribly backleveled!) version of Dave Johnson's Roller blogging software.
Thanks to Michael Lowry of IBM Sweden for the heads up (via his internal blog of course!).
Update: James Governor of RedMonk posted some commentary on my comment about IBM using backleveled Roller software internally. James Snell and I commented with some additional context.
Technorati: corporate blogging, ibm blogging
I've been working on an article for developerWorks discussing the architectural advantages, particularly with regards to scalability, of a pure Ajax/REST architecture to support immersive web applications. To back up my argument, I finally read Roy Fielding's famous dissertation "Architectural Styles and the Design of Network-based Software Architectures" which coined the term REST and explained how a RESTful architecture leads to extremely scalable applications.
About three-quarters of the way through the thesis, a small footnote pointed to a web site that allowed me to claim a free "I read Roy Fielding's whole thesis and need some REST!" t-shirt. According to the web page's counter (not very RESTful!) I was only the fourteenth person to claim the free t-shirt.
There are still a few left, though the XLs are going quickly.
Disclaimer: the dry humor in this blog entry is my own and doesn’t necessarily represent IBM’s positions, strategies or opinions.[Read More]
billhiggins 1000006JUS 347 Visits
I want you all to know that we have been listening and have recently made some great fixes to our engine to improve the garbage collection routine and to reduce unbounded memory growth.We're simple folks here at IBM, and we normally refer to IE's "unbounded memory growth" behavior simply as a memory leak :-)[Read More]
Friend and colleague Tracy Giles recently turned me on to Firefox's Adblock extension which allows you to very simply remove image and Flash advertisements from web pages.
I realize that this technology is controversial, since it enables users to deliberately circumvent the ad-based revenue model that many sites follow. If you want to read a commentary on this controversy, read this article from the Guardian. I'd like to write about something different.
Before I got Adblock, when I went to a web site, my mind seemed to subconsciously block the ads by immediately locating and focusing on the site's real content. The ads were still there, but they were background noise. Now that I have Adblock, I can permanently remove an ad with two clicks. The interesting thing is that this ability has caused me to look at each ad more closely. The reason is that in the past, for every thousand ads that I'd ignore, I'd see one or two interesting ads and click-through. Now that I have Adblock, I look at every ad for about two seconds before blocking it, just in case it's interesting. Because once I block it, it's likely not coming back, so I better make sure that indeed I want it gone.
contact me: firstname.lastname@example.org[Read More]
billhiggins 1000006JUS 1,650 Visits
... is here. Your brain must be able to follow five concurrent interleaving conversations for it to make any sense :-)
In summary I thought it was lots of fun and I think there was some good knowledge sharing, though I must admit everyone on the chat was already sold on Ajax, so there weren't any good food fights. The chat was run using an IRC-like Ajax chat client, and I must admit that I was half expecting it to die/crash midway through the chat just because we were all talking about how great Ajax is. But thankfully it worked just fine (thanks dW folks)!
We had good representation from IBM Rational (Grady Booch, Josh Staiger, Richard Backhouse, Jonathan Ellis, Matt Lavin, myself, others), WebSphere (Jared Jurkiewicz, Pat Mueller), Dojo (Adam Peller), the Eclipse Ajax Toolkit Framework (Bob Goodman, Gino Bustelo), Redmonk (Coté, Anne Zelenka), and several folks from IBM developerWorks, among others. Thanks so much to everyone who joined the chat.
A reminder that Grady will be hosting a chat later today (Thursday, 7 December) on the new Rational products that GA'd on the 5th. I will likely be there unless I end up having too much fun at the annual IBM holiday social. Re: the new products, Simon Johnston of Rational talks a bit about them here.[Read More]
I'll be hosting a live chat on Ajax on IBM developerWorks, Wednesday Dec. 6th at 1pm Eastern US time. Please join if you're interested in Ajax - whether an experienced developer, somone considering Ajax for your project, or just curious what the heck Ajax is.
I believe you'll need to have an IBM ID to join the chat (sorry!) - you can get one here. The process is pretty painless these days.[Read More]
I've been working on some Ajax stuff lately and this morning I was complaining to patterns guru Erich Gamma that I hadn't seen any good design pattern resources for Ajax. He pointed me to this site which looks good:
Would have never guessed that one!
- Bill (email@example.com)[Read More]
The article I recently wrote on the architectural issues of Ajax and REST is now online. Please note that this article only talks about runtime matters; I'm working on an article for next month that covers development-time and maintenance issues of Ajax applications. Here's the intro:
The more that server-side Web applications become immersive by following rich-application models and delivering personalized content, the more their architectures violate Representational State Transfer (REST), the Web's architectural style. These violations can decrease application scalability and increase system complexity. By achieving harmony with REST, Ajax architecture lets immersive Web applications eliminate these negative effects and enjoy REST's desirable properties.If you have any comments or questions on the article above, I'd appreciate if you would leave a comment to this blog entry.[Read More]
Alan Brown posted some comments of the "Software Factories" book, written by Microsofties by Jack Greenfield, Keith Short, Steve Cook, and Stuart Kent.
I agree with Alan's comments. It's a really informative book that provides a thorough summary both on the evolution of software design styles over time and on the process of design. But the authors' tone when speaking about UML and MDA is way too negative for my taste. Still, in my opinion, this book is worthy of your money for the first couple of chapters on software design.
It's going to be really interesting to see the responses by the authors on their blogs over the ensuing days. This ties back to the whole "UML vs. Domain-specific Languages debate" which I mentioned a while ago.
After a two month hiatus, Alan Brown is blogging again.
Alan's in charge of model-driven development strategy for Rational and used to work for the Software Engineering Institute (SEI) at Carnegie Mellon.
He wrote a good book called Large Scale Component Driven Development that is the first source I can find that mentions service-orientation, though there is probably something before that.
Also, he and Grady Booch co-authored a really excellent paper on Collaborative Development Environments that is driving a lot of my work these days.
Anyhow, check it out - he's got some really interesting things to say.[Read More]
I've got exactly four work days until I go on vacation for the rest of 2006. My vacation will be of the nice, relaxing, hang around kind, so hopefully I'll do a little more blogging than I have in the past several months (kids + Jazz + sleep = not much time for blogging).
I've been slowly working my way through an excellent book that Grady recommended a long time ago called How Buildings Learn by Stewart Brand which discusses how buildings change over time and considerations for building buildings that wear well.
Anyhow, you probably guessed that I'm going to draw parallels between Brand's book on building architecture and my profession of software development. Naturally I see lots of parallels - surely some real and some imagined :-)
I want to quote something from page 63 that to me perfectly explains much of my views on software design, and why trying to get everything right up front is not feasible.
Chris Alexander likes to make on-site adjustment to a building as it's being constructed. "Architects are supposed to be good visualizers, and we are," he says, "but still, most of the time we're wrong. Even when you build the things yourself and you're doing good, you're still making nine mistakes for every success. So you take the time to correct them. The more at each stage you can approach being able to experience the contemplated reality, the more it will give you feedback and you'll be able to intelligently develop it".
I think the key sentence is (sadly) the one that's most difficult to comprehend. To repeat:
The more at each stage you can approach being able to experience the contemplated reality, the more it will give you feedback and you'll be able to intelligently develop it
This is talking about the different between an abstract and concrete understanding of a design and how you can only make good decisions until you've descended from 50,000 feet, gotten your hands dirty, made some mistakes, and re-evaluated your design with the benefit of concrete experience. See also my post "Coding to Learn".
More on How Buildings Learn in future posts.[Read More]
I was on Amazon.com the other day and noticed that their URLs have changed. In the past, Amazon book URLs looked like this:
There's usually some application gorp appended to the URL above, but at it's essence, it's a well-designed RESTful URL that uniquely identifies a book resource by ISBN number. Although these URLs have the nice property that you can email a link to a friend and he or she can click on it and view the book, they had the not-so-nice property that (unless you've got Rainman-like ISBN memorization capabilities) it was impossible to determine the book identified by the link just by looking at the link.
So the other day I noticed that Amazon's book URLs now look like this
Now human-readable information about the book is embedded in the URL which means that if I have a list of URLs, I can quickly recognize what they are, e.g.:
Now interestingly, if you chop off the ISBN-part of the URL and paste it in a browser - e.g. http://www.amazon.com/Weaving-Web-Original-Ultimate-Destiny/ - the link no longer works. So it appears that the inclusion of the book information in URLs is intended purely to provide meaning to humans. This is a very nice feature.
Disclosure: I own Amazon.com stock, though I don't expect my pointing out this new URL feature to significantly affect the stock price. :-)
Update: Gunnar Wagenknecht comments: "Hehe, I'm not sure if providing meaning to humans was the reason for that enhancement or providing meaning to search engines. ;)" Good point Gunnar![Read More]
On Christmas Eve I was in Shanghai with my wife, and we met two of her old high school classmates for dinner. It turned out that one of them works as what I'd consider a business / systems analyst for a Chinese firm that does custom software development for the telecommunications industry in China.
During dinner we started talking a little about software development. It turned out that his group gets quite a few jobs subcontracted to them from IBM China, so he's quite familiar with WebSphere Application Server and Rational Application Developer.
Another thing he mentioned was that he found requirements gathering difficult. He mentioned that it's challenging because there are always different stakeholders across the customer's company which leads to problems such as:
Sound familiar? It's really interesting to me that although we come from two very different cultures, the same exact problems pop up during requirements gathering.[Read More]
billhiggins 1000006JUS 314 Visits
Grady Booch posted tonight about a very serious personal matter.
It's amazing how easy it is to start viewing work as so important and all-consuming, then hearing about truly important things like the southern Asia disaster and now Grady's news - it's like a slap in the face from real life.[Read More]
In response to my Ajax/REST article, Frank Staheli asked the following questions:
1. Can AJAX still take advantage of back-end database connection pooling (a huge disadvantage of client-server graphical apps, that they couldn't)? I would think so, but I'm not sure.
There is no conflict between the Ajax/REST architecture style I described in the article and database connection pooling. In fact if you're using J2EE, you can use pretty much any current J2EE facility you want, with the exception of JSP/JSF, which aren't necessary if you're doing pure Ajax/REST (although they are still relevant if your web app's a hybrid).
2. How does my AJAX app handle a server crash? Because would the readystate not change with no response from the server? Would the connection eventually time out?
First of all, I don't mess around with low-level XHR stuff. I prefer to use higher-level frameworks like Dojo or Prototype which provide relatively abstract Ajax request invocation libraries - which do time out after a period of time (and I believe this may even be user configurable in Dojo) and calls an error callback function which you control.
So how you deal with this error is purely a matter of user experience design. First remember that the only "critical time" where a server crash should affect a user is if the server is down when the user performs a gesture that causes a remote Ajax request to fire (or if a the Ajax app sends a background remote request - more on that later). With that in mind, also remember that a user using a web browser spends probably 95% of their time not interacting with the app but rather just looking at what's on their screen, so 95% of their time they're not invoking remote actions. It's entirely possible that the server could hiccup and come back between user interactions, and the user would be none-the-wiser (assuming a stateless server, which I strongly recommend).
One other corner case - many Ajax apps perform background requests that aren't caused by user interactions (e.g. Gmail checking for new mail). If one of these background operations fail because the server isn't responding you can either choose to fail silently or warn the user that the server's down. You should fail silently if there's no chance that the user may lose work if the server's down. E.g. if your application's relatively read-only, you may as well wait to notify the user of a server problem until they perform an explicit action that requires server responsiveness since the server may come back before the user performs that action. If your application allows the user to create data (e.g. sending emails, filing bugs, etc.) you may want to proactively warn the user that there's a server problem and they won't be immediately able to save any data they enter until the server comes back online (this is another great use case for 'ping server to determine when it's back up' user experience described above). If you're REALLY on the cutting edge, you can use something like dojo.storage that can store data locally for later remote replication, but this requires that the user have Flash installed, which has some consumability implications.
- Bill[Read More]
I've been implementing some REST services recently and I'm finding that I'm a bit in the dark when it comes to message design. The syntax of XML is straightforward, but what are the patterns to produce messages that satisfy your key application priorities (e.g. performance, scalability, maintainability, etc.)?
I can't find any good books or web sites on message design for distributed systems. Ted Neward's discussion of context completeness in Effective Enterprise Java was very good. Bobby's EIP book certainly talks about the mechanics of message systems and Martin Fowler's PEAA book talks about design considerations re: levels of granularity and such, but I have yet to find one book on message design vs. the 10s of great books on object design.
Any suggestions on books, articles, papers, or blogs on considerations for message design? Post a comment or email me if you don't feel like doing the developWorks registration thing.
And with that, I'll end my blogging extravaganza for this evening. Tomorrow it's heads down in more coding and radio silence on the blog channel again for a few weeks.
- Bill (firstname.lastname@example.org)[Read More]
As you may have heard :-) Apple has decided to use Intel chips rather than IBM chips in their desktops and laptop computers.
A natural response is to go into damage control mode and enumerate the reasons why this isn't a big deal for IBM, but I don't think that will serve any useful purpose, since everyone would see it as not honest discussion but rather... well... damage control.
So, as an IBMer, I'll simply thank Apple for their 10 years of collaboration, congratulate Apple and Intel on their new partnership, and wish them continued success together in the future.
Let me take the rest of this post to say some positive words about Apple:
PS - Congratulations to Paul Thurrott of WinInfo for breaking this story many, many weeks ago.
4:55 PM EDT update: Just read in this press release that Mac developers will have to pay $999 for a "Developer Transition Kit". That is not cool.
billhiggins 1000006JUS 397 Visits
I've been thinking recently about patterns that lead to good software. Not necessarily design patterns, but any sort of pattern.
One that I've thought of (that likely has been documented elsewhere) I call "application begets framework". This pattern basically states that all things being equal, great frameworks emerge from concrete applications, rather than being created out of the blue. A few examples:
Ruby on Rails - While various Java- and .NET-based web application frameworks have muddled along for years, Ruby on Rails in just two years has achieved massive mindshare and (as far as I can tell) rapid adoption across the industry. As the wikipedia entry mentions, it was "was extracted by David Heinemeier Hansson from his work on Basecamp, a project-management tool by 37signals."
The Eclipse Platform - The core Eclipse platform was designed while partnering very closely with Erich Gamma's team who was building the showcase application on top of Eclipse - the Eclipse Java Development Tools. Indeed the core platform was so strongly influenced by JDT (and the basic requirement to be an extensible IDE) that later, for version 3.0, the Eclipse team had to perform a major refactoring to separate a generic "Rich Client Platform" framework from the IDE-specific concerns.
I'm sure there are other examples but these are the best two that I can think of.
I believe there are two basic reasons why good frameworks must be extracted from real applications rather than vice versa:
Concrete to generic
I'm not a student of the human mental process, so this is just based on my experience and observations of software projects; people generally tend to succeed when they are focused on implementing a set of very real user scenario, preferably with the users providing rapid feedback. Occasionally you see parts of the code becoming somewhat redundant, and at that point it's relatively easy to generalize the code into a simple library or perhaps something framework-y. This also comes back to the basic agile mantra "you ain't going to need it". How many thousands of hours have been poured into uber-flexible, generic design patterns, with no particular need in sight?
Another benefit of beginning with concrete problems is that you may actually fail several times until you find a solution that works. But each time you fail, you learn something about the nature of the problem that you can take into consideration if you want to generalize things later. If you start off general, you may stroll very far down hopeless paths but never get the concrete feedback of unhappy users or code smells until after you've spent many hours and dollars on the hopeless design.
Constraints are good
As I write this, I realize that I'm just making many of the agile arguments in a particular scenario, but still it's worth thinking about next time someone asks you to consider a fancy new framework - just ask how it came into existence and who you can talk to who's used the framework successfully on a project similar to yours. If you get a blank or nervous stare, be wary.
Finally, it would be interesting to discuss how this principle is being applied by the Jazz project, but I'll wait until after programmers and the marketplace have a chance to judge its success.
- Bill[Read More]
I read this article on the Onion and had to laugh because recently I've been on a book buying binge; I get one in the mail and start reading it. One week later a new shipment shows up and I throw down the old book and start reading the new book.
The last book I completely finished was Extreme Programming Explained, 2nd Ed., because I had to write a book review on it (coming in this month's Rational Edge around the 15th).
Here's a list of recent books that I've started but not completed:
I've been making some good progress on The World is Flat, the Jack Welch book and the history of the Internet book, less so on the others :-) The Women, Fire, and Dangerous Things book is a cognitive science book dealing with some (relatively) new thoughts on how humans form categories. It's very fascinating and I'm going to try to hit that one hard next.
PS - For those not familiar, The Onion is a satirical newspaper so don't be surprised if this story or any others seem bizarre if taken at face value.
Goran Begic of Rational and I recently co-wrote an article on Code Review, a new set of static analysis functionality in RAD/RSA that validates your Java code against industry best practices. Note that the best practices are implemented as rules, so RAD/RSA ship with several hundred best practices/rules but you can also define your own through the extensibility mechanism.
Anyhow, check it out if you're interested. Feedback, via blog comments or email, is very welcome. I'll write more on my involvement with Code Review, which actually goes back several years to earlier technology out of IBM Research, in a future blog entry.
1:40 PM Eastern update: I forgot to mention that new IBM blogger Wayne Beaton recently posted a blog entry on Code Review that may be interesting to folks who are interested in the article above.
PS - I have a few more book reviews coming in the March issue of the Rational Edge which should be online within the next couple of days. This month I review Secrets and Lies (recommended book for February) and Requirements-led Project Management.
CNET has an article on the transition of IBM's PC Division from IBM to Lenovo. The "separation" part is what I'm working on; after PC Division is separated, I won't be working with Lenovo or PC stuff.
I've written an article for this month's issue of the Rational Edge. It's titled "Ground rules for managing business process integration projects". The full issue contents are here.
The reason I wrote this article is that I've worked on several really large business process integration projects over the past couple of years (ibm.com Direct, IBM-PC division separation) yet most of the writing on software engineering I find is geared to either single-app development, or at best, point-to-point integration of apps. What I want to read about is the pragmatic unification of the business process engineering and software engineering disciplines. This article tries to scratch the surface of this massive topic.
Comments, questions, and criticism are all welcome, whether you think it's genius or whether you think it's hogwash (or likely, somewhere in between). Please leave your comments here, so that others can see them (the ones submitted via the article form go into some ibm.com void).
PS - I see that Simon Johnston also has an article on "Modeling service-oriented solutions" which may interest people.
contact me: email@example.com[Read More]
billhiggins 1000006JUS 292 Visits
This is really funny - the BBC accidently interviewed a cab driver, thinking he was a technology expert re: an Apple lawsuit. The cabby didn't know what was going on until they introduced him - watch the expression on his face. You have to give him credit for keeping his cool and trying to BS his way through it. Via Kim VedBrat.
- Bill[Read More]
I've only posted about twice in the past five weeks. The reason? Well, I've been busy preparing for a new child!
My wife Chunhui and I welcomed our second child to the Earth on Wednesday morning here in Raleigh. We named her Diana Yang Higgins (Yang is my wife's maiden name). She was huge! 10 lb. 13 oz. (4.9 kg) and only a couple of days overdue. She's adjusting well to her new environment and I'll be off the next couple of weeks to help. Our first child, a 2 1/2 year old boy, is dealing very well with his baby sister who he calls Mei Mei (Chinese for little sister).
So now that all of the prep is done and the baby's actually here I should have lots more spare time ;-)
- Bill[Read More]
Last night, the family and I got back from a relaxing vacation in Big Bear Lake, California which is in the mountains about 100 miles east of Los Angeles.
Some facts, highlights, and observations from the vacation:
All and all, an enjoyable and needed break from work. I'm refreshed and ready to hit it tomorrow!
contact me: firstname.lastname@example.org[Read More]
billhiggins 1000006JUS 313 Visits
I mentioned in an earlier blog that I just finished reading a biography of Thomas Watson, Sr. I used to read books for several hours a day, but between increasing job responsibility and being a new husband and Dad, there's much less time to read books. One meme floating through the blogosphere recently is that people are gradually losing the ability to consume more complex works (like books) as they get used to smaller "sound-bites" of information - i.e. the 10s or 100s daily emails, similar amounts of short blog entries, 24 hour news on the web and TV that gets updated every 10 minutes, etc.
So I'm trying to spend an hour or two before bed working on the book backlog I've built up since I graduated from school. It's much easier to buy books than it is to read them. :-) Next on the list is Father, Son & Co., the autobiography of Thomas Watson Jr., who took over the reigns of IBM from his dad in the 1950s and took it from a dominant company in its industry to become the iconic IBM of the 1960s and beyond. Yes, I'm admittedly a little Watson'ed out, but I want to read Tom Jr's book again while all of the info from the Tom Sr. bio is fresh in my head. Also, it's amazing how many parallels I see between the culture that the Watson's established in the early part of the 20th century (almost 100 years ago!) and the culture that I still see in the halls of IBM today.
- Bill[Read More]
I was writing some code this week that essentially implements a REST API for a server-side web app. The URL could either end in a positive integer (e.g.
Java provides a method
I thought I found something when I found java.lang.String's matches method. It takes a regular expression as input and returns a boolean indicating whether or not your pattern matches your String. So to test for a positive int I could just say
I mentioned this to my manager and he was a bit worried because he was under the impression that regular expressions in Java were relatively processor-intensive, and the code in question was on a frequently-traveled server-side code path, meaning that any extra cycles would add up as more users used the server. He suggested I time the different options available, so I did. It turns out he was right - String.matches was horrendously slow compared to some of the other methods available. Below is a summary of the tests I ran:
Method 1: Custom checker
The custom checker is a private method that takes a String as input, walks the String and returns false if it hits any character that's not a digit (using
Method 2: Try Integer.parseInt, catch Exception
This seems to be the de facto method for testing Strings for ints, but the one I rejected because of the legit case of a non-int as input.
Method 3: Pre-compiled regular expression
Similar to String.matches, but using a regular expression that's compiled only once in the lifetime of the program, since the pattern ("[0-9]+") never changes.
Method 4: String.matches(String regex)
Matching on the string "[0-9]+", meaning that this regex needs to be compiled each time.
1 million randomly generated integers, converted to strings, with 5% of said int-strings mangled to include non-int characters.
I was pretty stunned that the most straight-forward method (String.matches) was two orders of magnitude slower than the custom checker, which I ended up going with. Now I know someone out there is reciting "premature optimization is the root of all evils", so a few disclaimers:
Ah, coding again.[Read More]
About a week ago, I sent an email to a product manager for an important IBM software product, encouraging him to blog. I pointed to Microsoft as an example of people who use blogs effectively to inform their user communities about upcoming products.
He pointed out that it is his group's explicit policy not to talk about future products until the release was several months away from release to manufacturing.
Software projects are volatile things - there are many potential events that may force you to change scope or schedule of the project. A few of these events:
So if you talk about your future product to the press or via a blog, it's easy to make implicit commitments - features or schedule that may be in flux internally, but once published becomes concrete in the customer's mind. And those commitments can lead to customer dissatisfaction and press angst when something about the project changes.
I have mixed feelings on this. On the one hand, I think any feedback from customers is valuable, and blogs open you up to the whole Internet community (as opposed to a focus group selected by marketing). On the other hand, I can understand the desire to avoid the reputation of someone who makes and breaks commitments on a regular basis. Not to mention that if you start talking about features a year ahead of RTM, that becomes very valuable (and incredibly cheap!) competitive intelligence for your rivals.
What made me think of this was this article on current happenings in the next major release of Windows (internally called "Longhorn"), and read the following quote:
What's not up in the air, however, is Longhorn's ship date. The company is now committed internally to shipping Longhorn in May 2006.Note that this quote says "committed internally" (italics mine).
Microsoft has really been burned in the past for committing to schedule and/or features way too early (the opposite of what I describe above from the IBM product manager). Sometimes this tactic is used to FUD competitors (e.g. pre-empting a competitor's actual product release by announcing competitive vaporware). But other times it's just plain enthusiasum for a future product.
I'm really not sure what the right answer is to this question, or even if there is a right answer. My gut feeling tells me that, the more input and feedback from the customer community, the better. Maybe its just a matter of putting up appopriate disclaimers.
In the meantime, it will be interesting to see if Microsoft can hit its internal May 2006 commitment on Longhorn. My bet is probably not, unless there's a heck of a lot of buffer time in the next sixteen months to deal with unexpected stuff. But since it's not a published commitment, they should have the freedom to move that date at will.
By that time I may be a Mac user anyway.[Read More]
As I mentioned in my last entry, I'm now working on the IT portion of the mega-project to segment PC Division function and data from the rest of IBM's IT as part of the sale of that division to Lenovo.
This is a large project.
Before this I had a nice little mental model of three sizes of "enterprise" projects:
I think that my work on PCD segmentation has led me to realize two new related categories of projects: "acquisition and divestiture".
These categories are of course two perspectives of the same business event. Company A buys all or some of Company B. From company A's perspective it's an acquisition; from company B's perspective it's a divestiture assuming that it only sold some of it's business, as is the case with IBM's sale of PC Division to Lenovo.
The reason that this is a new scale of project is that instead of focusing on several large scale business processes (as is the case in my "business process integration" type), you're focused on all business processes. This means that all applications are in scope, and in the case of IBM (a Fortune 10 company), we have about 5,000 of them. As you can imagine, it's impossible for mere humans to reason about 5,000 applications.
How do we manage this kind of scale? That old management tool: hierarchy. Someone (I don't know who) made the good decision to logically divide the landscape by "towers". A tower in this context is simply the name we've given to describe a grouping of applications by business process area like "Market and Sell" (e-commerce apps) or "HR". We have twelve towers, each with lots of applications under them. In addition to the towers are "the geos": North America, Latin America, EMEA (Europe, Middle East and Africa), and AP (Asia Pacific) who are responsible for geo-specific or country-specific applications, whereas "the towers" are generally responsible for applications that are used in many countries around the world.
I'm on the program team, responsible for change management (this task deserves a whole other blog entry) so I work with the tower and geos, not applications. Whenever a large scale change request comes in, I work with the lead architect to determine which towers and geos are probably impacted based on the nature of the change, then work with those towers/geos to do change assessments to figure out if and how the change should be accepted. They go off and work with the project managers of the applications in their geo/towers and then roll it up to me. I roll it up to the project and deal executives who make the yes/no decision on the change.
So that's the nature of my current project. It's very time-consuming as you might imagine, which is why I haven't posted lately. On the bright side, I just had someone assigned to help me administer change management yesterday, so perhaps this will lead to a decrease in workload and more time to blog. But not likely; this seems like one of those projects where there's an almost infinite amount of stuff to do, so if my workload goes down around change management, new tasks will emerge to suck up the freed-up time.
Luckily, this is a project with a well-defined end point (whenever IBM and Lenovo declare the IT "separated") so this pace shan't last forever.
I hope it doesn't sound like I'm complaining about this job. I actually enjoy it in a weird way; the pace and complexity really make you focus. The only thing that's a tad frustrating is that the change management piece I'm working on is really more project management-oriented as opposed to technically-oriented, especially at the level of abstraction at which I'm working. But to be perfectly blunt, I have a good reputation for leading people and teams through complex problem-solving activities, and change management needed some help, so there you go. The glass-half-full side of the equation is that it's always good to see "the world" from different perspectives and this experience has really improved my knowledge and skill around estimation, which is a key skill both for project managers and technical leaders.
Speaking of which, I picked up Kent Beck's recently released Extreme Programming Explained, 2nd Edition last night. As you probably know, one of the tenets of the Extreme Programming methodology is "embrace change". I want to read this book and assess the "embrace change" philosophy vis a vis a massive project like PCD segmentation, to figure out how far this philosophy scales. If I come to any sort of conclusion, I'll write it up.
For those of you interested in Jazz, there was a great deal of new Jazz news announced at RSDC yesterday morning. The big news is available in this podcast of a keynote by Martin Nally (Rational's CTO) and Lee Nackman (Rational's VP of Product Development and Customer Service).
A few key quotes:
on open sourcing the Jazz core infrastructure
"We're going to take the core infrastructure of Jazz and make that open source to help foster growth of a community around that core infrastructure and then Rational will build products, commercial products, on top of that core open sourced infrastructure and we expect that there will be other Jazz-based tools and frameworks that are produced by third-parties, by customers, etc. and of course we want to have an ecosystem of partners who are able to augment and provide additional capabilities to our products and to the platform."
on 'open commercial development'
"John (Wiegand) and Erich (Gamma) talked quite a bit about the benefits of transparency; so one of the things that we want to do is get those benefits in the commercial software that we develop on top of Jazz. So we're going to do two things: one of them is that, as I said, we're going to open source the core infrastructure to establish those standards and then we're going to develop the Rational products on top of that in a way that we call 'open commercial development' and what that means is that we're going to do the things that John and Erich talked about to get transparency with our commercial products. So customers will be able to participate in providing the kind of feedback loop that leads to the high quality software that we've seen from Eclipse. So we think this a very important innovation in the development of commercial software - this complete transparency that we're going to use as we build technology on top of Jazz."
I couldn't agree more with the decision to open source the Jazz core infrastructure and produce our commercial products in a transparent way.
- Bill[Read More]
billhiggins 1000006JUS 262 Visits
billhiggins 1000006JUS 1,602 Visits
FYI, I've gotten a few comments from people about not posting to my dW blog in the past couple of months. I decided to make my billhiggins.us blog my primary blog, but through the wonders of syndication, a subset of the blog entries over there will end up here on developerWorks - i.e. the ones that are germane to my job at IBM. Note that looking at the entries so far on billhiggins.us, that 'subset' would be 100% of entries :-)
But anyhow, you can consider the IBM dW blog a 'copy', but you're welcome to subscribe to whichever one you please.[Read More]
billhiggins 1000006JUS 363 Visits
I'll be incommunicado the rest of this week as I'm traveling to my hometown of Harrisburg, PA for my friend Shawn Lynam's wedding on Saturday and my 28th birthday on Sunday.
If anyone out there feels compelled to buy me a gift, my Amazon.com gift registry is here. I will act surprised and embarrassed and say things like "oh, you shouldn't have!" yet take no action to refuse the gift.
contact me: email@example.com[Read More]
2004.01.28 Update: Here's a good write-up on getting started with Bloglines. Thanks to Bob Sutor and James Governor for the pointer.
I switched RSS readers from Feedreader to Bloglines, as per Bob Sutor's recommendation. It's got some really nice features that I like, the key one being that you can which blogs other folks read, which is a great way for finding quality content in the large sea of information.
I get emails occaisionally from readers of this blog who for whatever reason don't leave comments (hi Clemens). Based on this anecdotal evidence, the readership of this blog consists of two general demographics:
You should stop reading now if you know what an RSS reader is.
For the non-technical friends and family out there (like my mom) who are not familiar with RSS readers, here's what I was talking about at the beginning of this post.
As you can see from the right side of this screen, I regularly read quite a few blogs (fifteen at the time of this writing). It's time consuming to jump from web site to web site to read all of the blogs, especially when many people update their blogs only occaisionally. Someone, somewhere, sometime in the past decided that this was a big waste of time, and invented a technology to simplify the aggregation of frequently changing content that one is interested in. This technology is called RSS (really simple syndication).
RSS is quite simple: any content provider can create an "RSS feed" which is just the regular content (whether a blog or set of news stories) in a format that a computer programmer can understand. Individuals, like myself, can then download and install an "RSS reader" and point it at all of the content providers in which they are interested. So my RSS reader points to all of the blogs on the right side of the screen as well as a number of news sources (like CNET News and The New York Times). So instead of going out to all of the different web pages, I just go to my RSS reader and read all of the new content that has been created since the last time I checked.
It's incredibly handy. If you're feeling adventurous, I recommend checking out Bloglines. Then as you go to different web sites, keep your eye out for little buttons that indicate an RSS feed is available. You can then add that web site to your list of content providers, and the information will be brought to you, rather than you having to go to it.
Here's a longer introduction to RSS if you're interested. Beware, it's somewhat technical.[Read More]
A round-up of some blogs and articles from the Jazz demo and discussion at RSDC.
I'll post more as I find them (feel free to email).[Read More]
Bobby Woolf mentioned in a blog today that he wrote an article for the WebSphere Technical Journal about ... oh hell, I can't explain it briefly - just check out the article.
Seriously though, if you'd like to gain a better understanding about what JNDI is for and the service locator pattern (and a nasty potential problem with it in J2EE 1.3), check out the article.
PS - on a related side note, Martin Fowler has a typically insightful article talking about the Dependency Injection (a.k.a. Inversion of Control, or IoC) pattern and how it compares to the Service Locator pattern that Bobby talks about. Thanks to Ted Neward for telling me what IoC stood for since Google couldn't.[Read More]
Bobby explains how fast food restaurants are similar to enterprise messaging systems.
No, I'm not making this up.
I just looked at our internal developerWorks blogging statistics for August 2005, and I was sort of blown away the number of hits Bobby Woolf got.
I won't give the numbers (don't think I'm allowed) but will say that he got over 2x anyone else and over 3x my number of hits.
Keep the great info coming Bobby!
contact me: firstname.lastname@example.org[Read More]