 Monday, September 18, 2006
One of the things in my job that I have been doing and enjoy doing is engaging the customers. Over the past few years, I have learnt from my mistakes and have seen people fall into serious pitfalls that have caused deals (and sometimes, fortunes) to be lost.
While this may be specific to technology applications and platforms, it can be applied horizontally cross-breadth. I hope I have time to make this a useful series to help the readers. Here is one:
--- Begin Exchange ---
When the customer CIO asked a presenter (of the bidding companies): What platform would you go on ?
You should never answer: We can do both. 
Worst, if the CIO repeats his questions again: Let me ask again, what platform would you go on ? 
You should NEVER NEVER NEVER answer again: We can do both. 
--- End Exchange ---
Bear this quote in mind first and I will address how it fits in this entire context:
Gordon Gekko: You stop sending me information, and you start getting me some.
Why ?
- Listen and Think. Dont just hear and read from a pre-arranged script. By answering the same to his repeated questions tells him you think he is deaf. He is NOT. You are. Brain-deaf, that is. If I was too crude, let me put it in a nicer way. You are hearing, but you are NOT listening. If the same customer CIO or his equivalent in the committee has also asked: "What is the ratio of XXX projects to YYY projects your company has done ?" It is very obvious he is asking for an answer and not a level of indirection.
- Know how the customer thinks, works and is measured. I refuse to believe that a customer CIO has no idea how the world outside functions. He may have no idea how it functions internally, but thats not the point. When he budgets for a project worth xx millions, he knows, pretty much in his head, what he wants as the end-goal. He just cannot put it down in voice and ink so as to play the political battles well and not to offend other people. What he is seeking for is - VALIDATION. That an outside external party thinks the same. The fact that he is there and you are down here means he is smarter, not necessarily capable. Ultimately, see what is at stake. If a project fails because of the wrong use of technology, his job and his pay is on the line and that is probably 3x more than yours. He knows. He just wants someone to sing the same. Do so.
As an example, I am arguing the customer already has 3 technologies or solutions in mind already before he approaches a public tender proposal situation. He doesnt have none. If he does, the worst thing you can do is assume that. Remember, the product and platform vendors have more resources and more time than you to camp at their site with their marketing agents and lovely legs. Many people dont realize that - Things have already been sold, just not in ink. So when you say, you can do both. Even though it is deemed to be more professional, you are giving away a few things
- You are no idea how they work and what is the current state. In other words, you have no intelligence.
- You didnt put an effort to discover what is going on in their current environment and the current battles they have. The fact that they are asking for a solution means they have a problem. Find out what that intrinsic problem is.
- You cannot make a bet and take that risk. He is, by granting you a project which he is paying millions for. Surely, you can ride that and show him you are taking the same risk as well ?
- Intelligence, Intelligence, Intelligence. Surely, the account manager, whom the team is supporting must be worth the commission he is paid. Gather the topology, the current state, the internal political battles. Who is the customer CIO sucking up to ? Who is buying the customer CIO the expensive red-wine bottle sitting in his office wine-cellar ? Which favourite prodigal son of the IT department is the customer CIO favourites with and what is he/she complaining out ? Find this out. It is likely, you can piece a good internal scenario, which the customer has to deal with in his daily work, your lesser competitors have no clue about.
- Go BIG or go home. For goodness sake, take a bet. We do that, every single day in everything we do and the choices and decisions we make. Why cant you do so in front of the customer ? When a customer CIO, not just another IT person, asked you the question above. Like I said, he is seeking validation from a 3rd party.
While it may be necessary to sing your corporate tune, remember - you are not presenting to your own CIO. It is the customer we are talking about here. If a customer has got a big flashing "We are an XXX shop" in front of their door, you should sing an XXX tune. However, like I said in Point [2], the CIO is not measured by how much he contributes to XXX revenue. He is measured by the ROI of the millions he is spending on this project and you. So, if you say: "We go with YYY", it is likely he will stop staring blankly at his handphone and his ears will perk up and listen.
Now, if he is anti-YYY because his mother has just slapped him because a stupid YYY patch failed to make it to her PC in time and therefore has lost all her fav bookmarks. Out of professionalism in front of the entire steering committee, he wont stop you and ask you to get out. But you would have gotten his attention when said those magic words. Getting his attention, out of the hundreds of meetings and other solution tender presentations he has to attend that day, is half the battle won.
Now if are worth the salt your company is paying you, you would address his concerns and answer them methodically. (Excuse me, but arent you an architect/consultant ?). Most importantly, stand up and be counted for. If you have done Point [3], rationalize your decisions to him and justify why you choose YYY. To take a technology-neutral stand, something like that will always be music to a customer's ears:
You: We choose to go with YYY's engines for this project because we understand that [repeat what your intelligence has gathered for you in this account. Remember to make sure that your solution justifies what your intelligence has gathered or you are screwed ... ].
However, we also understand some of the public/users/your concerns with YYY's engines such as the skillsets of your mechanics may be that of XXX's as we noticed that there is a recent M&A of your parent company with an unit of XXX. So if you should decide that XXX is what you want, be very rest assured that our company has the same kind of XXX calibre people as YYY ones. Let me share you what projects we have done with regards to the XXX engines ... 
He may not buy them in the end. But I assure you, he will respect you and your company for standing up for what you believe in and for taking a bet, which he is also doing.
- Think the bigger picture. Dont miss the forest for the trees. So, what if you lose this deal because you stuck YYY in your mouth ? Likelihood is that, you will also lose this if you had said: "We can do both". If you had said the quotes I mentioned above: "We choose to go with YYY's engines for this project because we understand that ... However we also understand some of the public/users/your concerns with YYY's ..." and still lost, it is obvious that the customer is looking for someone who worships XXX as much as he does. Too bad. Move on.
If you had not failed your maths in school and understood the theories of Probability, you will understand that, in the long run, you will stand an equal chance of winning YYY solution tenders as much as losing the XXX ones. If you dont make a bet, you will never lose or win, in the run.
To summarize and I quote one of my favourite fictional movie characters, Gordon Gekko, of Wall Street:
Gordon Gekko: You stop sending me information, and you start getting me some.
Remember, the customer CIO is not asking you for information. He probably knows more than you since he has the benefit of all the application, product or technology vendors camping at his office and singing to him everyday. Validate him, Sing his tunes, even better - tell him something he doesnt know yet. For example, we have reasons to believe that XXX may not be suitable because ...
He will appreciate that. Even, if you UN-validate his thoughts, Trust me (I have learnt), it is likely he will remember you for future references. By adopting a passive ground and not answering and worst, not listening to his questions and concerns, it is likely he will continue looking at his handphone, hoping someone will call and save him and you will be nothing more than a distant memory in his head.
 Monday, December 26, 2005
One of the things that I thought <Input TYPE=radio> had always lacked is that it only allows it to be specified as part of only ONE group - which is dictated by the NAME attribute.
Therefore, with this code
<INPUT TYPE=radio NAME=names VALUE=1>William Tay <INPUT TYPE=radio NAME=names VALUE=2>William Gates <INPUT TYPE=radio NAME=names VALUE=3>William Tell
I can do this: William Tay William Gates William Tell
However, if I wanted something with a 2-dimensional twist to it such as something like this:
I will be stuck somewhere in between because while I can select my order of Preferences (in terms of 1, 2, 3) for any of those topics, I cannot prevent other uses from selecting a Preference 1 for more than 1 topic. This kinda distorts the voting statistics as someone may vote a Preference 1 for all topics which is not meant for business functionality intent.
While, there are a few ways to do this, such as using a combination and tweaking of dropdownlists and other <input type>, I had some trouble searching for the same function to be served via a more intuitive Radio Input Type.
So, I decided to write a small javascript snippet to be implemented via the onclick event-handler of the <Input TYPE=radio>. The parameters to be passed into the javascript function are all the same for all the radio buttons so it will be very easy to do this programmatically in your favourite language.
The trick would be to manipuate the VALUE attribute to slot in a second Radio Group name and thereafter, have some javascript code manipuate the other radio buttons. Here is my documentation including the parameters to be passed into the javascript function:
/* Documentation: <INPUT TYPE=radio NAME=n1 VALUE=1_1 onclick="javascript:ClickAnotherRadioGroup(this.value,this.name)">
The Value of the Input Type=Radio must be a delimited string The Value to the left of the pre-defined delimiter is the name of the Second Group Name This means that while NAME signifies a Radio Group, the x of VALUE=x_actualvalue signifies the Second Radio Group Eg. (a) - <INPUT TYPE=radio NAME=n1 VALUE=g1_1 onclick="javascript:ClickAnotherRadioGroup(this.value,this.name)"> (b) - <INPUT TYPE=radio NAME=n1 VALUE=g2_2 onclick="javascript:ClickAnotherRadioGroup(this.value,this.name)"> belong to the same Radio Group (n1) (c) - <INPUT TYPE=radio NAME=n2 VALUE=g1_1 onclick="javascript:ClickAnotherRadioGroup(this.value,this.name)"> (d) - <INPUT TYPE=radio NAME=n2 VALUE=g2_2 onclick="javascript:ClickAnotherRadioGroup(this.value,this.name)"> belong to the same (but different from above) Radio Group (n2) However, (a) and (c) belong to the same radio group as well (g1) WHILE (b) and (d) belong to another group (g2) The Value to the right of the pre-defined delimiter is the ACTUAL VALUE of the Input Type=Radio Note that if the ACTUAL VALUE of the Input Type=Radio uses the same delimiter, we can change our own delimiter in this function */
Now try this with the Javascript implementation:
function ClickAnotherRadioGroup(v,n) { var f = document.forms(0); var n2 = v.split("_")[0]; // Retrieving the second grouped value for(var i=0; i<f.length; i++) { if ((f.elements[i].type == "radio") && (f.elements[i].checked) && (f.elements[i].value.split("_")[0] == n2)) { var c1 = f.elements[i].value; var c2 = f.elements[i].name; if ((v == c1) && (n == c2)) {} else { f.elements[i].checked = false; } } } }
Try this now:
I hope this snippet will help someone as much as it has helped me.
 Friday, November 11, 2005
What an awesome Translator !!!
Where was this a year ago when I had to port something from C# to VB.NET ?
The next enhancement should have something that translates business requirements to code. I would definitely buy that.
 Tuesday, July 12, 2005
After so many years, I have finally activated my first PSS call to Microsoft. All these years, I have been prowling Google and MS user-and-newsgroups rendering help and sometimes receiving help as well. Never had I once need to activate a PSS call. Power to the MVPs
However, I had this pressing problem that couldnt be solved and because of that, I had to skip a few cool demos which kinda sucks.
The problem revolved around the installation of SP1 on top of Windows Server 2003. It just rolls back halfway during the installation process without giving me a reason why. I also noticed that it happens during the installation of this file cladmwiz.dll, which is strange because I am not running any kind of clusters.
It was definitely a long and tedious day with a very helpful person from PSS Microsoft. There were language muckups because the APAC PSS center is based out of Greater China and it takes a good 3 minutes just to make sure we get the Case Reference ID correct. Patience is definitely his middle name.
Finally, we came to the troublespot and found a way to workaround it. The problem were the UDDI Components that was installed on my Windows 2003 Server machine. Apparently, SP1 doesnt like it enough to install itself on top of it.
Here is the workaround:
- Extract this attachment to the target machine.
- Extract the sp1 package with the following command line: [sp1 package file].exe -x
- Run the following command line on the target server: uddisp.exe install [sp1 path]
- Then, uninstall UDDI component through Add/Remove Program
- Install the service pack 1 again.
I hope this helps someone out there as days and days of googling resulted in nothing. This will also save some poor soul from activating the PSS for help.
Now in the first place, why isnt this documented ? It seems that I am the only one in the world who uses UDDI on Windows Server 2003 SP1.
You know what ? Somehow, why am I not surprised ? 
 Saturday, June 18, 2005
WS-MetadataExchange is used and enabled by default in Indigo and it comes with WS-Policy as well.
This is one specification that I find really useful because the current convention of using http-get to get the metadata from asmx?WSDL is still a very .NET sort of convention. For my projects, I usually like to put the metadata in a physical file and deploy it as *.wsdl. Other people and toolkits will also have their own naming conventions.
While using http-get is a very useful convention of retrieving metadata, we cannot assume that all services will support HTTP. In Indigo, it’s common to expose an endpoint that only listens over IPC or SOAP-over-TCP.
At its current Beta 1 drop, only http / https will be supported. I do forsee that tcp will be supported in the next major drop.
In Indigo, the WS-MetadataExchange endpoints are added to the (http) service by default at the container-baseAddress/containee-endpointAddress as a mex suffix. You can also choose to define your own custom mex endpoints. Another wonderful thing it supports is that it allows the specifying of a custom metadata file (which I know I will be definitely be using). In other words, instead of getting Indigo to automatically generate the metadata, it will send the requestor to the uri location of the metadata file I specify.
If you have done some UDDI work before, you would be accustomed to the convention of sending standardized (W3C) SOAP Request messages for querying purposes. WS-MetadataExchange uses the same sort of principles, albeit with different querying implementations.
Here is how it works. There is no better way to illustrate this than to get really friendly with the wire-layer plumbings. I have a tool here that will give you a good view of the exchange.
You need to send a standard SOAP request to the listening mex endpoint that goes like this (Replace the square brackets with angle ones)
[s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing"] [s:Header] [a:Action s:mustUnderstand="1"]http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata/Request[/a:Action] [a:MessageID]uuid:f22ee227-3eeb-460d-9352-1a34e97bf911;id=0[/a:MessageID] [a:To s:mustUnderstand="1"]http://localhost/servicemodelsamples/service.svc/mex[/a:To] [a:ReplyTo] [a:Address]http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous[/a:Address] [/a:ReplyTo] [/s:Header] [s:Body] [GetMetadata xmlns="http://schemas.xmlsoap.org/ws/2004/09/mex" /] [/s:Body] [!-- OR an Empty SOAP Body will do just as fine --] [!-- s:Body /--] [/s:Envelope]
In the tool I had build, you need to put the a:Action value (in bold above) into the SOAPAction textbox as this has to be propagated up to the HTTP-Headers as a SOAPAction header. This is one of the sticklers of using http to query for any SOAP Web Service. Once you clicked post, you will see a good-looking response with all the metadata of WSDL and WS-Policy in the SOAP body. I took out a lot of details in the constraints of space. You should be able to get the point.
[s:Envelope xmlns:a="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope"] [s:Header] [a:Action s:mustUnderstand="1"]http://schemas.xmlsoap.org/ws/2004/09/mex/GetMetadata/Response[/a:Action] [a:RelatesTo]uuid:f22ee227-3eeb-460d-9352-1a34e97bf911;id=0[/a:RelatesTo] [a:To s:mustUnderstand="1"]http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous[/a:To] [ActivityId xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics"]uuid:a55fa135-e1b9-4557-a7c3-39cbf042f85d[/ActivityId] [/s:Header] [s:Body] [wsx:Metadata xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"] [wsx:MetadataSection Dialect="http://schemas.xmlsoap.org/wsdl/" Identifier="http://tempuri.org/"] [wsdl:definitions] [!--WSDL and XSD GUNK--] [!--XSD GUNK--] [!--WS-Policy GUNK--] [/wsdl:definitions] [/wsx:MetadataSection] [/wsx:Metadata] [/s:Body] [/s:Envelope]
You will be able to load endpoints, bindings and types dynamically at runtime with such information.
Do take note that Indigo is extremely strict about the mediaTypes headers and you need to set the contentType of the Http-Headers to application/soap+xml. This can be done in the configuration file.
Do download it and try it.
If you think this is a cool new feature in the Microsoft technology space, it is not.
Web Services Enhancements (WSE) 2.0 also had it. All you need is to send in a "http://schemas.microsoft.com/wse/2003/06/RequestDescription" in the Action of a SOAP Message request to a listening WSE 2.0 service and you will be presented with the WSDL as well. This is what WseWsdl2.exe does you switch in a TCP address.
 Saturday, June 04, 2005
Courtesy of Aaron, a technically-brillant dude and a ASP.NET MVP of our Singapore Community.
 Wednesday, January 26, 2005
Got this inkling feeling that these ASCII Character code tables will come in handy one day...
| DEC |
HEX |
ASCII |
|
KEY |
|
DEC |
HEX |
ASCII |
| 0 |
00 |
NUL |
Null |
CTRL-@ |
|
32 |
20 |
SPACE |
| 1 |
01 |
SOH |
Start of header |
CTRL-A |
|
33 |
21 |
! |
| 2 |
02 |
STX |
Start of text |
CTRL-B |
|
34 |
22 |
" |
| 3 |
03 |
ETX |
End of text |
CTRL-C |
|
35 |
23 |
# | | |