My ideal job is anywhere where I can:
1. Learn and improve myself as a technician and human
2. Improve the world around me through my skills as an engineer and leader
3. Enjoy the passion and comradery of a truly unique group of people
In more concrete terms I find that the kind of workplaces that foster such an environment tend to be those in R&D, academic, or Free Software companies. I think what I consider to be an ideal company, right down to the details, is already well known and commonly held among serious professional programmers, the kind of people my ideal company staffs itself with.
I want to be exposed to a large breadth and depth of technologies, and given a chance to challenge myself. I want to work together as a team to accomplish things I could have never done alone.
I consider life to be a marathon race until death, not a sprint until twenty or thirty years old.
I want to die a great man in the judgment of the people who are closest to me.
And I realize that the only path to where I want to go is one with daily dedication to learning and growing just a little bit more than yesterday -- from this moment, until the time when the world passes me by.
Its in this way that I take my work, my life, seriously; but no more serious than I take the rising sun, or my daughter's smile. As it should be.
My idea workplace would be one where people understand, and agree, and walk with me down this road.
Tuesday, January 22, 2008
I HATE filling out those custom CV forms on job sites
I have a dream
I'm not big into politics, especially American politics, but I think it is the perfect timing for rare moment when someone brings a message that brings out the very best in our human nature.
Saturday, January 19, 2008
(Haskell) Monads for Imperative Peeps
Warning, since I am still learning Monads, it's quite possible the following is partially or even entirely wrong.
Why Monads
Functional programming languages have the constraint that their functions cannot have any side-effects. A function cannot do anything except produce a return value which is strictly dependent on its input values.
This is done for many good reasons. One such reason is to allow allowing some pretty mean performance optimizations: specifically allowing each individual "pure" function to run on their own processor core, since by definition each function is dependent on its input only, and can run efficiently this way.
However this constraint effectively eliminates entire sub-sets of useful and essential operations. Most notably IO operations such as printing or reading from the console.
A monad is a abstract idea that allows functional languages to stay theoretically coherent by encapsulating side-effect producing operations within themselves. Monadic functions can then be separated from the remaining pure functions when optimizing.
Monads are also extremely useful for encapsulating entire classes of behavior by type. For example a monad for functions that print or read from an OS provided data source is called IO. For functions that print or read strings from the console, the embedded type for IO would be String, and thus their type would be String -> IO String.
What are Monads
In programming languages, monads are meta-types that embed other types.
A monad has 3 parts:
1. A type construction, which defines how to embed a type in the monad
2. A unit function, which explains how to place a value of a type into a value of the monad, "as is"
3. A binding operation, which explains how pull out a value of a type from the monad, apply a pure function to it, and return the result to the monad
As an example we will construct a monad called Maybe that defines a type who's values are either invalid, or from a valid range:
1. data Maybe t = Just t | Nothing
Which says that the monadic type Maybe with parameter type t is a type who's values are of type "Just t" or "Nothing". Nothing is the type of invalid values.
2. return x = Just x
Which defines a function that wraps any value in the identity type Just, and thus embeds it the monad Maybe by our definition in 1.
3. (Just x) >>= f = f x
Nothing >>= f = Nothing
Which says that any function f can be applied to the type Just x as a normal, every-day function call; but any value of the Nothing type always yields Nothing. This means that whenever an invalid value is encountered, all functions from that point on are also invalid.
Posted by Ryan McDougall at 4:03 PM 0 comments
Labels: functional programming, programming, programming trickery
Tuesday, January 15, 2008
It's Ironic
They flee from me that sometime did me seek
With naked foot, stalking in my chamber.
I have seen them gentle, tame, and meek,
That now are wild and do not remember
That sometime they put themself in danger
To take bread at my hand; and now they range,
Busily seeking with a continual change.
Thanked be fortune it hath been otherwise
Twenty times better; but once in special,
In thin array after a pleasant guise,
When her loose gown from her shoulders did fall,
And she me caught in her arms long and small;
Therewithall sweetly did me kiss
And softly said, "dear heart, how like you this?"
It was no dream: I lay broad waking.
But all is turned thorough my gentleness
Into a strange fashion of forsaking;
And I have leave to go of her goodness,
And she also, to use newfangleness.
But since that I so kindly am served
I would fain know what she hath deserved.
--
Friday, January 11, 2008
Always Plotting Something...
An amazing source for a tool I always found hard to figure out: gnuplot.
Saturday, January 5, 2008
Friday, January 4, 2008
Thinking in git
"git" is a distributed source code management tool that is gaining a lot of interest from many corners of the international software development community due to its incredible flexibility and power. I like to compare it to powerful text editors like Vim or Emacs: it has a steep learning curve, but once you pick it up it will increase your productivity immensely, and if you are a professional programmer who takes himself seriously, you owe it to yourself to learn it fully.
However, using this new power-tool, like all specialized tools, requires readjusting you way of thinking about how you work before you can take advantage of the benefits.
1. Your local clone is also a repository in its own right
A repository is a .git directory. Every functional instance of a .git directory represents a full-featured repository, regardless how you came to possess it.
Its a deceptively simple but profound change in perspective. Ponder the implications fully.
2. All repositories are created equal
There is no inherent security policy in git (you have to piggy-back on SSH or Apache for that), and there is no sense of hierarchy among repositories that you do not define yourself through external policy.
Once you clone a branch from a remote repository, the originating branch is technically no more authoritative than yours is. The only technical constraint on branching and merging across repositories is that all branches must have a coherent history.
If two branches across repositories grow apart over time, and it is desired to reunite them into a common public branch, anyone attempting merge the two must reconcile the histories is such a way that other repositories are able to recognize the history as either a common ancestor of a local branch, or reachable future given their current state.
3. Branch everything
Branching and merging is the bread and butter of a SCM, so it hopefully goes without saying that branches are trivial, and merges are as smart as possible for a machine, so use them.
Branch to test out a idea. Branch to test out a merge. Branch to impress your friends at cocktail parties.
4. Git is a low-level tool
Git, from the beginning, was designed to be a low-level storage format for a Distributed SCM, and its only recently that git has included within itself some high-level commands for the kind of basic operations that programmers care most about. If you take the time to understand the basic representation that git uses, you will find it harder to get confused about why the high-level commands do things you didn't expect them to do.
Git assumes very little about a programmer's workflow, and converts your commands to into rather simplistic and literal manipulations upon the basic data structures within the .git directory, so it pays to take a look inside the internal representation once and a while to verify your assumptions.
5. You can break your own repository, and others'
Since git makes almost no assumptions about your work flow, contains no inherent security policy, and has no concept of repository hierarchy, it is very easy to do something that can seriously ruin anyone's repository.
Git tries hard to be non-destructive when making changes, but it will always do exactly what you ask of it. And while an experienced git user can likely recover from a whole host of mistakes, there is no guarantee that you can.
While learning git, always back up your working source and .git directory regularly. Always make new branches to test out your actions before you proceed on important branches. And finally, take care when pushing/pulling changes to/from someone else's repository.
6. Every commit is a change, uniquely identified by a SHA-1 hash number
The basic currency of git is a set of changes to the .git data structure represented by a commit, and every commit is uniquely identified by a SHA-1 number.
7. A repository is a directed acyclic graph of commits, with named branches
As commits succeed commits, a linear history is built within the .git directory. When a branch is made it is given a name, and when a commit follows, the history becomes a tree and thus non-linear. When a merge happens, the two histories are joined together under one of the named branches.
Since history only proceeds in one direction, the graph is acyclic.
8. Commits and branches exist in your .git directory, not your working directory
Git stores the above DAG compressed in data structures in your .git directory. The files that appear in your working copy is only a decompressed representation of those structures, after they have been processed by your git commands.
If files appear to be out of place or missing, consult the git command line tools to inspect the .git repository first.
Culture Clash
I often find myself complaining internally about all the things I find broken about Japanese culture, and why it needs to change before it can join the ranks of modern societies. However instead of being so negative, I thought I'd turn things around and talk about how Japanese handle certain kinds of problems and how their backwardness is wisdom in disguise -- something they have discovered that the rest of the world, especially Americans, really need to figure out before they can be called civilized:
While ignoring a problem will never make it go away, many times turning a blind eye to a problem really is simply the best choice among worse alternatives: Attempting to fight against a tide that is not ready to change will only make things worse, and the best option you have available is to just ride it out.
Its tempting to look at Japanese who are ignoring a glaring problem by putting their head in the sand as childish and irresponsible, and take the position that our western tendency to leap on problems as obstacles to be overcome through a vigorous response, is clearly the progressive and adult way to handle our difficulties.
However if we take the position that we must clearly examine the real-world results of both active and passive responses, we will find that the reality is that our desire to interfere in things we cannot actually control often only makes things worse. And the so the "foolish" course of ignoring problems allows conditions beyond our control to work themselves out in time; without requiring our personal intervention, and thus actually turns out to be the only method of reaching a positive outcome.
So often our ethnocentrism is just not justified in practice. And with a change of perspective we find ourselves viewing our actions not as being proactive and adult-like, rather childishly self centered, impulsive, and obstinate (-- as Japanese view them).