Tag Archives: Life Hacking

Optimal Distance

This morning I read the Atlantic piece Finding The Next Edison* in which Derek Thompson touches upon the notion of “optimal distance”.  This idea made me reflect upon Hamming’s 1986 talk You And Your Research, the transcript of which I find myself re-reading every few years for inspiration.

To exist optimally distant from a problem entails possessing an expertise close enough to it that you can understand the basics and tinker with solutions but far enough to avoid an over-familiarity that breeds complacency and groupthink.  If, for example, you are laboring to help NASA predict solar-particle events, you’ll likely flounder if you’re an English Literature professor, and you might bog down in the status-quo if you’re a NASA-lifer, but being a retired telecommunications engineer might make you the perfect outsider.

This harkens back to Hamming’s lamentation that…

“When you are famous it is hard to work on small problems. This is what did Shannon in. After information theory, what do you do for an encore? The great scientists often make this error. They fail to continue to plant the little acorns from which the mighty oak trees grow. They try to get the big thing right off.”

Regarding which he counsels us to…

“Somewhere around every seven years make a significant, if not complete, shift in your field. Thus, I shifted from numerical analysis, to hardware, to software, and so on, periodically, because you tend to use up your ideas. When you go to a new field, you have to start over as a baby. You are no longer the big mukity muk and you can start back there and you can start planting those acorns which will become the giant oaks.”

*: We’ll ignore for the moment that Edison was more businessman than inventor and that the piece would have been better titled Finding The Next Tesla.

StarCraft Life Lessons

After a hiatus of seven years, StarCraft has come roaring back into my life with the release of StarCraft 2. Given the game’s phenomenal richness and complexity, I cannot help but draw parallels between its challenges and those of life writ large.

To succeed at StarCraft, a player must be able to shift between macro and micro management tasks as well as cycle with fanatic discipline through a variety of distinct but intimately related macro management tasks. Focus too long on micro management tasks, and though you may win present battles, you’ll find yourself without troops to micro manage later. Focus overly much on particular macro management tasks, and you’ll eventually find those tasks impossible and undermined. The various facets of StarCraft make up a tightly coupled system of systems that all must operate well to be successful. So, too, with “real” life…

A solid StarCraft player is running a tight loop in which he/she polls a variety of subsystems and issues commands to them to optimize the system’s state. Such high level queries follow…

  • Are adequate workers being built?
  • Do I have idle workers?
  • Do I have adequate supplies?
  • Do I have enough resource flow?
  • Do I have enough production capacity?
  • Am I spending my resources?
  • Do I know what kinds and quantities of units my adversaries are building?
  • Do I have enough expansion bases?
  • Can I see enough of the map?
  • Have my adversaries acquired expansion bases?
  • Do I know where my opponents’ units are?
  • Are my units well positioned?
  • Have I upgraded my units’ strength and abilities?
  • Am I about to be attacked?
  • Am I harassing my adversaries enough?
  • Can I handle cloaked enemy units?
  • Can I handle highly mobile enemy units?
  • Can I handle long range enemy units?

You do not want to switch to a sub-task because it became a problem. Rather, you want to cycle through tasks and hit each one before it becomes an issue. If you’re frantically building Turrets in your base because you’re being overrun by cloaked Banshees, you’re doin’ it wrong. If you’re popping out additional Supply Depots because your supplies are maxed out, you’re being reactive instead of proactive. More generally, if you’re only doing a task because some other task is actively blocking on it then you are doomed.

The exigencies of life have a way of making one focus on the most obviously looming problems at the expense of other issues until they start to provide more concrete impact. Therein lies the path to unhappiness and ineffectiveness. If you’re expending all of your effort on your project at the office, then you’re neglecting your health, neglecting financial management, neglecting continual learning, neglecting to keep up on current events, neglecting your relationships, and so on. Eventually these neglects will undermine the thing on which you are attempting to focus, causing you to fail at everything.

To break out of such a rut requires a conscious and concerted effort. Build a loop in which you poll the various facets of your life. Keep asking “Am I making progress in this arena of my life?”. Keep a trail of your progress and/or set and observe concrete milestones. Keep a journal. Keep a log book. Keep shelves of books you have read. And so on…

But don’t go for 300 Actions Per Minute in your daily life… The frenetic pace of StarCraft is not the pace one wants in life as a whole. That said, the regular and proactive monitoring and management of multiple tightly related sub-goals can serve as the underpinnings of a satisfying life.

To be more relevant to a purported software blog… A successful software project presumably also results from a well run “health” management loop…

  • Am I delivering useful features to customers?
  • Am I returning to messy code and cleaning it up?
  • Am I writing enough automated tests?
  • Is there enough documentation?
  • Do I have good configuration management?
  • Am I validating the usability of the user interfaces?
  • Am I exposing good APIs?
  • Is the system going to scale?
  • Am I managing compliance issues successfully?
  • Am I making good use of existing technologies?
  • Am I anticipating the impact of coming technologies?
  • Are my team members in good spirits and growing?
  • Am I aware of my competitors’ status and plans?
  • Am I keeping my partner organizations adequately informed?
  • Am I keeping my management apprised of political and resourcing issues?

— AWG

Overhead

A long time ago in a galaxy far away, I was a high school student. In hindsight, this involved many artificially tedious things that I took for granted in the same way that I accepted various laws of Physics. The want of superior technology resulted in all manner of needless inefficiencies and cumbersome overhead. Such impedances ultimately drove down the rate at which I could ram knowledge into the confines of my skull. One particularly good example thereof involves my studies of the French language. Specifically, looking up words that I did not know entailed an inordinate amount of work.

When reading a piece of text in a foreign language, one can choose from two modes of operation when dealing with unknown words. Either one can stop at every unknown word and look it up, or one can read all the way through the article without worrying overly much about comprehension, recording unknown words along the way and translating them in batch mode at the end, and then read through the article again. Both have their advantages and drawbacks. The as-you-go approach avoids an extra reading, but the regular interruption to go to a dictionary proves highly disruptive. The batching approach reduces disruption, but in some ways it results in extra work, such as looking up words you might have understood from context if some other word had been known sooner rather than later.

This represents a false dichotomy, thrust upon the student by non-availability of technology that reduces the expense of context switches. Instant translation that does not force a disruptive modality changes the rules of the game. The appearance of online dictionaries improved things significantly. Not having to thumb through a dictionary reduces the context switch overhead enormously. It does, however, still involve an unfortunate amount of clumsiness and flow disruption. Ideally, when reading a sentence that contains an unknown word, one ought with a single keystroke be able to start a parallel process that brings up a translation without disrupting completion of the sentence being read. Having to copy and paste a word into a web browser and then wait for the response soon becomes irksome.

I have for some time now had a decent solution to this problem embodied in an Emacs extension. During my vacation of this week I decided to improve and generalize it. The reader may find the full code at the end of this essay.

The extension makes use of the W3M library for browsing in Emacs and a modicum of custom elisp to glue everything together. The extension exposes a simple plug-in system of its own that allows the user to integrate with different translation systems. The code exhibits sufficient compactness and descriptiveness that its mechanics ought to be mostly self-evident.

The end result is that I can press F5 and enter a URL, say http://www.lemonde.fr, and commence browsing French articles within Emacs. When I encounter a French word that I don’t know, I put the cursor over it and press F6. My current window stays open so I can continue to read. Eventually my definition appears and I peruse it. When finished with it, I press F8 and the definition vanishes. The whole process is the same except for hitting F7 instead of F6 if I happen to be perusing, say, http://www.welt.de.

One mildly obnoxious thing about the W3M library is the inability to specify a callback function to be invoked when an asynchronous W3M function completes. Since I wanted my translation plug-ins to have such a callback faculty, I had to switch the W3M library’s mode of operation from asynchronous to synchronous. A word to the wise for library writers: if you expose an asynchronous API, you should always provide a hook via which “after” callbacks can be invoked. Failure to do so renders the lives of API users needlessly difficult.


(add-to-list 'load-path "~/emacs-w3m-1.4.4")
(require 'w3m-load)

(defcustom w3m-async-exec nil
  "*Non-nil means execute the w3m command asynchronously in Emacs process."
  :group 'w3m
  :type 'boolean)

(defun grab-word-under-cursor ()
  (forward-char 1)
  (backward-word 1)
  (mark-word 1)
  (copy-region-as-kill (point) (mark))
  (car kill-ring))

(setq translator-hash (make-hash-table :test 'equal))

(defun add-translator (source-lang target-lang url-constructor post-load-hook)
  (puthash (concat source-lang ":" target-lang)
           (cons url-constructor (cons post-load-hook nil))
           translator-hash))

(defun get-url-constructor (source-lang target-lang)
  (car (gethash (concat source-lang ":" target-lang) translator-hash)))

(defun get-post-load-hook (source-lang target-lang)
  (car (cdr (gethash (concat source-lang ":" target-lang) translator-hash))))

(defun translate-word (word source-lang target-lang)
  (split-window-vertically)
  (other-window 1)
  (w3m-goto-url-new-session
   (apply (get-url-constructor source-lang target-lang) word nil))
  (let ((post-load-hook (get-post-load-hook source-lang target-lang)))
    (if (not (equal nil post-load-hook)) (apply post-load-hook nil))))

(defun translate-current-word (source-lang target-lang)
  (translate-word (grab-word-under-cursor) source-lang target-lang))

(add-translator
 "french" "english"
 (lambda (word) (concat "http://www.wordreference.com/fren/" word))
 nil)

(add-translator
 "german" "english"
 (lambda (word) (concat "http://dictionary.reverso.net/german-english/" word))
 (lambda () (search-forward "See also:") (recenter 0) (beginning-of-line)))

(defun translate-current-word-french-to-english ()
  (interactive)
  (translate-current-word "french" "english"))

(defun translate-current-word-german-to-english ()
  (interactive)
  (translate-current-word "german" "english"))

(defun kill-and-close ()
  (interactive)
  (kill-this-buffer)
  (delete-window (selected-window)))

(global-set-key [(f5)] 'w3m-goto-url)
(global-set-key [(f6)] 'translate-current-word-french-to-english)
(global-set-key [(f7)] 'translate-current-word-german-to-english)
(global-set-key [(f8)] 'kill-and-close)

— AWG