Looking back, it seems I've run out of important things to share in a while; but it seems the world is not yet finished things to share with me.
A reminder performance driven world, we remain psychologically driven creatures.
Monday, February 29, 2016
The Perfect Team
Thursday, July 11, 2013
Scourge of the modern corporation
Simple steps to tame meetings. I'd add onto that no meeting of more than three people should ever last longer than 30 minutes.
Friday, February 5, 2010
Beautiful C++
It is possible.
I think this is possibly the most elegant code I've written as a professional programmer.
A lot of thought went into making it that small and simple.
Here's hoping it only gets better.
Sunday, November 29, 2009
How he hires
While ago I wrote an entry on how I hire.Today I came across this fellow opinion, which is similar to my own.
I agree with the author, and this this is how you should hire too.
The Essence of a Manager
I didn't write this, and I'm not sure it matters who did; only that it's true and bears memorialization.
Managers get to do a lot of knowledge-free decision making, which necessarily drives them insane. Here’s how the manager’s bipolar disorder works.
During maniacal periods, the manager is the only one who can do anything around here. This frequently happens when the manager is under external pressure, and he feels that control is slipping out of his hands. He’s trying to compensate for his lack of knowledge by immense concentration and willpower. (Managers always have ample emergency supplies of both.) “Concentration” translates to an ability to derive general and far-reaching conclusions from insignificant details, then “willpower” translates to aggression.
Then depression follows: “Don’t bother me with details”. This results partly from exhaustion quickly arrived at during the mania (especially if reports were wise enough to not argue with the manager, letting his efforts defeat their own purpose.) The manager has delivered his trademark concentration and willpower, so he no longer feels guilty on that front. However, he’s overwhelmed by information and (rightly) feels that he doesn’t know what’s going on. He decides it is none of his business and concentrates on the Big Picture (does nothing). Usually, the cycle repeats upon a new wave of external pressure.
Saturday, August 29, 2009
The dawning of the Windows era
Recently the RSI stress in my right hand is becoming too much to bear. I needed to find a way to reduce the stress on my hands so I went to pick up Dragon NaturallySpeaking. The idea is, for me to use voice recognition to do regular English writing, such as e-mails, blogs, and other non-coding writing.
Since trading NaturallySpeaking is a Windows only product, and the open source speech recognition tools are not nearly mature enough, this is meant that I've had to officially convert one of my machines to Windows. I think Dragon NaturallySpeaking can be made to work in wine, but when it comes to something as serious as my health I'd rather just bite the bullet, and exchange OS preference for physical comfort.
I purchased a Compaq Mini 10 inch laptop, with Windows XP installed, so that I can take it into a quiet room in order to dictate. The first thing I did with the laptop is remove all the preinstalled software that came with the laptop, and installed from source alternatives like Firefox, OpenOffice, VideoLAN, and ClamAV.
So far using Dragon NaturallySpeaking has been as smooth as silk, the error rate is extremely low, and if there is a mistake it's usually because I slurred my speech. In fact this whole blog entry has been dictated through Dragon NaturallySpeaking; in far less time and far more comfort than had I had to type it out. The only adaptation being having to think about what you say before you speak it,and make sure you enunciate clearly. it also includes a startlingly large dictionary with plenty of technical terms included such as Windows, Linux, Firefox, OpenOffice; all dictated directly without need for correction.
If there is one drawback, it's that writing become so easy, there is a tendency to carry on far too long. :)
Here's hoping someday open source speech dictation becomes as good as this.
Tuesday, August 18, 2009
Handedness in coordinate systems
When I learned about handedness in coordinate systems, it was algebraically (AxB=C, BxA=-C), which is interesting but doesn't build much intuition. I enjoy analytic arguments, but ultimately it's the intuitive reasoning that tends to stick with me and inform new insights.
I often had trouble remembering which meant which, staring at my hands trying to remember how "that stuff" went, looking rather silly the while. I recently wanted to recall what OpenGL and D3D respectively do, and came across this discussion on real-time rendering, pointing out that even the pros get mixed up sometimes.
His example gave me, finally, a good piece of intuition about handedness: label your thumb X, index Y, and middle Z.
A right-handed coordinate system is what you have when you imagine your world relative to your desk: X goes east, Y goes north, and Z goes into the sky.
A left-handed coordinate system is what you get when you imagine your world relative to your monitor: X goes right, Y goes up, and Z goes into the monitor.
A perfectly good reason why modellers would prefer their object coordinates to be in a RHS, and programmers might convert it to LHS.
Sunday, June 7, 2009
On Platforms and the Convergence of 2D and 3D Internet
Working in Virtual Worlds, we are often given to wonderful discussions about what the future will hold for the Internet, and when and how various technologies will converge.
One popular school of thought is that virtual worlds should be embedded in existing web browsers as "light" plug-ins -- in order to make installation easy, and leverage history's most popular connected application platform.
The other is that there should be a "heavy" viewer designed completely around a unique virtual world experience; which happens to contain a superset of features, including web-browsing.
I belong to the second school; and in fact that opinion had lead to conflicts within my previous company. Thankfully, my current employer very much shares my vision.
However there are many in the first camp, and I am sometimes asked why I will not join them, especially in light of recent developments specifically aimed at bringing 3D to web browsers. Let me try to explain why despite all the momentum for adding 3D to web browsers:
I believe placing a 3D virtual world viewer within a 2D web viewer is somewhat comparable to embedding a gopher viewer, or ftp viewer, or email viewer within a web browser -- it's of course been done, but it's backwards, leads to awkward results, and has never proven to be very popular.
In the long term, computer code is plastic. If the world decided to morph a web browser into a 3D application platform overnight, there is no technological reason why it couldn't happen. So the question of where to put certain features is more ideological, metaphorical, or about user interaction concerns
What is a web browser?
Is it the ultimate convergence point for anything internet-related? Is it a new OS that should have it's own version of OpenGL? Is it just a safer sandbox for internet applications that the OS itself?
For me, issues of security or specific features are not interesting. Clearly any application platform needs to constrain the ways in which hosted applications can access raw resources. And clearly the needs of the platform evolve over time, and that requires adding new APIs.
For me, the question of what makes a web browser is a question of design, and mental modes; and how the totality of those decisions affect the expressiveness of applications written for the platform.
A web browser, for me, is a transaction-oriented 2D document-centred internet application platform. A virtual world viewer is a stream-oriented real-time interactive 3D scene-centred internet application platform. I am not sure there exists any easy abstraction that allows one to fluidly translate concepts between categories. The commonality that they host applications that run on the internet is not enough to unite disparate modes, and inform the design of a coherent platform.
Web browsers will indeed need 3D features. But they way in which 3D will be used on the web will be document-oriented, and happen in transactions (not real time). Things like e-commerce catalogues can be made available in full 3D. Any number of static scenes relating to the host web document will add a lot of value -- the way embedded streaming video adds value to many current websites.
But World of Warcraft will never run in Firefox (not at least without a severe redefinition of "browser", "runtime", or "OS").
What is a platform?
What might the average computer look like in 10 years from the perspective of application platforms?
I feel that each computer will consist of several rings or layers of runtime platform:
- Native: applications are programmed against the native OS libraries, and constrained by native OS security model (ex: win32, POSIX, OpenGL, etc.)
- Managed: applications are programmed against a large, general purpose, coherent, high-level API; and run in a virtual machine with detailed, explicit, and programmable security model (.NET, Java, Python, etc.)
- Internet: applications are programmed against a special-purpose API, with clearly defined semantics, which is exposed though a common data model (the DOM for web) and standard set of operating primitives (HTTP for the web); security model is highly sandboxed, limiting access to private data where not explicitly required by the data model or operating primitives (IE, Firefox, and one day Virtual World Viewers?)
How would the web look in a VW viewer?
I think it would be wrong to assume that because 2D embeds in 3D mathematically, that the web browser should go away -- entirely subsumed in a 3D viewer. That really ignores the long and ongoing history of humans quite preferring to do a lot of their most abstract work in 2D documents. It would also really undermine my own argument that the web and VWs are really very different modes of interaction.
Instead, I believe that the VW viewer will know of the system's web browser, and rely on it directly for all web-related tasks. Examples might be embedding a browser window for the purpose of authenticating with an OpenID or oAuth provider for some network resource, such as gaining access to your facebook profile, or to send emails through gmail. Web applications like Google Apps would also make a simple and effective document sharing service available from within a virtual space.
So from a user's perspective, the web browser would be rendering elements of the regular user interface, or displaying discrete web pages in an integrated manner without appearing as a full web browser. There will also be cases of rendering to texture in order to display web pages as in-world objects, but their purpose will be peripheral.
As a some what related aside, I find it constantly amusing to see VW implementers try to embed 2D documents in 3D spaces. With few exceptions, there is no benefit whatsoever to being able to see your spread sheet in perspective projection as a texture. Give me a use case where having 2D documents in 3D is more than a gimmick, and I'll give you a modified use case where dimensionality is irrelevant, and the interaction feels much more natural.
Not just the browser
Other internet applications that I feel should not be subsumed within the virtual world viewer, but instead should integrate smoothly with them using an inter-process communication channel are things like E-mail, IM/Chat networks, Streaming Media, Office programs, etc.; all of which are regular desktop applications that the viewer calls out to in response to in-world stimulus; or alternatively, will respond in-world to a stimulus from the user's desktop.
Imagine a "meet in-world" button on your IM client, or having the streaming audio in your virtual home synced with your current desktop play-list (or vice versa).
Posted by
Ryan McDougall
at
12:21 PM
3
comments
Labels: philosophy, programming, virtual worlds, work
Wednesday, June 3, 2009
Structured Streams
TCP done right, implemented over UDP, as a user-space library.
What more could you ask for? Seriously, the paper is simple yet beautiful.
Tuesday, May 26, 2009
Compiling WebKit on Windows
- If you're doing any open source programming, you'll need to constrain yourself to the Cairo-based WebKit, as Apple's CoreGraphics-based rendering is non-redistributable.
- You'll need VS 2005, as anything newer isn't supported. If you're using Express edition, make sure you have the Windows Platform SDK.
- You'll need cygwin to run the build scripts. Make sure you install perl (in cygwin) -- but not GCC, as this may interfere with the scripts finding Visual Studio's compiler.
- If cygwin has any problems with "/r" character in text files, run the command "dos2unix $(find . -name '*.sh' -o -name '*.pm')" in "C:\cygwin\home\$username", to convert bash and perl files to UNIX new-lines.
- Run "C:\Program Files\Microsoft Visual Studio 8\VC\bin\vcvars32.bat" to enable the path's needed to run the compiler from command line.
- Check out your source from SVN. Nightly tarballs have some sort processing step specific to the platform that may remove things you might want.
- Check out the SVN into "C:\cygwin\home\
$username", as the build scripts assume this. - Set the environment variables "WEBKITLIBRARIESDIR=C:\cygwin\home\$username
\WebKitSupportLibrary\win" and "WEBKITOUTPUTDIR=C:\cygwin\home\ $username\webkit\WebKitBuild". - Configure WebCore/config.h to build with Cairo instead of "Safari", as according to this.
- Run WebKit/WebKitTools/Scripts/update-webkit
- Run WebKit/WebKitTools/Scripts/update-webkit-support-libs
- Run WebKit/WebKitTools/Scripts/update-webkit-auxiliary-libs
- Run WebKit/WebKitTools/Scripts/build-webkit --cairo-win32 --debug
- To be continued!
Monday, April 27, 2009
A Programmers Work-day
When I first started working as a programmer full time outside of school, in the "real world", I was a bit unsure what to expect. Would I spend all my day slaving at a keyboard? Would I spend it all in endless meetings? Buried under mountains of TPS reports? How does a real software house organize it's labour force on the day-to-day?
Starting my career in some poorly managed companies didn't provide a shining example for me to learn from.
I was literally shocked to see how much of the day co-workers just surfing out of boredom, but I was a little ashamed to ask anyone about their workplaces. Would anyone be honest about such flagrant waste of time? Would they look down on my workplace as a joke? Was the big horrible secret of the "working world" the fact that very little work actually gets done?
It touched protestant work ethic I didn't know I had. So much wasted time and money felt dirty to me.
That said, it wasn't long before I too #$%@ed my day away on websites; and for the same reason co-workers did: there was no serious management structure. Management didn't give anyone serious goals, or give developers the resources needed to meet them. Management provided no structure or oversight to the development process, and morale was fairly low; no one cared. One place I worked some of the developers showed up at 3pm and left before 7pm, four days of the week!
Over the development of my career no one has yet come out and given me a clear definition of what the professional standard for work ethic, but I have managed to develop my own idea of what should be expected of all programmers from a work day (you'll note I do not include managerial job titles):
Organizational Overhead
2 hours per dayThis is the overhead that is not an output itself, but is a natural requirement of any development process, and thus is has to be done every day.
It's often characterized by a series of interruptible tasks that center around communication with other human beings.
- Face to face meetings
- Phone calls
- E-mail and mailing-lists
- Bug triaging and code reviews
- Work-related blogs, websites, and IMs
Development
4 hours per dayThis is the "real" work, and is the measurable result by which your contribution to the group will be judged. If you're not producing here, you are not a developer.
This work is characterize by the necessity to spend long unbroken periods concentrating single-mindedly on the task(s) at hand.
- Researching technologies or libraries
- Devising designs
- Proposing and discussing design details
- Implementing code
- Testing and debugging running code
- Implementing tests and documentation
You'll also note that that accounts for only 6 hours, and the reason is that I essentially do not believe that knowledge workers' productivity, especially developers who are required to expend so much concentration for extended periods of time, scales linearly with time. Your brain needs breaks to open back up. Overwork just leads to burn-out.
The ideal work day for a programmer is some variation on the following:
- 0900-1000: handle time-critical overhead tasks such as emails, bug reports, and meetings
- 1000-1200: concentrate on priority work items
- 1300-1400: regular meetings and emails
- 1400-1600: concentrate on other important work items
- 1300-1700: try concentrate on work while being distracted by meetings and emails
Trying to do too much per day leads to burn-out, which doesn't have to be emotional or dramatic; it can be intellectual, and manifest itself is a subtle lack of creativity that's hard to detect.
Do you agree with my experience-bought conclusion? Do you have your own? Let me know.
Friday, January 16, 2009
Finally a work-related post -- about Windows?!
I decided to force myself to make a technology blog. Its because I have made a very important discovery.
For a long time I've been a linux user working in a world where windows is overly common. Luckily though, I have often been able to make the argument to my bosses that cross-platform development is important, and that free-software tools are high quality and save much time and effort.
What often stymied my noble efforts however, was the pain in the arse, not in making cross-platform code, which is a problem well attended to over the decades, but the trouble of getting something to build on all platforms.
You have autotools on the unix side, Visual Studio solution-files on the windows side, and well-meaning cmake in the middle, with a down-trodden, lonely, underused look on his schoolboy face.
This is issue is oppressing me as we speak at work, with us trying to integrate the powerful and flexible Telepathy messaging framework, and its companion libraries GStreamer and D-Bus. All of it portable C. All of it buried under mounds of steaming autotools.
For the past week we have been doing the slop-work of trying to reverse-engineer the intended build process codified in the dead languages that make up autotools, and re-implement them in cmake in the hopes that it might be accepted upstream, and one day be liberated from the shackles of 1987.
It's not Happy.
And neither was I until I stumbled across this little gem. Long story short: Fedora 11 will ship with a fully functional windows cross compiler.
Autoconf-based programs can generally be cross-compiled by doing:
yum install mingw32-*
./configure --host=i686-pc-mingw32
make
Project page here.
That however means that the binary will not be build with VC++, rather GCC, which may cause some windows programmers to cringe. I'd like to learn just how much performance is really lost. I also wonder what sort of ABI boogie-men are lurking.
To summarize
1. Portable code - Done
2. Cross-platform build system (with no need for windows license!!) - Check
3. Broad binary compatibility - Future is Hazy
Thursday, August 28, 2008
Distributed Identity in Virtual Worlds
Thinking about managing identity across various distributed grids of virtual worlds, I am of course drawn immediately to OpenID as the current preeminent solution to that problem. Let me explain the problem a little bit, and discuss how OpenID might fit in.
The Problem
VWs suffer from the same problem as website with regard to multiple sign-on. However due to the central role Identity makes in VWs, the problem is much magnified in its implications. Having single identities for each website you visit is merely a clerical annoyance -- remembering each user name and password -- and one that can be quite acceptably fixed with a smart enough user agent keeping track of each password, as Firefox now does.
However in a VW, having a new Identity for each grid of VW means having to recreate yourself each time you change worlds. You have to redesign your avatar appearance, rebuild your inventory, rebuild your social network, etc. An unacceptably large burden that turns the "metaverse" into a series of "walled gardens".
What we need is a means of
- asserting a unique identity agreed to by all observers
- mapping of that identity to a common specification for appearance, inventory, etc.
For this post, we will only be considering how to enable item 1.
Thinking about solutions
The obvious means of asserting identity, at least for those of us who have followed any cryptographic developments within the past decade, is for the user agent in question to generate a asymmetric key pair, and use it to pass to the VW a digital signature.
However as we well know, an endpoint directly asserting a signature without a public third-party is vulnerable to a man-in-the-middle attack. However if there was a public third party from which he could receive your public key, then that could be avoided (so long as the third party is actually publicly trusted).
Also, the tools for generating, maintaining, and using an asymmetric key set are far from ubiquitous and user friendly. If we really want it to be something that everyone can agree on and use, is has to be practicable for the average computer user. If we wanted to use PKI directly, we would have to create a standard protocol for use in VWs, write a standard implementation, then convince everyone to use it. Otherwise we'd have nothing more than cryptographically secure walled gardens.
The simplest way to take the burden off the end-user from maintaining his own identity is to outsource it a third party as much as possible. Also we can increase the odds that various VWs might standardize on something third party.
An interesting security property of having a 3-way negotiation, is that if any one party feels that they might be being lied to by one other party, they can always verify with the third. So it takes two parties collaborating with each other to create a deception.
With special consideration towards having a protocol that could be standardized on, and already has existing implementations, we look at OpenID to see how it measures up to our criteria, and what flaws it possesses.
OpenID Protocol
I recommend you read for yourself here and here, however I will provide a brief overview of how it works.
Let us define:
User Agent: The end user's Web browser, which we will denote AliceFox.
Relying Party: A Web application that wants proof that the end user controls an Identifier, which we will denote BobBlog.
OpenID Provider: An OpenID Authentication server on which a Relying Party relies for an assertion of identity, which we will call CarolCert.
Identity: A URI that represents an identity that AliceFox will assert, and and CarolCert will corroborate. Notice that this identity is "for" AliceFox, but cannot exist outside the context of CarolCert. The two are inextricably tied. We will denote AliceFox's identity with CarolCert as alice.carolcert.com.
Protocol:
AliceFox (A) wishes to assert her identity alice.carolcert.com (I) to BobBlog.com/comment.cgi (B) for the purpose of submitting a comment under that identity. She POSTs I to B through the comment form.
B GETs the URL I, which includes a "link" tag which points to carolcert.com/id.cgi (C). B redirects A to C, passing a "return to" parameter (R) and nonce (N) to C as GET parameters.
A and C confer amongst themselves is a manner undefined by the protocol in order to verify that A is in fact the entity known as I.
When C is satisfied of this fact, it prepares a reply to B by creating a secret key (K), a "handle" (H) that publicly identifies that secret key, and signs certain fields to ensure detection of tampering (S). C redirects A back to B with H and S attached as GET parameters.
If B carries state, B can negotiate (out of band??) the exchange of K with C using Diffie-Hellman key exchange, and use K to verify S.
If B is stateless, he merely echos A's message back to C to verify that A did not tamper with it en-route.
When B or C verifies S, B considers the identity successfully asserted, and associates A with I for the duration of the session.
What does OpenID Give
With that understanding in mind, what can we say about A and B, and what does I really mean to them?
It's important to point this out: all OpenID says from B's perspective is "A is an entity known to C as I". The delimiting context here is important to understand. A could have any multiple of identities with C, or any other OpenID provider. Moreover C could be anyone at all, even an untrustworthy party. OpenID says nothing about trust.
However, it is easy to create a trust-based system if one was to white list OpenID providers based on public reputation. It's certainly trivial to create a black list of known untrustworthy providers. This is certainly enough for our purposes as a distributed VW authentication system.
That said OpenID gives us much more. As we said above, its not hard to create our own simpler (and probably more secure) protocol. However that would entail writing an implementation, drafting a standard, ensuring it was practically deployable in working systems, and building critical mass for its adoption by all VW players. OpenID lets us skip that work, because its done already for us, and get straight to solving our own domain specific problems.
What does OpenID not Give
There is a well-known flaw in OpenID that can be used for phishing. If B is malicious, he can redirect A to his own copy-cat OpenID provider C', and if the user doesn't notice, C' can possibly steal A's credentials and allow a malicious party A' to impersonate A.
There are other means of misdirection as well. While a computer would always be able to tell that I and I' are different identities, humans might be confused if A and C are sufficiently similar looking to A' and C'.
The only solution to this is to white list known providers.
Another known problem with OpenID is the common reliance on passwords as a means of validating A with C. While that is no different from the password schemes currently in use on VWs or websites, I am sure a digital signature based protocol would be vastly superior from a technical standpoint.
My humble alternative protocol
Often the best way to judge a design is to consider how you would do it yourself, if you were tasked with making an alternative. I am happy to say that while what I started out with was quite different from OpenID, as I improved my protocol, I noticed that my decisions became more and more like those taken by OpenID, which is a good sign.
Warning: I am neither a security nor web expert, nor do I claim to be. Be gentle with your corrections.
This design also relies on cookies from one site being inaccessible from another. I have no idea how true this is in practice.
When A registers an identity I with C, A downloads an implementation of an asymmetric cipher in JavaScript that writes the private key K in a cookie, and the public key P in C's database.
A asserts identity I to B. Like OpenID, this is a URL that ties A to C, such as alice.carol.com.
Like OpenID, I contains a link to C, which B redirects A to, sending a return-to R and nonce N as GET parameters. Unlike OpenID, I also contains a link to P, which B downloads and associates with N.
C delivers to A a JavaScript program which opens K, encrypts N into a digital signature DS, then creates a message signature S to detect tampering. C then redirects A back to B, with N, DS, and S as GET parameters.
B verifies S, uses P to decrypt DS and verify it is the same as N. If so, B considers I successfully asserted.
Essentially C is nothing more than a repository for 1) public keys, 2) trusted JavaScript implementation of cryptographic algorithms.
Thoughts?
Posted by
Ryan McDougall
at
4:56 AM
0
comments
Labels: crypto, internet, technology, virtual worlds, work
Sunday, August 10, 2008
The Next Chapter
While I was at 3Di I had the pleasure of working with many real and potential partner companies from across the globe. Many times I succeeded only in embarrassing myself professionally; but I always tried to hold true to a sense of professional competence, ethics, and behaviour that stood for the kind of person I want to be. Not unselfishly, I hoped to be seen as a stand out guy, even if only to serve my own conceited self image.
Part of my professional ethic is that companies, as abstract entities, with no more life than that which the whim of its investors endow it, deserve no great respect or loyalty in and of themselves. Companies demand obedience, whether it be to laws or directives from superiors; but it's people that deserve respect and loyalty. And many times it's people outside your company, who's respect you've cultivated and earned, who go furthest in helping you accomplish your goals.
I hope that doesn't sound too shocking, because superficially it appears to be a contradictory to the notions of belonging and identity that most people hold. However if you look closer you might find merely a different definition of the same.
The purpose for someone like me to join a company, it's never about getting rich, it's always about creating something larger that yourself. Money is just a means to play the game, not the game in and of itself. On the other hand, for many people, joining a company is about keeping your head down so you can continue to earn a wage to fund whatever it is you'd rather be doing. People like that aren't going to join you in building new things.
I am happy to say that the result of my connections was several strong relationships with people from many different companies, industries, and backgrounds. Some of whom I haven't even ever met in person yet. When I informed those people that I would no longer be able to act as a liaison with 3Di due to my decision to leave, I was impressed with the level of interest in continuing working with me after 3Di. It didn't take very long for someone to offer me a job, but I am somewhat surprised at the quality of opportunity I have been given a shot at.
I have tentatively accept a role as senior engineer with RealXtend, an emerging leader in open 3D virtual worlds, to work with them directly in Oulu Finland. I will likely be involved in working with the open source community, general programming, and helping plot technical direction using the knowledge and insight I've cultivated during my short but eventful career in virtual worlds.
That means picking up the family and heading down to the equivalent of a small town to the north of Edmonton. While Oulu is quite a bit smaller than the some 35M people in the greater Tokyo area, I am actually relishing a chance to leave this mass of humanity behind for a while. I needed a new direction, under leadership that I can respect, and quite frankly, I am impressed beyond words at the professionalism and attitude that realxtend has shown in their work to get me over to Finland. These guys are great guys, and as I said to start out, it's the people there that have earned my respect and loyalty.
Saturday, July 26, 2008
Belated Happy L. Day, and other such Joyous News!
I know my blog entries have become scarce. There is a fair amount of change happening in my world, and what free time I do have generally goes to L., who demands it most insistently.
For those that don't know, I am finally leaving 3Di after over a year. The final incident that decided the matter was a bit of a much-ado-about-nothing due to political and cultural issues, and I finally realized that what I was doing wasn't rewarding enough to justify that degree of continued frustration. I told the management that something had to change or I would leave; and they sat on their thumbs, and said nothing, as they are wont to do, until I resigned as I said I must. And thus it was decided.
My entire career at 3Di might be considered one of trying to "fix things from the inside", but in the end it must be said that I have failed almost entirely. I don't blame myself for it, though I am hardly blameless -- no doubt my frequent lack of tact when complaining of systematic incompetence throughout the company lead to a situation where after a while no one would hear anything I had to say any more. However simply ignoring a rather insistent complaint doesn't make the root disease vanish, and so it's management's failure to own up to their own ... um failures and implement some real improvement, that was the ultimate ... ah failure. Fail.
That said I cherish my time at 3Di, as it has taught me a lot about technology, business, management, and myself. I am very glad that I joined this rollercoaster, and would do it again.
Where to go from here is a little unclear yet, but one thing I am fairly certain of, I don't wish to work for any Japanese capitalized/managed companies any more. I've had my share, and it's taught me that outside of some superstar companies like Toyota or Sony, (current?) Japanese business culture rewards mediocrity, hides incompetence, and punishes excellence. It obscures clear, precise communication, and is generally ill-suited for business outside of Japan. (This is a whole rant in and of itself!)
I am looking at western companies in Tokyo, a handful of foreign companies related to my work at 3Di, various companies back in Canada and the US. I am also considering taking some of my ideas from working at 3Di and seeing if anyone wants to do some research with me. Particularly I wish to study Scalability, Security, and Identity in Virtual Worlds (OpenSim).
And now time for something completely different.
Thursday, June 19, 2008
Every thing you need to know about a Programmer, you can learn from having them explain their own code to you.
I've been doing interviewing and hiring at our technology startup for almost a year now. When we began hiring, I found that I was basically the only person who would do it -- partly because I was the only person who displayed any sort of natural aptitude at judging another Engineer's technical and personal abilities.
It didn't take me long to create my own system which I thought was both fair to the interviewee (whom I empathized with, having been one for so long), and gave me a decent understanding of the candidate's qualities. With a little bit of intuition, and some trial-and-error, I evolved my system.
As the people I had interviewed and hired began to join me in the interviewing process, I got to notice how other people handled going from interviewee to interviewers, and how their outlook on a candidate's performance differed from mine.
This evolutionary process has lead me to solidify the following as my Golden Laws (tm) of hiring. Most people who are experienced with interviewing will not be surprised I think, but when a new person joins our team, I find that I need to explain these rules each time anew, so I thought I'd write them down.
1. Hiring is the single most important thing a company can do because it directly affects all other things that are done thereafter.
2. Hire only people you completely trust to fulfil a given role. Then completely trust those people.
3. Your job as an interviewer is NOT to hire "good" people -- that's an undecidable problem. Your job as interviewer is to REJECT substandard people.
4. The most critical personality trait to look for in a candidate is Honesty. All other important properties flow from that font. Dishonesty in an interview is the Kiss-of-Death.
5. Every thing you need to know about an Programmer, you can learn from having them explain their own code to you.
(And lastly, the Green Interviewer's Trap: Hiring is not a popularity contest. Most interviewees are a nice people.You are not required to hire nice people just because they're nice.)
The last law is the title of this entry because its perhaps the most controversial item. Yet I hold it to be the most essential truth I have discovered about hiring Programmers. So much so, I am going to let you in to my entire technical review process, and how it is centred around item 5:
The Sample
After reviewing the candidate's resume, and mentally making note of potential strengths and weaknesses, I always request a code sample from the candidate, in the following order of preference:
1. Open Source or otherwise Publicly Available Source
Open source is the best way to possibly find out how good a programmer is. A public SCM server has all history and contribution information regarding that project. You can graph a programmer's entire history with that code base to the most minute detail.
Mailing lists have discussions of technical matters, and help show how well the candidate gets along with other people.
Open Source is usually a work of passion, and outside the corrupting influence of bad company management, so you have already factored out the naked element of talent.
2. Redacted Source code taken from a company project (without violating any applicable laws, be careful)
Proprietary (but redacted in order to comply with confidentiality laws) source code is good because it shows what the candidate produces when given a real-world problem in real-world circumstances. Particularly it shows if they tend cut corners to meet deadlines or other practical constraints.
3. School Coursework (if a semi-recent graduate)
School coursework, if not too dated, is good because it shows what the candidate can do when asked to really apply their intellect to a serious problem. It's also an opportunity for the candidate to explain how his coding style has evolved over time, and why he would make different decisions today.
4. Toy Project selected by Candidate
Candidate-selected toy project is good because it shows what interest the candidate has if someone is not over their shoulder telling them what to do.
Do they choose something just difficult enough to meet your requirements? Do they choose something way too hard to complete in a reasonable amount of time? Do they report enjoying the exercise?
5. Toy Project selected by Me
One reason why I neglect this option to the last is that one must be respectful that candidates often are busy people, and they can and will turn down the interview because they feel they have better things to do than jump through your recruiting hoops.
6. Source written by Me
This is fun for showing off your work, and is realistic in the sense that programmers are routinely asked to do exactly that, however its rarely under such pressure situations. It's too easy to have a flustered programmer get thrown off by some minor detail, and thus you end up with incomplete reading of their true ability.
Either way, it is absolutely critical that the code is either hand-written by the candidate (or in cases where external code sources were used, clearly attributed as belonging to someone else), because we are going to ask them to explain its working to us. Clear attribution is critical because it is an unalterable part of our standard of honesty.
The Interview Prep
Once you have a sample of their code, you can of course review the code before the Interview to look at issues of Style, Correctness, Performance, Good Design. This is important. However the real purpose of reviewing the code is to generate questions for the candidate once he arrives to the interview. Ask yourself, "why did this person choose to make these decisions when writing the code?"
The Interview
When the Candidate arrives, I open the interview with a stupid joke or sarcasm. Partly because I often am as nervous as the candidate, and I want to break the ice. I also tell him that there are no "Right" answers in this interview, and no trick questions. It is important for the dignity of both parties to keep the interview cooperative, and to make it understood that you are both on the same side -- after you hire the candidate, you certainly will be counting on their cooperation and good will then!
Next I have a short list of simple, no-nonsense, general questions that I ask every candidate. For example "We are in the technology field, and as we both know, technology changes at a staggering rate. What methods do you use to keep on top of that change? Please be specific."
Next I have the list of questions generated from their sample code with me, and I move across the table to sit beside to the candidate with my laptop. I open their source code opened in a text editor (their preferred on if possible).
I ask the candidate to pretend that I am a Junior Engineer, and he must explain his code to me. As a curious person, I will stop them at various points to clarify the concerns I compiled during the Interview Prep, and put to rest any questions that happen to come into my mind as they are speaking.
What an observer can gather from this simple exercise is essentially everything you'll ever need to know about that person as a Programmer.
- A person who remembers even very old code is a person that was paying close attention when they wrote it, and understood the nuance of every line.
People who have trouble recalling what they wrote either didn't write it, or never understood it clearly when the wrote it.
- A person who speaks confidently and at a decent pace is a person at ease with their code and the decisions that code embodies. Even if the code is bad, a good programmer can justify their compromises in a rational manner.
People who speak in broad generalities, ramble incoherently, or carry off on tangents are more than just disorganized. They are trying to distract you from the fact that they don't know what they are talking about by burrying you in an avalache of verbage.
- A person who identifies their own mistakes and errors is more than just aware of their own mistakes, they are showing an honesty and desire to learn and improve. Similarly, people admit their don't know or understand some facet of the system.
A person who steadfastly insists on issues where you know him to be mistaken are not capable working with others, and should be rejected immediately.
- A person that can turn a complicated algorithm or technical trick into something easily understood by any simple engineer has not just a gift for teaching, but likely a deep and intuitive understanding of domain.
People who cannot relate technical matter without speaking entirely above your level may be brilliant, but could prove problematic if they have to work with others.
That said, even simple body language can tell you a lot about a candidate. One of the most dependable Engineers I've ever worked with failed horribly in trying to understand some source code I had written (possibly because I hadn't written it nearly as well as I thought I had!). Every time I asked him what a certain peice of code was doing, he politely answered "I don't know". What impressed me was the way in which he studied my code so closely, determined to fathom out my design through force of will. To this day his tenacity to reason through a problem completely is the hallmark of his good work with our company.
The wind-down
If I have come to a negative conclusion about the candidate, and decided not to continue, I ask the if he has any questions, then thank the person for their time, and ask them to leave.
If I have finished my walk-through on a positive note, I wrap the interview up with a brief explanation of my company, then invite the candidate to ask his own questions of us in a reversal of the interview process.
A complete and incisive set of questions for me to answer is a sign of a good candidate.
If I conclude that a person is technically competent, the next round of interviews include various members of our team, and are mostly about making sure that personalities match well, and that company culture is maintained.
If any one interviewer registers a "refuse" vote, then the candidate is refused.
Monday, April 21, 2008
Asterisk Realtime Architecture
Like any machine tinkered with heavily over time, Asterisk has a lot of exposed configuration points in a lot of places, and it can be hard to know how or why what you want to do isn't working because you neglected to set some variable that became necessary since the last time the module was documented.
I've fallen into this situation for the past couple days, and having finally found the right thing to tweak, let me write down how to use ODBC to access Asterisk's configuration files, including the dial plan, from a real-time database.
First thing: go read the official book by O'Reilly, and read the chapter on ARA.
Once you have downloaded Asterisk, as we did here, run ./configure, then make menuselect and ensure res_odbc, res_config_odbc, and all *_realtime modules are set
to be built. If they have a 'XXX' beside their name, it means that you need to install some dependencies. Search your package installer for "ODBC" and a database that supplies an ODBC driver, such as PostgreSQL or MySQL. You may also need the "-devel" version of those packages.
To make the tutorial complete, we'll pick a DB for the examples, so we choose PostgreSQL.
1. Setting Up the Database
As the DB's (not the system's) root user create a new role and database for Asterisk to use:
createuser -SRdP asterisk-role
createdb --owner=asterisk-role asterisk-db
Then restart the database.
2. Setting Up ODBC
Ensure that /etc/odbcinst.ini exists and contains something like the following:
[PostgreSQL]
Description = ODBC for PostgreSQL
Driver = /usr/lib/libodbcpsql.so
Setup = /usr/lib/libodbcpsqlS.so
FileUsage = 1
Ensure that /etc/odbcinst.ini exists and contains something like the following:
[asterisk-postgres-connector]
Description = PostgreSQL connection to 'asterisk' database
Driver = PostgreSQL
Database = asterisk-db
Servername = localhost
UserName = asterisk-role
Password = 123456
Then verify that the connection works using the following command:
echo "select 1" | isql -v asterisk-postgres-connector
3. Setting Up a Basic Asterisk Configuration
extconfig.conf
[settings]
sipusers => odbc,asterisk-postgres-connector,sip_table
sippeers => odbc,asterisk-postgres-connector,sip_table
extensions => odbc,asterisk-postgres-connector,extensions_table
extensions.conf
[general]
[default-sip]
switch => Realtime/@
modules.conf
[modules]
autoload=yes
preload => res_odbc.so
preload => res_config_odbc.so
res_odbc.conf
[ENV]
[asterisk-postgres-connector]
enabled => yes
dsn => asterisk-postgres-connector
username => asterisk-role
password => 123456
pre-connect => yes
sip.conf
[general]
4. Setting up Dialplan and Sip User/Peer Tables
This is perhaps the most mysterious point. The ARA requires a number of columns to be set within the table, and if they aren't it will silently fail. The SIP table in particular. Nearest I can tell, the only source of documentation is here.
Run the following SQL code as the asterisk-role:
CREATE TABLE extensions_table
(
"id" serial,
"context" varchar(20) NOT NULL default '',
"exten" varchar(36) NOT NULL default '',
"priority" smallint NOT NULL default '0',
"app" varchar(20) NOT NULL default '',
"appdata" varchar(128) NOT NULL default '',
PRIMARY KEY (id)
) WITHOUT OIDS;
CREATE TABLE sip_table
(
"id" serial,
"name" varchar(80) NOT NULL default '',
"host" varchar(31) NOT NULL default 'dynamic',
"nat" varchar(5) NOT NULL default 'route',
"type" varchar(6) check (type in ('user','peer','friend')) NOT NULL default 'friend',
"accountcode" varchar(20) default NULL,
"amaflags" varchar(13) default NULL,
"callgroup" varchar(10) default NULL,
"callerid" varchar(80) default NULL,
"call-limit" int NOT NULL default '0',
"cancallforward" char(3) default 'no',
"canreinvite" char(3) default 'no',
"context" varchar(80) default 'default-sip',
"defaultip" varchar(15) default NULL,
"dtmfmode" varchar(7) default NULL,
"fromuser" varchar(80) default NULL,
"fromdomain" varchar(80) default NULL,
"insecure" varchar(4) default NULL,
"language" char(2) default NULL,
"mailbox" varchar(50) default NULL,
"md5secret" varchar(80) default NULL,
"deny" varchar(95) default NULL,
"permit" varchar(95) default NULL,
"mask" varchar(95) default NULL,
"musiconhold" varchar(100) default NULL,
"pickupgroup" varchar(10) default NULL,
"qualify" char(3) default NULL,
"regexten" varchar(80) default NULL,
"restrictcid" char(3) default NULL,
"rtptimeout" char(3) default NULL,
"rtpholdtimeout" char(3) default NULL,
"secret" varchar(80) default NULL,
"setvar" varchar(100) default NULL,
"disallow" varchar(100) default '',
"allow" varchar(100) default '',
"fullcontact" varchar(80) NOT NULL default '',
"ipaddr" varchar(15) NOT NULL default '',
"port" smallint NOT NULL default '0',
"regserver" varchar(100) default NULL,
"regseconds" int NOT NULL default '0',
"username" varchar(80) NOT NULL default '',
"delay" int NOT NULL default '0',
"sortorder" int NOT NULL default '1',
PRIMARY KEY (id),
UNIQUE (name)
) WITHOUT OIDS;
GRANT ALL ON sip_table TO asterisk;
GRANT ALL ON extensions_table TO asterisk;
INSERT INTO extensions_table (context, exten, priority, app, appdata) VALUES ('default-sip', 'sip-extn', 1, 'Answer', '');
INSERT INTO extensions_table (context, exten, priority, app, appdata) VALUES ('default-sip', 'sip-extn', 2, 'Wait', '2');
INSERT INTO extensions_table (context, exten, priority, app, appdata) VALUES ('default-sip', 'sip-extn', 3, 'Playback', 'hello-world');
INSERT INTO extensions_table (context, exten, priority, app, appdata) VALUES ('default-sip', 'sip-extn', 4, 'Wait', '2');
INSERT INTO extensions_table (context, exten, priority, app, appdata) VALUES ('default-sip', 'sip-extn', 5, 'Hangup', '');
INSERT INTO sip_table (name, context, host, type) VALUES ('sip-user', 'default-sip', 'dynamic', 'friend');
5. Test the setup
Run Asterisk on the console, and verify the ODBC connection is working by issuing the command odbc show.
Don't bother trying to run dialplan show or similar, as this will not display what we inserted in the previous step. Instead we need to make a call to test: in your soft-phone, dial sip:sip-extn@asterisk.example.com, and you should hear a voice say "hello world".
Thursday, April 17, 2008
Working with Asterisk
Recently I have been working on some VoIP based solutions using Asterisk.
I've found it a bit hard to work on, partly because Asterisk appears to suffer from some ad-hoc growth over time, and not only is the design somewhat dated, but more importantly the documentation left around the web appears to be tied to past versions such that working with the newest versions can leave you scratching you head why what one guy did, and what you're doing don't seem to match up. Even when you manage to get the example working you're never quite sure which flag you twiddled happened to do the trick.
(Aside: there seems to be a lot of consulting business around Asterisk. Partly this is due to the inherently Enterprise-related nature of a PBX. However I have to wonder if these consultants don't have a vested interest in keeping Asterisk opaque. Certainly they'd have more clients than if the community spent time making it easier to use.)
First thing one needs to do when learning a system is to make some small examples. The easiest way to test your examples, lacking the sort of hardware one might have if they owned a real Enterprise phone system, is to use software phones. The most common kind of software phone is one that uses SIP to set up an audio stream (over RTP) for voice communication.
To obtain a working Asterisk server, download either the source, or a pre-compiled binary from your favorite location. If you're working a lot with Asterisk it makes sense to build the source yourself, since it's rather easy to build.
After you have completed the install, your /etc/asterisk/ directory should be full of a wild assortment of configuration files, each over-teeming with tweak-worth options. However just to set up a simple call, we don't need such complexity. Copy those files to a safe place, and consider the minimal files below:
modules.conf
As far as I can tell, this is all you'll ever need from modules.conf, under any situation.
[modules]
autoload=yes
This means that as Asterisk looks for .conf files (which we have mostly removed), and processes its internal and external dependencies, it will automatically load the binary files in /usr/lib/asterisk/modules.
sip.conf
This file controls the SIP input "channel", from which any session created from sip:a-sip-user@example.com to sip:somewhere@asterisk.example.com, must pass first on its way through an Asterisk system. The call from a-sip-user is assigned a "context" which is where in the "dialplan" the call should be routed. ("user" means that the call is in-bound only, and "dynamic" means the server should look up the user's IP address dynamically)
[a-sip-user]
context=my-sip-context
type=user
host=dynamic
This means that anyone who call into Asterisk, and declares themselves to be "a-sip-user" via their SIP URI (such as sip:a-sip-user@somewhere.example.com), is given a dial plan context of "my-sip-context".
extensions.conf
This is the "dial plan", the place where the routing logic of a PBX is stored. It consists of a number of named contexts, under which a series of sequential functions are called. It will appear odd to a modern programmer, but if one considers the evolution of old-fashioned hardware based PBXs, it makes more sense.
Basically there is first an "extension", which is related to the old extension numbers you would have to dial over an old-fashioned system. However with software based PBXs, those extensions can now easily be human-readable strings.
A call is brought in to the dial plan from a channel. The only channel we are considering now is a SIP-based VoIP call. That channel attached a context to the call, and starting from the named context, the dial plan attempts to match an extension pattern to the one specified in a call.
In the case of a SIP call, where the URI is sip:my-destination@asterisk.example.com, the extension is considered to be "my-destination".
[my-sip-context]
exten => sip-extn,1,Answer()
exten => sip-extn,n,Wait(2)
exten => sip-extn,n,Playback(hello-world)
exten => sip-extn,n,Wait(2)
exten => sip-extn,n,Hangup()
This means that when dropped in the "my-sip-context" context, Asterisk will attempt to match the extension against "sip-extn". The first action to be taken is to answer the call. The steps with priority marked "n" proceed sequentially from each other.
In the example above, the soft-phone must dial the following URI: sip:sip-extn@asterisk.example.com as the user designated sip:a-sip-user@somewhere.example.com. Upon doing so, they should hear a female voice saying "hello world!"
If you are using ekiga as your soft-phone, go to Edit->Accounts, and then add a new one. The name can be any thing you like, however the registrar must be asterisk.example.com (that is the name or IP address of the machine running Asterisk), and the user must be a-sip-user. The password is empty because we have not required password protection in sip.conf.
Click OK and confirm that the Status indicates that it is registered with the server. If registration fails, check that the server's firewall is not blocking port 5060, and that you are not using the soft-phone from the same machine that Asterisk is running on since port numbers will conflict.
In the top-most address bar, enter the URI sip:sip-extn@asterisk.example.com and click enter. You should now hear the words "hello world!"
The version of Asterisk I used was 1.6.
Saturday, March 8, 2008
What Ive been up to at work
So the entire executive team has been replaced with a far more experienced and professional team.
Since the change I have been very busy getting work done, and trying to march towards getting products out the door, and money back in.





