<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Vijay Talks Tech</title><link href="https://vijay.varadan.com/talks/" rel="alternate"/><link href="https://vijay.varadan.com/talks/feeds/all.atom.xml" rel="self"/><id>https://vijay.varadan.com/talks/</id><updated>2026-08-06T09:00:00-07:00</updated><entry><title>macOs grep -f Is a Nested Loop Join; Use ripgrep or mawk Instead</title><link href="https://vijay.varadan.com/talks/macos-grep-f-is-a-nested-loop-join/" rel="alternate"/><published>2026-08-06T09:00:00-07:00</published><updated>2026-08-06T09:00:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2026-08-06:/talks/macos-grep-f-is-a-nested-loop-join/</id><summary type="html">&lt;p class="first last"&gt;BSD grep runs every pattern over the whole file, at 6.5 ms per pattern per mebibyte. ripgrep, GNU grep and mawk each build one lookup structure and make a single pass.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;object data="https://vijay.varadan.com/talks/images/nested-loop-header.svg" type="image/svg+xml"&gt;4887x: the same job through the grep macOS ships and through ripgrep, a thousand patterns over 128 MiB. /usr/bin/grep 13 minutes 56 seconds, ripgrep 0.171 seconds&lt;/object&gt;&lt;/p&gt;
&lt;p&gt;If &lt;tt class="docutils literal"&gt;grep &lt;span class="pre"&gt;-F&lt;/span&gt; &lt;span class="pre"&gt;-f&lt;/span&gt; patterns.txt&lt;/tt&gt; has been running for hours on a Mac, the size of your file probably isn't the problem.
The &lt;tt class="docutils literal"&gt;grep&lt;/tt&gt; in &lt;tt class="docutils literal"&gt;/usr/bin&lt;/tt&gt; is BSD grep, and it runs every pattern over every line, so what it costs you is your
pattern count multiplied by the size of your file. Two things to run instead:&lt;/p&gt;
&lt;pre class="code bash literal-block"&gt;
&lt;span class="c1"&gt;# ripgrep: matches anywhere on the line, the way the grep you have does.
&lt;/span&gt;brew&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;ripgrep&lt;span class="w"&gt;
&lt;/span&gt;pigz&lt;span class="w"&gt; &lt;/span&gt;-dc&lt;span class="w"&gt; &lt;/span&gt;data.csv.gz&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;IFS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;h&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'%s\n'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$h&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rg&lt;span class="w"&gt; &lt;/span&gt;-aF&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;ids.txt&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pigz&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;filtered.csv.gz&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# mawk: faster still, when the match sits at a known position in the line.
&lt;/span&gt;pigz&lt;span class="w"&gt; &lt;/span&gt;-dc&lt;span class="w"&gt; &lt;/span&gt;data.csv.gz&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;LC_ALL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;C&lt;span class="w"&gt; &lt;/span&gt;mawk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'NR==FNR{p[$0];next} FNR==1||(substr($0,1,36) in p)'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ids.txt&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;pigz&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;filtered.csv.gz
&lt;/pre&gt;
&lt;p&gt;I ran into this filtering 1122 universally unique identifiers (UUIDs), one per line in &lt;tt class="docutils literal"&gt;ids.txt&lt;/tt&gt;, out of a
comma-separated values (CSV) export of 330 GB (329,691,473,398 bytes) and 1.27 billion (1,272,998,467) lines, 10.3 GB
gzipped. BSD grep was heading for a month. The mawk pipeline took 3 minutes 40 seconds.&lt;/p&gt;
&lt;div class="section" id="the-cost-is-6-5-milliseconds-per-pattern-per-mebibyte"&gt;
&lt;h2&gt;The Cost Is 6.5 Milliseconds per Pattern per Mebibyte&lt;/h2&gt;
&lt;p&gt;Whether this will bite you comes down to two numbers, how many patterns you have and how big the file is. I timed
three pattern counts against three slice sizes of that file, twice each, on an Apple M5 running macOS 26.5.2 with BSD
grep 2.6.0-FreeBSD:&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;colgroup&gt;
&lt;col width="24%" /&gt;
&lt;col width="24%" /&gt;
&lt;col width="26%" /&gt;
&lt;col width="26%" /&gt;
&lt;/colgroup&gt;
&lt;thead valign="bottom"&gt;
&lt;tr&gt;&lt;th class="head"&gt;Patterns&lt;/th&gt;
&lt;th class="head"&gt;8 MiB&lt;/th&gt;
&lt;th class="head"&gt;32 MiB&lt;/th&gt;
&lt;th class="head"&gt;128 MiB&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0.58 s&lt;/td&gt;
&lt;td&gt;2.14 s&lt;/td&gt;
&lt;td&gt;8.70 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;5.12 s&lt;/td&gt;
&lt;td&gt;20.62 s&lt;/td&gt;
&lt;td&gt;82.20 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;1000&lt;/td&gt;
&lt;td&gt;50.47 s&lt;/td&gt;
&lt;td&gt;206.44 s&lt;/td&gt;
&lt;td&gt;835.69 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Every cell is the mean of two runs, which were within a 5% spread at the smallest and a 0.5% spread at the largest.
Multiply the pattern count by the mebibytes and then by &lt;strong&gt;6.5 milliseconds&lt;/strong&gt;, and you have the time. Eight of the nine
sit within 5% of a flat rate over a span of 1600 in the product and 1440 in the time; only the smallest, at half a
second, is further out, and that's start-up.&lt;/p&gt;
&lt;p&gt;So the two figures to keep are that &lt;strong&gt;about 1500 pattern-mebibytes is ten seconds, and about 9000 is a minute&lt;/strong&gt;. A 2
GiB file against 50 patterns is 102,400 of them, which is eleven minutes. My 1122 patterns against 330 GB were 353
million, which is 26 days, and from the two progress checks below I got 27 days and 29, independently of it.&lt;/p&gt;
&lt;p&gt;If your own product is in the low hundreds, none of this matters and BSD grep is fine. The rest of this page is for
everyone above that.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="every-line-against-every-pattern-is-a-nested-loop-join"&gt;
&lt;h2&gt;Every Line Against Every Pattern Is a Nested Loop Join&lt;/h2&gt;
&lt;p&gt;BSD grep reads a line, then evaluates the pattern set against it one pattern at a time: your lines on the outside,
your patterns on the inside, which is a nested loop join. The comparison count is the Cartesian product of the two,
and each of those comparisons has to scan the line it lands on, which is how a count of lines turns into a count of
bytes and gives you the rate in the table above. All the slices I timed came out of one file, where the lines and the
bytes rise together, so these runs don't separate the two; the per-comparison scan is the reason to expect bytes to be
the factor that matters.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-f&lt;/span&gt;&lt;/tt&gt; is only the usual way to hand grep a large set, not the trigger. Over the same 2 MiB, a hundred patterns as a
hundred &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-e&lt;/span&gt;&lt;/tt&gt; flags cost 1.20s where &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-f&lt;/span&gt;&lt;/tt&gt; costs 1.21s, and folding them into one &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-E&lt;/span&gt;&lt;/tt&gt; alternation is 1.6x faster
at 0.75s, against the hundredth of a second GNU grep takes on that identical alternation. If you have a lot of
patterns, how you spell them barely matters.&lt;/p&gt;
&lt;p&gt;GNU grep compiles the pattern set into one automaton instead and makes a single pass, so adding patterns to it is
nearly free. mawk loads them into a hash and looks up one substring per line, which arrives at the same place by a
different route.&lt;/p&gt;
&lt;p&gt;The &lt;a class="reference external" href="{filename}filtering-a-330gb-gzipped-csv-with-duckdb.rst"&gt;same thing happens in DuckDB&lt;/a&gt;, where &lt;tt class="docutils literal"&gt;IN&lt;/tt&gt; against a
list of 1122 identifiers compiles to a hash join. Build one lookup structure and a row costs a single lookup however
large the set is. Loop over the set instead and a row costs one comparison per entry, so the work is rows times
entries, which is the multiplication in the table above.&lt;/p&gt;
&lt;p&gt;The timings separate the two greps the same way. Over the same 128 MiB with a thousand patterns, BSD grep takes 13m56s
where GNU grep takes 0.401s, &lt;strong&gt;2084x faster&lt;/strong&gt;, and ripgrep 0.171s, the &lt;strong&gt;4887x&lt;/strong&gt; on the image at the top. Their
scaling separates them too: on that slice a hundred times the patterns costs BSD grep 96 times the time and GNU grep
3.2 times. mawk takes 0.045s whatever the pattern count.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="reach-for-ripgrep-unless-the-match-sits-at-a-known-position"&gt;
&lt;h2&gt;Reach for ripgrep, Unless the Match Sits at a Known Position&lt;/h2&gt;
&lt;p&gt;Here are the three that will do this job at a usable speed, on the whole 330 GB with all 1122 patterns, decompressing
with &lt;tt class="docutils literal"&gt;pigz&lt;/tt&gt; and writing the same gzipped output through &lt;tt class="docutils literal"&gt;pigz &lt;span class="pre"&gt;-p&lt;/span&gt; 8&lt;/tt&gt;, with the floor and the macOS default for
scale:&lt;/p&gt;
&lt;object data="https://vijay.varadan.com/talks/images/matcher-wall-times.svg" type="image/svg+xml"&gt;Wall time for one filter over the full 330 GB. Decompressing and counting the bytes, the floor, 1m44s at 3164 MB/s. mawk 3m40s at 1500 MB/s. ripgrep 7m05s at 776 MB/s. GNU grep 17m10s at 320 MB/s. /usr/bin/grep killed at 15 hours, 0.13 MB/s, having read 2.16% of the input, too slow to fit the same axis.&lt;/object&gt;
&lt;p&gt;The top bar is the floor, the time to decompress 330 GB and count the bytes, because everything under it has to do
that too. All three matchers selected the same rows in the same order, so they differ only in how long they take: GNU
grep's output and ripgrep's are byte-identical, and mawk's is those same bytes with one extra line at the top. Every
rate here is this machine, this file, and this one month of data. Compare them with each other rather than with
numbers from yours.&lt;/p&gt;
&lt;p&gt;All three cost one &lt;tt class="docutils literal"&gt;brew install&lt;/tt&gt;, so the choice is not about effort:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;strong&gt;ripgrep&lt;/strong&gt;, the one to reach for. &lt;tt class="docutils literal"&gt;brew install ripgrep&lt;/tt&gt;, and it matches anywhere on the line the way grep does,
so nothing about your patterns has to change. It carries an Aho-Corasick automaton, reads each input byte once
however many patterns you hand it, and is 2.4x faster than GNU grep here. Pass &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-a&lt;/span&gt;&lt;/tt&gt;: without it a stray byte
sequence makes ripgrep decide the stream is binary and stop early, and a file that is quietly short is a worse
outcome than a run that is slow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mawk with a hash&lt;/strong&gt;, if the match sits at a known position. Fastest of the three and the most restricted. The
pipeline at the top loads the identifiers into the array &lt;tt class="docutils literal"&gt;p&lt;/tt&gt; and tests &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;substr($0,1,36)&lt;/span&gt;&lt;/tt&gt; against it, so it
matches field 1 exactly rather than the identifier anywhere on the line. That's stricter than grep and it was what
I actually wanted; if your patterns can appear anywhere, this one doesn't apply to you. If they can't, you can say
so by anchoring every pattern to &lt;tt class="docutils literal"&gt;^uuid,&lt;/tt&gt;. Anchoring is worth 1.06x to ripgrep and 2.31x to GNU grep, each
against its own unanchored run, at this file's 12.6% match rate, and the GNU grep figure rises to 6.38x at a 1.5%
match rate, because the sparser the matches, the bigger the gain; ripgrep stays between 1.06x and 1.08x throughout.
mawk still finishes first, by 1.83x over anchored ripgrep and 2.04x over anchored GNU grep.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GNU grep&lt;/strong&gt;, if you'd rather not learn another tool. &lt;tt class="docutils literal"&gt;brew install grep&lt;/tt&gt; puts it at &lt;tt class="docutils literal"&gt;ggrep&lt;/tt&gt;, the flags are the
ones you're already typing, and your pipeline changes by one character. That costs you 2.4x against ripgrep, or
1.11x at this file's match rate if both are anchored. Where matches are sparser the anchored order flips: at a 1.5%
match rate anchored GNU grep takes 2m54s against anchored ripgrep's 6m56s. Either way it finishes a job the default
could not.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;The greps drop your header row.&lt;/strong&gt; A CSV header matches no pattern, so &lt;tt class="docutils literal"&gt;grep&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;rg&lt;/tt&gt; throw it away, and that is
the extra line mawk wrote: 83 bytes, twelve of them once gzipped. Both commands at the top put it back, by different
means. mawk has a record number, so &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;FNR==1||&lt;/span&gt;&lt;/tt&gt; prints line 1 whatever is on it. grep and ripgrep have no such
notion, so the shell peels the line off the front of the stream instead: &lt;tt class="docutils literal"&gt;read&lt;/tt&gt; takes exactly one line from the
shared stdin and the filter picks up from line 2, with &lt;tt class="docutils literal"&gt;IFS=&lt;/tt&gt; to keep the header's leading and trailing whitespace
and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-r&lt;/span&gt;&lt;/tt&gt; to stop backslashes being read as escapes.&lt;/p&gt;
&lt;p&gt;Three traps, all of them silent, and two are in &lt;tt class="docutils literal"&gt;ids.txt&lt;/tt&gt; rather than in your data. &lt;strong&gt;One empty line in the pattern
file matches every input line&lt;/strong&gt;, so the filter quietly becomes &lt;tt class="docutils literal"&gt;cat&lt;/tt&gt;: 7,794 matching lines in a 200 MiB sample
became all 784,857. The tell runs the wrong way, because an empty pattern matches before any real work happens and the
run gets &lt;em&gt;faster&lt;/em&gt;, BSD grep going from 10.65s to 0.01s on a 2 MiB slice. A job that has been crawling and then
suddenly finishes is the thing to be suspicious of. More empty lines change nothing, and neither does where they sit,
so one stray newline at the end of &lt;tt class="docutils literal"&gt;ids.txt&lt;/tt&gt; will do it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CRLF line endings in the same file do the reverse.&lt;/strong&gt; grep appends the carriage return to every pattern, so nothing
matches and you get an empty file and exit status 1. That costs more than the real job, 14.30s against 10.65s on the
same slice, because a line that matches lets grep stop trying patterns on it and a line that cannot match never does.
ripgrep strips the carriage return and is unaffected. mawk is immune to the blank line, an empty string never
equalling a 36-byte prefix, but not to the CRLF, where it writes your header and nothing else.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The third trap is in the data.&lt;/strong&gt; All three matchers read a line at a time, so a newline inside a quoted field, which
the CSV spec allows, splits one record across two lines and defeats them equally: the second line starts mid-record,
and a byte offset lands on whatever happens to be there. This file has none, which is why &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;substr($0,1,36)&lt;/span&gt;&lt;/tt&gt; is safe
on it. DuckDB's CSV reader counted 1,272,998,467 records where awk counted 1,272,998,467 lines, and two counts that
match, one of them from a real parser, are how you know.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-same-command-name-is-a-different-program"&gt;
&lt;h2&gt;The Same Command Name Is a Different Program&lt;/h2&gt;
&lt;p&gt;This goes past grep, and it's the part that holds at any size: the name of a command tells you almost nothing about
which program will run, and you can't reason about its speed until you know. &lt;tt class="docutils literal"&gt;sed&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;sort&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;date&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;find&lt;/tt&gt;,
&lt;tt class="docutils literal"&gt;tar&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;head &lt;span class="pre"&gt;-c&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;tr&lt;/tt&gt; all differ between macOS and Linux, in flags and in performance, and inside an Alpine
container most of them are busybox, which is a third implementation again. &lt;tt class="docutils literal"&gt;grep &lt;span class="pre"&gt;--version&lt;/span&gt;&lt;/tt&gt; costs nothing and I
should have run it first.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="fifteen-hours-in-grep-had-written-2-7-of-the-output"&gt;
&lt;h2&gt;Fifteen Hours In, grep Had Written 2.7% of the Output&lt;/h2&gt;
&lt;p&gt;I started with &lt;tt class="docutils literal"&gt;pigz &lt;span class="pre"&gt;-dc&lt;/span&gt; | grep &lt;span class="pre"&gt;-F&lt;/span&gt; &lt;span class="pre"&gt;-f&lt;/span&gt; | pigz &lt;span class="pre"&gt;-p&lt;/span&gt; 8&lt;/tt&gt;, which is what I'd typically use, and went to do something else.
Four and a half hours later the output file was 11 MB and at fifteen hours 38 MB. I had no denominator for either
until ripgrep finished the same filter in seven minutes: 0.8% and 2.7% of the finished output. The rows in that output
sit 0.70% and 2.16% into the input, which is how far grep had actually reached, at 0.13 to 0.14 MB/s. From both checks
I got about a month, so I killed it. Having something to compare against is what made stopping obvious rather than
agonising.&lt;/p&gt;
&lt;div class="callout docutils container"&gt;
&lt;a class="reference external" href="{filename}macos-grep-f-is-a-nested-loop-join--details.rst"&gt;The long version&lt;/a&gt; has the six matchers timed
against each other, the awk field-splitting measurements, what quoted fields do to &lt;tt class="docutils literal"&gt;awk &lt;span class="pre"&gt;-F,&lt;/span&gt;&lt;/tt&gt;, and the benchmarks
that misled me.&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="related"&gt;
&lt;h2&gt;Related&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="{filename}macos-grep-f-is-a-nested-loop-join--details.rst"&gt;Filtering a 330 GB Gzipped CSV, in full&lt;/a&gt;, the long
version of this one: every matcher timed against the others, the awk field-splitting measurements, the correctness
traps, and the benchmarks that misled me.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="{filename}filtering-a-330gb-gzipped-csv-with-duckdb.rst"&gt;Filtering a 330 GB CSV in DuckDB&lt;/a&gt;, for doing this more
than once.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="{filename}pitfalls-directing-an-ai-agent.rst"&gt;Pitfalls Directing an AI Agent&lt;/a&gt;, for the analysis the extract was
made for.&lt;/li&gt;
&lt;li&gt;FreeBSD made BSD grep the default in &lt;a class="reference external" href="https://cgit.freebsd.org/src/commit/?id=b82a9ec5f53e79b3ab5ea8d5a3666961c0a5e050"&gt;December 2020&lt;/a&gt;, replacing GNU grep for
licensing reasons.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Technical"/><category term="programming"/><category term="shell"/><category term="awk"/><category term="grep"/><category term="csv"/><category term="duckdb"/><category term="performance"/><category term="macOS"/></entry><entry><title>Review: Brief: Make a Bigger Impact by Saying Less</title><link href="https://vijay.varadan.com/talks/review--brief/" rel="alternate"/><published>2018-05-30T20:51:00-07:00</published><updated>2018-05-30T20:51:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2018-05-30:/talks/review--brief/</id><summary type="html">&lt;p class="first last"&gt;For a book on being brief, it's thrice as long as it needs to be. Only chapters 1-8 are
worth reading.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="post image" src="https://vijay.varadan.com/talks/images/brief-make-a-bigger-impact-by-saying-less.jpg" /&gt;&lt;/p&gt;
&lt;div class="section" id="verdict-ymmv-your-mileage-may-vary"&gt;
&lt;h2&gt;Verdict: &lt;img alt="ymmv" src="https://vijay.varadan.com/talks/images/ymmv.png" /&gt; &lt;strong&gt;Your Mileage May Vary&lt;/strong&gt;&lt;/h2&gt;
&lt;div class="section" id="the-good"&gt;
&lt;h3&gt;The Good&lt;/h3&gt;
&lt;p&gt;There is good, solid information in the first 8 chapters of the book. It's easy to read and absorb.
Applying the ideas as a habit will take some effort on your own.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-bad"&gt;
&lt;h3&gt;The Bad&lt;/h3&gt;
&lt;p&gt;Pretty much all the stuff after chapter 8 is just fluff. It would even be too generous of a
compliment to say that the remainder of the book is peripherally related to brevity.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ugly"&gt;
&lt;h3&gt;The Ugly&lt;/h3&gt;
&lt;p&gt;The stories that go on and on and on.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="notes"&gt;
&lt;h2&gt;Notes&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; These are primarily written for my own future reference, but they may be useful to
you, either to decide if you want to read / buy the book or as something to revisit. The
information is not comprehensive, not in the least - so, please don't use it as a substitute for
actually reading the book. As with all my content, some is verbatim from the original source,
opinion may be interspersed &amp;amp; of course, YMMV.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Being brief is not just about time. What's more important is how long it feels to the audience.
It's not about using the least amount of time. It's about making the most of the time you have.&lt;/li&gt;
&lt;li&gt;It's a balancing act of being concise, clear, and compelling. All three need to be in harmony.&lt;/li&gt;
&lt;li&gt;To be brief doesn't just mean being concise. Your responsibility is to balance how long it takes
to convey a message well enough to cause a person to act on it. That's the harmony of brevity
when it's striking the right chords.&lt;/li&gt;
&lt;li&gt;Brevity starts with deep expertise. Only with thorough knowledge can you accurately make a
summary.&lt;/li&gt;
&lt;li&gt;The road to brevity hard work and lots of time. Doing all the digging and analysis on your own
time saves the members of your audience from doing the labor themselves.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="capital-sins"&gt;
&lt;h3&gt;7 Capital Sins&lt;/h3&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Your leadership team doesn't know what to do with your assessment &amp;amp; guidance &amp;amp; subconsciously
starts questioning your leadership ability... When someone who is braver &amp;amp; clearer steps up,
you're history.&lt;/li&gt;
&lt;li&gt;Nobody likes to talk to you because once you start, there is little they can do to stop you...
People ignore or instantly delete your e-mails. Over the course of your career, your specialty
knowledge &amp;amp; knack for being long-winded impede your career growth.&lt;/li&gt;
&lt;li&gt;If people see that you don't respect their time, they'll stop respecting you. During your
review, you get low scores from your peers.&lt;/li&gt;
&lt;li&gt;There's a time &amp;amp; place for small talk. You must always be aware that what is exciting for you to
share could be agony for someone else. You should treat everyone the same way; they are busy &amp;amp;
begging you to be brief.&lt;/li&gt;
&lt;li&gt;Even though your idea is still developing &amp;amp; in lots of pieces, people will make judgments about
you &amp;amp; your abilities. Choose carefully when &amp;amp; where—&amp;amp; to whom—you think out loud.&lt;/li&gt;
&lt;li&gt;When people want a simple answer, you need to give it to them... (else) they lose patience &amp;amp;
trust.&lt;/li&gt;
&lt;li&gt;Being mentally &amp;amp; verbally lazy sends a clear message: you might not be ready for the next
assignment—or even be the right person for the job.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="trimming-level-1-to-3-details"&gt;
&lt;h3&gt;Trimming: Level 1 to 3 Details&lt;/h3&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Think of a defining professional moment.&lt;/li&gt;
&lt;li&gt;Take 10-15 minutes to prepare for a 3-minute presentation.&lt;/li&gt;
&lt;li&gt;Present to a partner who listens, takes notes, and shares a 1-minute version to the rest of the
group.&lt;/li&gt;
&lt;li&gt;When telling a story, Level 1 details are those that are absolutely &lt;strong&gt;essential&lt;/strong&gt;; Level 2
points are those that add a little flavor but do not take too much more time; Level 3 items
weigh it down and don't make the story noticeably better.&lt;/li&gt;
&lt;li&gt;This challenge forces you to start trimming. To hit the 1-minute mark means only Level 1 and a
few Level 2 details.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Implications&lt;/strong&gt;:&lt;ol class="arabic"&gt;
&lt;li&gt;Ensure instant appreciation: People are thankful when it requires less energy to grasp the
same basic information in less time.&lt;/li&gt;
&lt;li&gt;Look for what weighs you down: Cutting out the finer detail requires attention and awareness
for what unnecessarily burdens people.&lt;/li&gt;
&lt;li&gt;Live the &amp;quot;less is more&amp;quot; way: When you are throwing things out, it may be hard to decide what
goes - but keep in mind what people will really care about.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="outlines"&gt;
&lt;h3&gt;Outlines&lt;/h3&gt;
&lt;p&gt;Outlines organize and prioritize thoughts with clarity and logic, and help stop nonsensical
rambling.&lt;/p&gt;
&lt;p&gt;Five immediate benefits to outlining are they keep you:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Prepared: I'm ready to deliver.&lt;/li&gt;
&lt;li&gt;Organized: I understand how all my ideas connect.&lt;/li&gt;
&lt;li&gt;Clear: I'm certain what my point is.&lt;/li&gt;
&lt;li&gt;Contextual: I can draw a bigger picture so my point stands out.&lt;/li&gt;
&lt;li&gt;Confident: I know what to say, inside and out.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="mind-mapping"&gt;
&lt;h3&gt;Mind Mapping&lt;/h3&gt;
&lt;p&gt;Mind mapping software is particularly well suited to information triage, because it enables you to
gather, organize, evaluate, and take action on a vast amount of information, knowledge, and
ideas…by giving you the power to move topics and subtopics around, attach notes, links, and
documents to them that provide meaning and context, and play “what if” with your ideas. No other
type of software provides the power and flexibility offered by mind mapping software for
manipulating information and ideas.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="brief-maps"&gt;
&lt;h3&gt;BRIEF Maps&lt;/h3&gt;
&lt;p&gt;Every BRIEF Map is organized in the following way:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;B: Background or beginning&lt;/li&gt;
&lt;li&gt;R: Reason or relevance&lt;/li&gt;
&lt;li&gt;I: Information for inclusion&lt;/li&gt;
&lt;li&gt;E: Ending or conclusion&lt;/li&gt;
&lt;li&gt;F: Follow-up or questions you expect to be asked or that you might ask&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="controlled-conversations"&gt;
&lt;h3&gt;Controlled Conversations&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Do not use your turn to start an irrelevant conversation.&lt;/li&gt;
&lt;li&gt;Keep your responses short.&lt;/li&gt;
&lt;li&gt;Know when to end so the other person can begin talking again.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Management"/><category term="bookReview"/><category term="management"/><category term="communication"/></entry><entry><title>Raise the Bar: Ennobling Habits</title><link href="https://vijay.varadan.com/talks/rtb--ennobling-habits/" rel="alternate"/><published>2018-05-23T20:34:00-07:00</published><updated>2018-05-23T20:34:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2018-05-23:/talks/rtb--ennobling-habits/</id><summary type="html">&lt;p class="first last"&gt;&amp;quot;We function best when our habits ennoble us.&amp;quot;&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="rtb" src="https://vijay.varadan.com/talks/images/rtb-384x216.png" /&gt;&lt;/p&gt;
&lt;p&gt;I've been working at my currentjob for almost a year now and it's been a fun roller coaster ride
the entire time. One of a handful of reasons I decided to work at here was that over the
course of my interview, I got a strong sense that the engineers I spoke with truly enjoyed working
there. When I asked them about problems they faced at their job, I got very straight answers;
nothing canned or evasive like I had encountered at most other places I was interviewing with
around the same time.&lt;/p&gt;
&lt;p&gt;I recently changed roles at my current job and became officially responsible for running a team. One
of the first changes I've been able to effect, with enthusiastic support from fellow engineering
directors and our head of engineering, is to set up a cross-team mentoring program. Our
site reliability engineering (SRE) team lead, was a universal early pick. I had an
interesting conversation with her earlier today, which in a way, serves to emphasize a prized
quality in high-performing engineers -- &lt;strong&gt;constantly raising the bar&lt;/strong&gt;. The chat was in the context
of making improvements; how a (short) period of a problem festering followed by some trigger pushed
her over the line to actually force a change in behavior to eliminate that type of issue from
recurring.&lt;/p&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;strong&gt;We function best when our habits ennoble us.&lt;/strong&gt;&lt;/blockquote&gt;
&lt;p&gt;I'm paraphrasing, so apologies in advance if it lacks precision:&lt;/p&gt;
&lt;p&gt;➜ I can only walk into a room and see a candy wrapper on the table so many times before I have to
pick it up and toss it into the trash can. But it doesn't end there. I start to think about why the
candy wrapper wasn't put into the trash can right away and when I look at the room, it becomes
obvious. It was easy to leave the candy wrapper on the table because there was no trash can in the
room. That's an easy problem to solve - put a trash can in the room, right next to the table; this
makes it easy to do the right thing (put the candy wrapper in the garbage) and just that much more
difficult to do the wrong thing (leave it on the table). It's not enough to make it easy to do the
right thing, we have to make it hard to do the wrong thing. &amp;quot;We function best when our habits
ennoble us.&amp;quot; As we develop such habits, we raise the bar - a little bit at a time, each time -  and
it accumulates as we do it repeatedly.&lt;/p&gt;
&lt;p&gt;➜ Software suffers from the problem where it's acceptable to have a 15-page instruction manual to
do simple things and the barrier to entry for software developers wanting to contribute to opens
source projects is needlessly high. We, as engineers, are part of the problem, in that we've
accepted that it's okay for the barrier to entry to be that high, since we're used to dealing
with complexity as part of our jobs.&lt;/p&gt;
&lt;p&gt;➜ We need to design our software with an easy button.&lt;/p&gt;
&lt;p&gt;&lt;img alt="easy button" src="https://vijay.varadan.com/talks/images/easy-button.jpg" /&gt;&lt;/p&gt;
</content><category term="Management"/><category term="habits"/><category term="raiseTheBar"/><category term="management"/></entry><entry><title>Review: Kanban in Action</title><link href="https://vijay.varadan.com/talks/review--kanban-in-action/" rel="alternate"/><published>2018-05-14T13:50:00-07:00</published><updated>2018-05-14T13:50:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2018-05-14:/talks/review--kanban-in-action/</id><summary type="html">&lt;p class="first last"&gt;Highly recommended. An excellent Kanban resource.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;strong&gt;Authors: Marcus Hammarberg &amp;amp; Joakim Sundén&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="post image" src="https://vijay.varadan.com/talks/images/kanban-in-action.jpg" /&gt;&lt;/p&gt;
&lt;div class="section" id="verdict-recommended-highly-recommended"&gt;
&lt;h2&gt;Verdict: &lt;img alt="recommended" src="https://vijay.varadan.com/talks/images/recommended.png" /&gt; &lt;strong&gt;Highly Recommended&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Buy the book and hold on to it as a reference.&lt;/p&gt;
&lt;div class="section" id="the-good"&gt;
&lt;h3&gt;The Good&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;A very solid introduction to Kanban.&lt;/li&gt;
&lt;li&gt;Fairly in-depth on the meta-process and gradual, piece-meal incorporation into existing
workflows.&lt;/li&gt;
&lt;li&gt;Fable style introduction to Kanban in chapter 1 - I was able to recall most of the chapter from
when I first read it back in June / July of 2017, a good 9 months later.&lt;/li&gt;
&lt;li&gt;Excellent pointers to reference material and Kanban-adjacent information to continue to build
one's knowledge.&lt;/li&gt;
&lt;li&gt;Strong focus on constant improvement.&lt;/li&gt;
&lt;li&gt;Summary section at the end of each chapter provides a quick refresher.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-bad"&gt;
&lt;h3&gt;The Bad&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The chapter on pitfalls seems to pander to critics.&lt;/li&gt;
&lt;li&gt;The last chapter &amp;quot;Kanban Games&amp;quot; might have been better introduced earlier; in retrospect, the
&amp;quot;Passing the Pennies&amp;quot; game was a good starting point to explain WIP limits and need to focus on
lead times.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ugly"&gt;
&lt;h3&gt;The Ugly&lt;/h3&gt;
&lt;p&gt;Nothing.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="notes"&gt;
&lt;h2&gt;Notes&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; These are primarily written for my own future reference, but they may be useful to
you, either to decide if you want to read / buy the book or as something to revisit. The
information is not comprehensive, not in the least - so, please don't use it as a substitute for
actually reading the book. As with all my content, some is verbatim from the original source,
opinion may be interspersed &amp;amp; of course, YMMV.&lt;/p&gt;
&lt;div class="section" id="kanban-principles"&gt;
&lt;h3&gt;Kanban Principles&lt;/h3&gt;
&lt;p&gt;Kanban aims to make the work flow fast through the whole value chain, from idea or concept to
software in production, delighting your customers.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;strong&gt;Visualize&lt;/strong&gt; your work and policies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Limit&lt;/strong&gt; the amount of work in progress.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Control flow&lt;/strong&gt; of work.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="visualizing-your-work"&gt;
&lt;h3&gt;Visualizing Your Work&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Visualizing your work is ultimately about creating the transparency and information-sharing
needed to understand how the work works and to collaborate effectively together.&lt;/li&gt;
&lt;li&gt;The process of visualizing work means making information visible that previously wasn’t, making
implicit knowledge and policies explicit, and, in doing so, resolving inconsistencies and
conflicts that surface.&lt;/li&gt;
&lt;li&gt;The kanban board is a great way to visualize your workflow and share information about
priorities, who’s working on what, the progress of individual work items, and so on.&lt;/li&gt;
&lt;li&gt;By using a big, visible board, the information radiates to everyone interested instead of being
hidden in people’s brains or inaccessible tools.&lt;/li&gt;
&lt;li&gt;Creating a kanban board is easy: you map the workflow of your work items - that is, the steps
they typically go through in order to be completed—to columns you create on a whiteboard or a
wall.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="work-items"&gt;
&lt;h3&gt;Work Items&lt;/h3&gt;
&lt;p&gt;A work item should contain all the information the team needs to be able to know how to work with
it. Of the following, pick and choose what fits your current needs and add features as needed:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;A description - So you know what the work is about&lt;/li&gt;
&lt;li&gt;An avatar or other marker - So you know who is working on the item&lt;/li&gt;
&lt;li&gt;Deadlines and other important dates - So you know when you need to have the item done&lt;/li&gt;
&lt;li&gt;Tracking IDs or other references to an external system - So you know where to find more
information&lt;/li&gt;
&lt;li&gt;Blockers - So you can pick out items that are blocked and therefore hindered from further
progress&lt;/li&gt;
&lt;li&gt;Type of work - So you know the type of work for each item, which is important so you can
prioritize the work items against each other if needed&lt;/li&gt;
&lt;li&gt;Progress indicators - So you know how much of the work you have done so far&lt;/li&gt;
&lt;li&gt;Size - So you can see the differences in size and effort&lt;/li&gt;
&lt;li&gt;Flow data, emotions, and other data accumulated during the flow through the board - So you know
how the work behaved and how the team felt about it&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="work-in-process-wip"&gt;
&lt;h3&gt;Work in Process (WIP)&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The more WIP, the longer the cycle time for each work item will be. You should limit the WIP to
get faster flow and shorter lead times.&lt;/li&gt;
&lt;li&gt;WIP can take many forms, and we looked at some common ones in software development:&lt;ul&gt;
&lt;li&gt;Specifications that haven’t been implemented yet&lt;/li&gt;
&lt;li&gt;Non-integrated code that “works on my computer”&lt;/li&gt;
&lt;li&gt;Untested code, which may or may not live up to your standards&lt;/li&gt;
&lt;li&gt;Code not in production, which sits and wait for the next release&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Problems and bad things can follow from having a lot of WIP:&lt;ul&gt;
&lt;li&gt;More context switching&lt;/li&gt;
&lt;li&gt;Prolonged feedback loop, which in turn causes extra work for you&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;And we mentioned some ways that WIP can manifest itself:&lt;ul&gt;
&lt;li&gt;Increased risk&lt;/li&gt;
&lt;li&gt;More overhead&lt;/li&gt;
&lt;li&gt;Lower quality&lt;/li&gt;
&lt;li&gt;Less motivation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="limiting-wip"&gt;
&lt;h3&gt;Limiting WIP&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;There’s no one right WIP limit for you and your team.&lt;/li&gt;
&lt;li&gt;Limiting WIP isn’t the goal; improving flow is. WIP limits are merely a tool that helps find
problems that hinder a better flow.&lt;/li&gt;
&lt;li&gt;A lower WIP limit will move your work faster and also bring problems to your attention more
quickly. You want a low WIP limit, but not too low.&lt;/li&gt;
&lt;li&gt;When setting out to find a WIP limit, start simple—maybe as simple as the slogan “Stop starting,
start finishing.”&lt;/li&gt;
&lt;li&gt;You can limit the WIP for the whole team/workflow:&lt;ul&gt;
&lt;li&gt;This approach can help you improve collaboration.&lt;/li&gt;
&lt;li&gt;It helps you keep focus on finishing work items before taking on new ones.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You can limit WIP based on column:&lt;ul&gt;
&lt;li&gt;This puts focus on flowing items through the workflow.&lt;/li&gt;
&lt;li&gt;It can help to manage bottlenecks.&lt;/li&gt;
&lt;li&gt;Maybe you already have a hunch about what you need to improve and can start limiting WIP for
that column.&lt;/li&gt;
&lt;li&gt;Work can also be limited by estimated size (story points, for example).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You can limit WIP based on people:&lt;ul&gt;
&lt;li&gt;Limiting the number of avatars that can be in play is one way to easily accomplish this.&lt;/li&gt;
&lt;li&gt;Using swim lanes is another.&lt;/li&gt;
&lt;li&gt;This can help you prevent too much multitasking and people being involved in every item on the
board.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Most teams have a WIP limit on the work-item level, not the task level.&lt;/li&gt;
&lt;/ul&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&amp;quot;&lt;strong&gt;The question is, are you selling keystrokes or completed features?&lt;/strong&gt;&amp;quot;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="managing-flow"&gt;
&lt;h3&gt;Managing Flow&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Flow (or continuous flow) is an ideal state that describes a process in which every step in the
process creates value, with no interruptions or waiting time.&lt;/li&gt;
&lt;li&gt;Pursuing this ideal state is a never-ending quest that will help you not only get a smoother,
faster flow but also find problems in your process.&lt;/li&gt;
&lt;li&gt;Everything that isn’t value in the eyes of the customer is waste. Eliminating waste leads to
better flow.&lt;/li&gt;
&lt;li&gt;“Managing flow” is one of the principles of kanban, and there are a lot of things you can do to
help the work flow:&lt;ul&gt;
&lt;li&gt;Limit WIP.&lt;/li&gt;
&lt;li&gt;Reduce waiting times in your process: for example, by ensuring that the work is always ready
for the next step or by making the work items smaller so that they move faster through the
process. Remove blockers as fast as possible. Or why not strive to “never be blocked”?&lt;/li&gt;
&lt;li&gt;Avoid rework by building quality into your process from the start. How much of the demand you
have in your system today is failure demand? How can you have less failure demand and more
value demand?&lt;/li&gt;
&lt;li&gt;Create cross-functional teams that can minimize waiting times.&lt;/li&gt;
&lt;li&gt;Use goals and targets like SLAs to get clear timeboxes and objectives to strive toward.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Many teams use the daily standup to collaborate well together. Here are some practices to help
make a standup great:&lt;ul&gt;
&lt;li&gt;Keep it short and energized: never more than 15 minutes (that’s why you stand up).&lt;/li&gt;
&lt;li&gt;Keep it regular: same time and place every day.&lt;/li&gt;
&lt;li&gt;Keep it disciplined: start and end on time.&lt;/li&gt;
&lt;li&gt;Keep it focused: complete discussions afterward.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Many kanban teams have some practices that they follow:&lt;ul&gt;
&lt;li&gt;Focus on the work, not the workers.&lt;/li&gt;
&lt;li&gt;Walk through the items on the board from right to left.&lt;/li&gt;
&lt;li&gt;Focus on deviations - the smells in your process.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Here are some other things to think about to get the most out of your standup:&lt;ul&gt;
&lt;li&gt;Is all the work visible on the board?&lt;/li&gt;
&lt;li&gt;Are we working on the right thing?&lt;/li&gt;
&lt;li&gt;Do we understand the work?&lt;/li&gt;
&lt;li&gt;Encourage spontaneous &lt;em&gt;kaizen&lt;/em&gt; meetings after the standup in which small improvements are
made every day.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Standups can be scaled to more than one team, but make sure each layer adds value and isn’t just
another reporting instance. Think about the following:&lt;ul&gt;
&lt;li&gt;Run before or after smaller team standups?&lt;/li&gt;
&lt;li&gt;Who attends?&lt;/li&gt;
&lt;li&gt;What kinds of visualizations are needed?&lt;/li&gt;
&lt;li&gt;How will statuses be synchronized between local team boards and other boards?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;quot;What should I be doing next?&amp;quot; is a common question at standups. With explicit policies on how to
handle that question, you minimize the risk of hindering the flow of work.&lt;/li&gt;
&lt;li&gt;A bottleneck is something that slows down production. With queues, you can get leading indicators
and discover the bottlenecks.&lt;/li&gt;
&lt;li&gt;The Theory of Constraints is a management theory built around finding and eliminating bottlenecks
in a process.&lt;/li&gt;
&lt;/ul&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
An activity in itself isn’t a value-add or waste; it’s the &lt;strong&gt;return of time invested (ROTI)&lt;/strong&gt; in
that activity which determines if it’s waste or not.&lt;/blockquote&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;strong&gt;Optimizing for flow vs. optimizing for resource utilization is a strategy decision.&lt;/strong&gt; Lean as
an operations strategy aims to increase resource efficiency through focusing on increasing flow
efficiency.&lt;/blockquote&gt;
&lt;div class="section" id="the-seven-wastes-of-software-development"&gt;
&lt;h4&gt;The Seven Wastes of Software Development&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;strong&gt;Partially done work&lt;/strong&gt; - Work that isn’t completely done is in reality just work in process. It
lies around waiting for you to complete it and adds to your WIP.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extra features&lt;/strong&gt; - Taiichi Ohno famously said, “There’s no greater waste than overproduction.”
Build the right thing. On an individual level, if you’ve ever thought “This may come in handy” or
“Maybe they want this to be configurable,” it's likely wasted.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Relearning&lt;/strong&gt; - Software development is, to a great extent, learning. Failing to remember
mistakes you’ve made before and having to redo them (and relearn the solution) is a great waste.
This can happen both in teams and for individuals.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hand-offs&lt;/strong&gt; - When you hand work from one person to another, a lot of extra work is created in
order to convey necessary information to the next person. Even with that extra work, a lot of
information will be lost in the hand-off.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delays&lt;/strong&gt; - Delays create extra work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Task switching&lt;/strong&gt; - Context switching and the wasteful effect it can have on your focus and
capacity can be as high as 10% per switch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Defects&lt;/strong&gt; - Defects are work that comes back to you because you did something wrong the first
time around. Not only does this create extra work, but typically that kind of work comes at a bad
time, slowing down the things you’re working on right now.&lt;/li&gt;
&lt;/ul&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;strong&gt;Specification by Example&lt;/strong&gt;: Write your specification in the form of acceptance criteria or
concrete examples (real numbers and real data used) of how a feature will be used. The feature
will be complete when the example is fulfilled: nothing more, nothing less.&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="five-focusing-steps"&gt;
&lt;h4&gt;Five Focusing Steps&lt;/h4&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Identify the constraint of the system: for example, a single machine that all the parts in a
factory need to pass through.&lt;/li&gt;
&lt;li&gt;Exploit the constraint to get the most out of it. For example, make sure the machine is running
all the time.&lt;/li&gt;
&lt;li&gt;Subordinate all other work to support the exploitation of the constraint. For example, make sure
you don’t send faulty parts to the machine; that would be a waste of time for the constraint.&lt;/li&gt;
&lt;li&gt;Elevate the constraint. For example, buy another machine to share the workload.&lt;/li&gt;
&lt;li&gt;Rinse and repeat. Go over your system again, and see if the constraint is still the biggest
constraint in the system.&lt;/li&gt;
&lt;/ol&gt;
&lt;!--  --&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Never be blocked&lt;/strong&gt;: Like a good pool player who always makes sure the shot he is taking sets up
the next shot he expects to take, every step a good agile developer takes enables the next step.
A good agile developer never takes a step that stops his progress, or the progress of others.&lt;/p&gt;
&lt;p class="attribution"&gt;&amp;mdash;&amp;#64;unclebobmartin&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="classes-of-service"&gt;
&lt;h3&gt;Classes of Service&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Classes of service are a powerful way to make your policies explicit around the service level for
certain type of work.&lt;/li&gt;
&lt;li&gt;Assigning a class of service to a work item can influence the work item: visualization,
prioritization, impact on WIP, and workflow.&lt;/li&gt;
&lt;li&gt;Classes of service help the team to self-organize around&lt;ul&gt;
&lt;li&gt;Work selection and scheduling&lt;/li&gt;
&lt;li&gt;Work distribution&lt;/li&gt;
&lt;li&gt;Making sure the work capacity is distributed as decided&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Common classes include&lt;ul&gt;
&lt;li&gt;Urgent (or Expedite) - Prioritized over other work&lt;/li&gt;
&lt;li&gt;Fixed Delivery Date - Needs to be completed on or before a certain date&lt;/li&gt;
&lt;li&gt;Regular - Normal items, increasingly urgent, pulled FIFO-style&lt;/li&gt;
&lt;li&gt;Defects - Rework produced by bad quality (you want as few of these as possible)&lt;/li&gt;
&lt;li&gt;Intangible - No tangible business value now, but later: paying off technical debt&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Use classes that suit your needs and situation, using the examples in this chapter as
inspiration. There’s no one right answer for everyone.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="planning-and-estimating"&gt;
&lt;h3&gt;Planning and Estimating&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Find the right time to plan - not too early nor too late, just in time:&lt;ul&gt;
&lt;li&gt;Order points are one way to run event-driven planning.&lt;/li&gt;
&lt;li&gt;Planning more often involves stakeholders around you more and builds trust, but it can also be
costly. You need to balance it so that you plan with the right frequency.&lt;/li&gt;
&lt;li&gt;Using Disneyland wait times is a way of showing expected delivery times.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Plans and estimates are often requested by others around you, extend the workflow upstream and
downstream.&lt;/li&gt;
&lt;li&gt;Estimating in exact terms is much harder than giving relative estimates, so prefer doing relative
estimates:&lt;ul&gt;
&lt;li&gt;Story points and T-shirt sizes are two common ways of doing relative estimates.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Estimation techniques:&lt;ul&gt;
&lt;li&gt;A line of cards ➜ Pick any work item and then compare the next one to the first: smaller or
bigger? When all are laid out, assign T-shirt sizes.&lt;/li&gt;
&lt;li&gt;Planning Poker (see below).&lt;/li&gt;
&lt;li&gt;Goldilocks ➜ Change work items so that they're just the right size for your convenience.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cadence is the natural rhythm or heartbeat found in your process. In iteration based processes,
there are natural cadences when iterations start and stop.&lt;/li&gt;
&lt;li&gt;With kanban you can have the cadences you see fit for activities: reviewing, planning,
demonstration, and retrospectives. You don’t have to tie it to the flow of your work.&lt;/li&gt;
&lt;li&gt;Need for plans and estimates:&lt;ul&gt;
&lt;li&gt;Teams that use kanban see the need for detailed plans decreasing with the tightening of
feedback loops.&lt;/li&gt;
&lt;li&gt;Customers don’t want plans and estimates; they want business capabilities.&lt;/li&gt;
&lt;li&gt;Estimating and making plans is useful as long as you’re uncovering new information.&lt;/li&gt;
&lt;li&gt;The &lt;a class="reference external" href="https://twitter.com/hashtag/noestimates"&gt;#NoEstimates&lt;/a&gt; movement talks about abandoning
estimates altogether and finding effective ways to work without estimates.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="planning-poker"&gt;
&lt;h3&gt;Planning Poker&lt;/h3&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Have a domain expert explain the requirement in question to the team, to ensure that everyone
understands what it’s all about.&lt;/li&gt;
&lt;li&gt;Perform the following estimation rounds, and only continue to the next round if you aren’t in
agreement of the size of the estimate:&lt;ul&gt;
&lt;li&gt;Round 1 - Conduct silent voting using cards. No discussion, but cast votes. Show votes, for
example on the count of three.&lt;/li&gt;
&lt;li&gt;Round 2 - Let people think for a minute or two before doing a new silent vote, still without
discussion.&lt;/li&gt;
&lt;li&gt;Round 3 - Let the team members explain why they voted as they did, and then vote again.&lt;/li&gt;
&lt;li&gt;If you’re still not in agreement, then park that story for a separate session, and continue
with the next requirement.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="process-improvement"&gt;
&lt;h3&gt;Process Improvement&lt;/h3&gt;
&lt;p&gt;Core to kanban:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;continuous improvement&lt;/li&gt;
&lt;li&gt;respect for people&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Common practices for improvements:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;A retrospective is a way for a team to look back on their process and see how they can improve
it.&lt;/li&gt;
&lt;li&gt;Root-cause analysis is a tool that helps you find the root problem so you don’t only fix the
symptom.&lt;/li&gt;
&lt;li&gt;Root-cause analysis also guides you to see why the problem is worth solving.&lt;/li&gt;
&lt;li&gt;Kanban Kata is a continuous-improvement tool that is based on how Toyota makes improvements.&lt;/li&gt;
&lt;li&gt;There are three katas within Kanban Kata:&lt;ul&gt;
&lt;li&gt;Daily Kata ➜ Including improvement work in your daily work&lt;/li&gt;
&lt;li&gt;Improvement Kata ➜ A formalized way to improve your process&lt;/li&gt;
&lt;li&gt;Coaching Kata ➜ Improving the learners&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kata ➜ follow a set way of working toward a goal, until the routine becomes second nature and
making improvements becomes the way that you normally work.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="retrospective-five-distinct-parts"&gt;
&lt;h4&gt;Retrospective - Five Distinct Parts&lt;/h4&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;strong&gt;Set the stage w/ the retrospective prime directive&lt;/strong&gt;: Regardless of what we discover, we
understand and truly believe that everyone did the best job they could, given what they knew at
the time, their skills and abilities, the resources available, and the situation at hand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gather data&lt;/strong&gt;: The team looks back (hence retrospective) at the past period and gathers data
about what happened.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Generate insights&lt;/strong&gt;: Analyze the data to determine what conclusions can be drawn from it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Decide what to do&lt;/strong&gt;: Find a suitable set of actions that can be completed before the next
retrospective.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Close the retrospective&lt;/strong&gt;: Good practice is to ask what people about the form of the
retrospective and how it can be improved.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="metrics"&gt;
&lt;h3&gt;Metrics&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;In order to know if you’re improving or not, you measure your process behavior and analyze these
metrics.&lt;/li&gt;
&lt;li&gt;Metrics are like a visualization of your process’s health.&lt;/li&gt;
&lt;li&gt;The following are common metrics that kanban teams use:&lt;ul&gt;
&lt;li&gt;Cycle time ➜ time taken to complete part of the process&lt;/li&gt;
&lt;li&gt;Lead time ➜ time taken to complete the whole process&lt;/li&gt;
&lt;li&gt;Throughput ➜ number of completed items in a week (or month or some period)&lt;/li&gt;
&lt;li&gt;Due date performance ➜ do you keep your promises?&lt;/li&gt;
&lt;li&gt;Quality ➜ do you deliver with quality?&lt;/li&gt;
&lt;li&gt;Value demand vs. Failure demand ➜ demand on a system caused by failure to do something or do
something right for the customer&lt;/li&gt;
&lt;li&gt;Discarded ideas ➜ do you innovate enough or too much?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;These are common diagrams that kanban teams use:&lt;ul&gt;
&lt;li&gt;Statistical process control (SPC) chart ➜ A visualization of lead and cycle times&lt;/li&gt;
&lt;li&gt;Cumulative flow diagram (CFD) ➜ Shows a lot of information about your process based on the
number of items per stage in your process per day&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Finding a good metric can be hard. Remember the following:&lt;ul&gt;
&lt;li&gt;You get what you measure.&lt;/li&gt;
&lt;li&gt;Don’t focus on a single metric - use balanced metrics.&lt;/li&gt;
&lt;li&gt;Use metrics that are easy to capture, or make them so.&lt;/li&gt;
&lt;li&gt;Prefer real data over estimates.&lt;/li&gt;
&lt;li&gt;Use metrics to improve - not to punish.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="principles-of-theory-of-variation"&gt;
&lt;h4&gt;Principles of Theory of Variation&lt;/h4&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;You should expect things to vary - they always do.&lt;/li&gt;
&lt;li&gt;Understanding variation will tell you what to expect.&lt;/li&gt;
&lt;li&gt;Work on the causes of variations, which are always found in the system.&lt;/li&gt;
&lt;li&gt;Understanding variation tells you when something has happened.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="pitfalls"&gt;
&lt;h3&gt;Pitfalls&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Kanban can end up just being a long flow of work that seems never-ending - it’s just  work,
work,  work.  Make  sure  that  doesn’t  happen  to  you  by  adding cadences for reviews,
retrospectives, and planning as needed.&lt;/li&gt;
&lt;li&gt;No  timeboxing  is  suggested  when  using  kanban,  which  can  remove  the  constraint you need
to finish stuff and make trade-offs to do so. To tackle this, add timeboxes to individual items;
use deadlines/due dates or SLAs.&lt;/li&gt;
&lt;li&gt;Kanban  is  great  because  it  starts  where  you  are:  you  don’t  have  to  change  a thing
about how you work to get started with kanban. But sometimes you need a revolution:&lt;ul&gt;
&lt;li&gt;Nothing is hindering you from taking on new roles or ways of working.&lt;/li&gt;
&lt;li&gt;You can also control the tempo at which you improve by limiting WIP , more or less. Less WIP
means more opportunities to improve.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Kanban is a meta-process—an improvement process for an already-existing process.  Don’t  remove
things  that  work  today  merely  because  kanban doesn’t say anything about them.&lt;/li&gt;
&lt;li&gt;The number-one mistake when starting with kanban is to begin without any WIP limits. This means
there’s no constraint pushing you to improve.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Management"/><category term="bookReview"/><category term="management"/><category term="kanban"/><category term="agile"/></entry><entry><title>Review: The Life-changing Magic of Tidying Up</title><link href="https://vijay.varadan.com/talks/review--the-life-changing-magic-of-tidying-up/" rel="alternate"/><published>2017-03-04T18:58:00-08:00</published><updated>2017-03-04T18:58:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2017-03-04:/talks/review--the-life-changing-magic-of-tidying-up/</id><summary type="html">&lt;p class="first last"&gt;Recommended, but be ready to filter out some strange anecdotes and slightly whacky techniques.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="post image" src="https://vijay.varadan.com/talks/images/the-life-changing-magic-of-tidying-up.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Author: Marie Kondo&lt;/strong&gt;&lt;/p&gt;
&lt;div class="section" id="verdict-recommended-recommended-but-be-ready-to-filter-out-some-strange-anecdotes-and-slightly-whacky-techniques"&gt;
&lt;h2&gt;Verdict: &lt;img alt="recommended" src="https://vijay.varadan.com/talks/images/recommended.png" /&gt; &lt;strong&gt;Recommended&lt;/strong&gt;. But be ready to filter out some strange anecdotes and slightly whacky techniques.&lt;/h2&gt;
&lt;p&gt;I first read this book in January and decided to wait to review it till I could figure out if the methods in the book were practical. When I read the book, I was a rather skeptical. Some of the anecdotes make the author seem a few cards short of a full deck. E.g. throwing other people's stuff away without asking them, dumping unwanted stuff on a younger sibling, etc. So, considering that the average person is unlikely to act in such a (inappropriate?) way, I was wary; particularly of the technique where you're expected to touch each thing to determine if it brings you joy. I decided to let the ideas, bereft of the awkward bits, simmer for a few days before deciding to put them into practice.&lt;/p&gt;
&lt;p&gt;About a week later, I realized that the ideas could apply, not just for physical possessions, but also for a lot of ideas and thoughts swirling in my head. I'm one of those people who has at least 1 side-project going on in addition to a serious hobby. I was often left feeling like I'd never done enough and there were lots of incomplete projects (mostly software) or things I wanted to get better at (photography, playing the saxophone, etc). Truth be told, I take on way more things than I realistically have time for. These would weigh heavily on my mind whenever I spent time broadly reflecting on how things were going and whether I'd made progress in my various endeavors.&lt;/p&gt;
&lt;p&gt;Around the same time, in January, I'd started trying to re-organize my life (yeah, a bit radical) using the techniques outlined in &lt;a class="reference external" href="https://vijay.varadan.com/talks/review--getting-results-the-agile-way/"&gt;Getting Results the Agile Way&lt;/a&gt; and there are some common threads in both books which apply broadly to better self-organization.&lt;/p&gt;
&lt;p&gt;Eight weeks later, I re-read the book, this time prepared to filter out the awkward bits and focus on the core. Looking back at the last few weeks to see what I actually used, here's what I've learned:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Tidying up is about getting rid of things, not finding places to put (hide?) things away.&lt;/li&gt;
&lt;li&gt;I interpreted the part about &amp;quot;keeping only the things that bring joy&amp;quot; along slightly more practical lines of &amp;quot;is this something I will use going forward?&amp;quot; This interpretation seemed a little less &amp;quot;fluffy&amp;quot; to me.&lt;/li&gt;
&lt;li&gt;Tidying by category is an excellent idea. Bringing all things of the same category together gives a clearer big picture and makes it easier to decide what to get rid of; hint: bigger pile means you're likely to dispose off more.&lt;/li&gt;
&lt;li&gt;From the part about dealing with mementos: I found that when applied to my mind, it helped me to eliminate wasteful brain cycles on past, incomplete side-projects and hobbies that I'm unlikely to resume. The focus has shifted firmly to my on-going and near-future side-projects .&lt;/li&gt;
&lt;li&gt;From the technique to designate a place for each thing: I'm a &amp;quot;work hard, play hard&amp;quot; kind of person. The &amp;quot;play hard&amp;quot; part becomes difficult when I don't feel like I've accomplished the &amp;quot;work hard&amp;quot; part; not because I didn't work hard, but because of distractions from work remnants. Separating the two clearly has reduced the interruptions in my head, resulting in better focus and higher productivity.&lt;/li&gt;
&lt;li&gt;I used to store stuff by fine-grained categories which made things more difficult to find. Broad classification for storing items works well. Fewer places to look for things, consequently things are easier to find.&lt;/li&gt;
&lt;li&gt;&amp;quot;Empty your bag everyday&amp;quot; didn't work for me. I have disparate items that I carry in my bag. They get stored in different places and I found that I spent more time putting away and gathering things that needed to go into my bag, sometimes forgetting items.&lt;/li&gt;
&lt;li&gt;Bulk buying is economical and unless I become severely space constrained, I plan to ignore its description as hoarding.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Tidying-up definitely has a positive effect on other parts of my life. There are fewer distractions, less visual noise, and reduced guilt from having to see unused items (in my case mostly books).&lt;/p&gt;
&lt;/div&gt;
</content><category term="Productivity"/><category term="bookReview"/><category term="productivity"/></entry><entry><title>Review: Getting Results the Agile Way</title><link href="https://vijay.varadan.com/talks/review--getting-results-the-agile-way/" rel="alternate"/><published>2017-02-08T18:58:00-08:00</published><updated>2017-02-08T18:58:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2017-02-08:/talks/review--getting-results-the-agile-way/</id><summary type="html">&lt;p class="first last"&gt;Recommended, but only chapters 1-4.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="post image" src="https://vijay.varadan.com/talks/images/getting-results-the-agile-way.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Author: J. D. Meier&lt;/strong&gt;&lt;/p&gt;
&lt;div class="section" id="verdict-recommended-recommended-but-only-chapters-1-4"&gt;
&lt;h2&gt;Verdict: &lt;img alt="recommended" src="https://vijay.varadan.com/talks/images/recommended.png" /&gt; &lt;strong&gt;Recommended&lt;/strong&gt; (but only chapters 1-4)&lt;/h2&gt;
&lt;p&gt;The book uses Agile principles as a basis for defining a results oriented approach to work and personal life. The meat of the book is in the first part, chapters 1-4 (about 60 pages). Parts II-III and the appendix (the remaining 180 pages) expand on the information in part I (needlessly?). Be warned, there is a &lt;strong&gt;lot of unnecessary repetition&lt;/strong&gt; of the same information with added verbosity later in the book. As a result these negatives, I highly recommend &lt;strong&gt;only&lt;/strong&gt; part I of the book.&lt;/p&gt;
&lt;p&gt;I've tried several systems of self-organization to prioritize tasks and reduce &amp;quot;wasted&amp;quot; time. I found some of them vague (e.g. Just Fucking Ship) or unsustainable (e.g. What the Most Successful People do at Work). To clarify, those books have worked for people, they didn't work for me.&lt;/p&gt;
&lt;p&gt;&amp;quot;Getting Results the Agile Way&amp;quot; has a small set of repeatable steps, is  simple, lightweight and as a result doesn't get in the way. In fact, being dead simple makes it easy to start using and to &lt;strong&gt;continue&lt;/strong&gt; using.&lt;/p&gt;
&lt;p&gt;A focus on outcomes i.e. end results (not goals or tasks) forms the backbone of the system; first at a high level (annual), from which monthly, weekly and finally daily outcomes are successively derived. The suggestions is to keep only &lt;strong&gt;3 outcomes&lt;/strong&gt; on your radar, any more may result in lost focus. Tasks are the actions that you take towards achieving the outcomes. Also, I like the recommendation to pick &lt;strong&gt;one improvement each month&lt;/strong&gt; to work on.&lt;/p&gt;
&lt;p&gt;A strong bias towards action to overcome analysis-paralysis, time-boxing (limiting time, so energy levels are high), versioning results to avoid perfectionism, incremental results, varying your approach till one works, separate action items from informational items.&lt;/p&gt;
&lt;p&gt;Some examples of improvements I was able to make:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;I had a problem reading non-technology, non-fiction books. I'd read half a dozen pages, but couldn't tell you what I'd just read in the last 5 minutes; go back, rinse, repeat and still not absorb the material. I was able to overcome this by changing my approach:&lt;ul&gt;
&lt;li&gt;I used Tabata timers initially and subsequently the Pomodoro technique to stay focused and not let my mind wander.&lt;/li&gt;
&lt;li&gt;I also started writing 1-3 line summaries or key takeaways for each page as I read it. Within 10 days, I'd finished reading 4 books and was back at my old reading pace from about 7 years ago.&lt;/li&gt;
&lt;li&gt;I no longer need to write notes to focus, but I've started trying out the Kindle app's Text-to-Speech feature (2x speed) while I myself read the book - it works really well.&lt;/li&gt;
&lt;li&gt;For printed books, if I find myself losing concentration, I read aloud to myself.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I added time tracking to ensure that I:&lt;ul&gt;
&lt;li&gt;Spent at least 1 hour a day having fun.&lt;/li&gt;
&lt;li&gt;Set aside 8 hours a week in non-work socializing.&lt;/li&gt;
&lt;li&gt;Got 7-8 hours of sleep. Tracking showed that I watched shows at night to unwind. I canceled my Netflix membership, fell asleep faster and gained the benefits of higher energy levels and sharper focus.&lt;/li&gt;
&lt;li&gt;Became realistic about time spent on life essentials like chores, errands, etc&lt;/li&gt;
&lt;li&gt;Started batching up tasks that could be done simultaneously. e.g. iron my clothes while watching shows.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I would beat myself up about not making progress on my side-projects (come on, admit it - you have a few yourself). So, I started writing down how much time I had outside of life essentials (incl. sleep &amp;amp; meals), work, socializing &amp;amp; (minimal) fun (aka stress busters). Tracking time using a calendar color coded with broad categories (essentials, fun, work and socializing) showed me that I realistically had only 20 hours a week for my side-projects and hobbies. I've reset my expectations, altered my plan accordingly and don't feel frustrated at myself for failing to get as much done as I &amp;quot;ought to&amp;quot;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="notes-only-part-i"&gt;
&lt;h2&gt;Notes (only Part I)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; These are primarily written for my own future reference, but they may be useful to you, either to decide if you want to read / buy the book or as something to revisit. The information is not comprehensive, not in the least - so, please don't use it as a substitute for actually reading the book. As with all my content, some is verbatim from the original source, opinion may be interspersed &amp;amp; of course, YMMV.&lt;/p&gt;
&lt;div class="section" id="foundation"&gt;
&lt;h3&gt;Foundation&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;10 Values.&lt;/li&gt;
&lt;li&gt;10 Principles.&lt;/li&gt;
&lt;li&gt;12 Practices.&lt;/li&gt;
&lt;li&gt;No big upfront design.&lt;/li&gt;
&lt;li&gt;Pave a path; find a way forward.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="values"&gt;
&lt;h4&gt;10 Values&lt;/h4&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Action over analysis-paralysis.&lt;/li&gt;
&lt;li&gt;Approach over results: results as gauge.&lt;/li&gt;
&lt;li&gt;Energy over (as in above) time.&lt;/li&gt;
&lt;li&gt;Focus over quantity: focus is the force multiplier.&lt;/li&gt;
&lt;li&gt;Good enough over perfection.&lt;/li&gt;
&lt;li&gt;Growth mindset over fixed mindset.&lt;/li&gt;
&lt;li&gt;Outcomes over activities: focus on results.&lt;/li&gt;
&lt;li&gt;Maximize strengths: spend less time shoring up weaknesses.&lt;/li&gt;
&lt;li&gt;System over ad-hoc: for basics.&lt;/li&gt;
&lt;li&gt;Value-up over backlog burndown: &amp;quot;What's the next best thing to do?&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="principles"&gt;
&lt;h4&gt;10 Principles&lt;/h4&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;80/20: 80% action, 20% analysis.&lt;/li&gt;
&lt;li&gt;Change your approach: tune as you go.&lt;/li&gt;
&lt;li&gt;Continuous learning&lt;/li&gt;
&lt;li&gt;Deliver incremental value.&lt;/li&gt;
&lt;li&gt;Less is more: reduce work that's in-flight.&lt;/li&gt;
&lt;li&gt;Factor out action from reference: reduce signal to noise ratio.&lt;/li&gt;
&lt;li&gt;Set boundaries: both for time and energy.&lt;/li&gt;
&lt;li&gt;Fix time, flex scope: time is a 1st class citizen.&lt;/li&gt;
&lt;li&gt;Rhythm of results: habit becomes ritual =&amp;gt; produces feeling of accomplishment.&lt;/li&gt;
&lt;li&gt;Version your results: fight perfectionism.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="practices"&gt;
&lt;h4&gt;12 Practices&lt;/h4&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Rule of &lt;strong&gt;3&lt;/strong&gt;: focus on vital things; a buffet you can go back to, don't overfill your plate.&lt;/li&gt;
&lt;li&gt;Monday vision, daily outcome, Friday reflection.&lt;/li&gt;
&lt;li&gt;Scannable outcomes: what's on your radar?&lt;/li&gt;
&lt;li&gt;Daily outcomes: &lt;strong&gt;3&lt;/strong&gt; action items for the day.&lt;/li&gt;
&lt;li&gt;Weekly outcomes.&lt;/li&gt;
&lt;li&gt;Strong week: do the toughest things that drain you early in the week to create a glide path.&lt;/li&gt;
&lt;li&gt;Timebox your day: optimize &amp;amp; prioritize.&lt;/li&gt;
&lt;li&gt;Triage incoming action items: Do / Queue / Schedule / Delegate.&lt;/li&gt;
&lt;li&gt;Monthly improvement sprints: pick &lt;strong&gt;1&lt;/strong&gt; thing to improve each month.&lt;/li&gt;
&lt;li&gt;Growth mindset: get knocked down, get up again.&lt;/li&gt;
&lt;li&gt;Action lists: Daily / Weekly / Queue / Scripts.&lt;/li&gt;
&lt;li&gt;Reference collections: for non-actionable information.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr class="docutils" /&gt;
&lt;div class="section" id="hot-spots"&gt;
&lt;h3&gt;Hot Spots&lt;/h3&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Things that are important i.e. big picture items and long term goals.&lt;/li&gt;
&lt;li&gt;Clusters of important things going on in your life.&lt;/li&gt;
&lt;li&gt;At a macro-level think in terms of work, personal &amp;amp; life.&lt;/li&gt;
&lt;/ol&gt;
&lt;table&gt;
&lt;tr&gt;
&lt;th colspan=3 align=center&gt;&lt;strong&gt;Hot Spots&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td align=center&gt;&lt;strong&gt;Life Frame&lt;/strong&gt;&lt;/td&gt;
&lt;td align=center&gt;&lt;strong&gt;Work&lt;/strong&gt;&lt;/td&gt;
&lt;td align=center&gt;&lt;strong&gt;Personal&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td &gt;&lt;ul&gt;&lt;li&gt;Mind&lt;/li&gt;&lt;li&gt;Body&lt;/li&gt;&lt;li&gt;Emotions&lt;/li&gt;&lt;li&gt;Career&lt;/li&gt;&lt;li&gt;Financial&lt;/li&gt;&lt;li&gt;Relationships&lt;/li&gt;&lt;li&gt;Fun&lt;/li&gt;&lt;/ul&gt;&lt;/td&gt;
&lt;td &gt;&lt;ul&gt;&lt;li&gt;Activities&lt;/li&gt;&lt;li&gt;Active Projects&lt;/li&gt;&lt;li&gt;Backlog&lt;/li&gt;&lt;/ul&gt;&lt;/td&gt;
&lt;td &gt;&lt;ul&gt;&lt;li&gt;Activities&lt;/li&gt;&lt;li&gt;Active Projects&lt;/li&gt;&lt;li&gt;Backlog&lt;/li&gt;&lt;/ul&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;ol class="arabic simple"&gt;
&lt;li&gt;Set boundaries: max / min time &amp;amp; energy; use Hot Spots to set these boundaries. e.g. max 50 hrs for work and min 3 hrs for body (workout).&lt;/li&gt;
&lt;li&gt;Worst mistake is to continually throw more time at problems.&lt;/li&gt;
&lt;li&gt;Increase value, improve efficiency &amp;amp; effectiveness =&amp;gt; reduce time spent.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="section" id="activities"&gt;
&lt;h4&gt;Activities&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Recurring activities like administration, mentoring, status meetings for work; household chores, grocery shopping for personal.&lt;/li&gt;
&lt;li&gt;Make a list for each big activity =&amp;gt; enables you to see stuff at a glance.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3&lt;/strong&gt; most important results at the top.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="active-projects"&gt;
&lt;h4&gt;Active Projects&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt; list per project =&amp;gt; this is your queue.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="backlog"&gt;
&lt;h4&gt;Backlog&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt; list per major backlog item.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr class="docutils" /&gt;
&lt;div class="section" id="monday-vision-daily-outcomes-friday-reflection"&gt;
&lt;h3&gt;Monday Vision, Daily Outcomes, Friday Reflection&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Deliver value over backlog burndown.&lt;/li&gt;
&lt;li&gt;Rule of &lt;strong&gt;3&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Frame results for the week.&lt;/li&gt;
&lt;li&gt;Test for success: (re)define outcomes based on what success looks like.&lt;/li&gt;
&lt;li&gt;Scenario driven results: e.g. laying on a hammock &amp;amp; enjoying the rose garden, rather than tasks like mowing the lawn. Gives work meaning &amp;amp; improves quality of life.&lt;/li&gt;
&lt;li&gt;Incremental progress.&lt;/li&gt;
&lt;li&gt;Have a buffer: at a buffer, you would take smaller portions, make multiple trips. Buffers help see opportunities. No buffer =&amp;gt; only threats are visible.&lt;/li&gt;
&lt;li&gt;Use timeboxes: spend energy effectively.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="monday-vision"&gt;
&lt;h4&gt;Monday Vision&lt;/h4&gt;
&lt;p&gt;Identify &lt;strong&gt;3&lt;/strong&gt; outcomes for the week:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Use Hot Spots as input.&lt;/li&gt;
&lt;li&gt;Focus on where you want to be at the end of the week.&lt;/li&gt;
&lt;li&gt;Focus on outcomes, not activities / tasks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="daily-outcomes"&gt;
&lt;h4&gt;Daily Outcomes&lt;/h4&gt;
&lt;p&gt;Identify &lt;strong&gt;3&lt;/strong&gt; outcomes for the day:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;You can always add more later.&lt;/li&gt;
&lt;li&gt;Don't get caught up in backlog.&lt;/li&gt;
&lt;li&gt;Choose most valuable things.&lt;/li&gt;
&lt;li&gt;Track against the week's &lt;strong&gt;3&lt;/strong&gt; outcomes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Must&lt;/strong&gt;, &lt;strong&gt;Should&lt;/strong&gt;, &lt;strong&gt;Could&lt;/strong&gt; are the &lt;strong&gt;3&lt;/strong&gt; buckets for the daily list:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Must&lt;/strong&gt; =&amp;gt; got to get these done.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Should&lt;/strong&gt; =&amp;gt; nice to haves.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Could&lt;/strong&gt; =&amp;gt; pipe dreams.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="friday-reflection"&gt;
&lt;h4&gt;Friday Reflection&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Focus on the pitch, not the scoreboard.&lt;/li&gt;
&lt;li&gt;Evaluate what got done, or what didn't and why.&lt;/li&gt;
&lt;li&gt;Be balanced: what needs improvement &lt;strong&gt;and&lt;/strong&gt; what went well.&lt;/li&gt;
&lt;li&gt;Get clarity on personal success patterns and what needs to change.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Productivity"/><category term="bookReview"/><category term="agile"/><category term="productivity"/></entry><entry><title>Review: User Story Mapping</title><link href="https://vijay.varadan.com/talks/review--user-story-mapping/" rel="alternate"/><published>2017-02-07T23:58:00-08:00</published><updated>2017-02-07T23:58:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2017-02-07:/talks/review--user-story-mapping/</id><summary type="html">&lt;p class="first last"&gt;Recommended: In-depth treatment, good writing style makes it easy to absorb information.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="post image" src="https://vijay.varadan.com/talks/images/user-story-mapping.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Author&lt;/strong&gt;: Jeff Patton&lt;/p&gt;
&lt;div class="section" id="verdict-recommended-recommended"&gt;
&lt;h2&gt;Verdict: &lt;img alt="recommended" src="https://vijay.varadan.com/talks/images/recommended.png" /&gt; &lt;strong&gt;Recommended&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Took me about 9 hours to read. It's a bit wordy and has some repetition, but I was able to look past that due to the quality of information. I possibly have a slight bias towards the techniques outlined because I've used them with some variations both at Expedia and at my own company, but I see that more as validation that the user story mapping works better than the traditional software requirements. This is particularly true for products whose form and function fluctuate because end-users themselves aren't aware of what they need (which is very different from what they think they want) and don't know how software can make their lives better (simpler, enable them to get more done, etc).&lt;/p&gt;
&lt;div class="section" id="the-good"&gt;
&lt;h3&gt;The Good&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;In-depth coverage of user story mapping.&lt;/li&gt;
&lt;li&gt;Good use cases with sufficient detail which keep the reader engaged.&lt;/li&gt;
&lt;li&gt;Covers how things can go wrong / off-track if the basics aren't at the forefront of your mind.&lt;/li&gt;
&lt;li&gt;Good tips on how to get people out of the traditional requirements gathering and spec writing mindset.&lt;/li&gt;
&lt;li&gt;Clear six-step process to story mapping, viz. frame the problem, map the big picture, explore, slice out strategies for release, learning and development.&lt;/li&gt;
&lt;li&gt;Possibly a book to keep on your shelf if this is your primary job function.&lt;/li&gt;
&lt;li&gt;References to books and publications for related topics.&lt;/li&gt;
&lt;li&gt;I liked the analogy of using the classic Asteroids game (by Atari) to break down large user stories into smaller ones, but not all of them at once - too many small user stories becomes like the huge number of tiny asteroid chunks on-screen if you shoot at all the large asteroid.&lt;/li&gt;
&lt;li&gt;Sage advice that you're not done once you release - there's work to determine if what you built is right, to figure out improvements and to create plans to work on the significant ones.&lt;/li&gt;
&lt;li&gt;Stand-out message: Deliver half a baked cake, not a half-baked cake.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-bad"&gt;
&lt;h3&gt;The Bad&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Harping about building shared understanding. Yes, it central to user story mapping and it's good to hear cautionary tales and gotchas, but it gets old after the first couple of times.&lt;/li&gt;
&lt;li&gt;Some analogies / exercises are a bit worn out, though I probably feel that way reading about them and they actually work well in practice.&lt;/li&gt;
&lt;li&gt;The goldfish bowl technique to limit active participants in discussions doesn't work in my experience. It's better to exclude people that aren't necessary and fill them in later, regardless of how they may feel about it. And yes, making the determination about who is necessary is a judgement call.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ugly"&gt;
&lt;h3&gt;The Ugly&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Low resolution images in the Kindle version which you must zoom into (feature not available on the Kindle desktop app, btw), squint your eyes to be able to make anything out.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Management"/><category term="bookReview"/><category term="agile"/><category term="engineering"/><category term="userStoryMapping"/><category term="projectManagement"/></entry><entry><title>Review: Software in 30 Days</title><link href="https://vijay.varadan.com/talks/review--software-in-30-days/" rel="alternate"/><published>2017-02-05T23:50:00-08:00</published><updated>2017-02-05T23:50:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2017-02-05:/talks/review--software-in-30-days/</id><summary type="html">&lt;p class="first last"&gt;YMMV (Your Mileage May Vary). The book is primarily for executives &amp;amp; decision makers.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="post image" src="https://vijay.varadan.com/talks/images/software-in-30-days.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Authors&lt;/strong&gt;: Ken Schwaber, Jeff Sutherland&lt;/p&gt;
&lt;div class="section" id="verdict-ymmv-ymmv-your-mileage-may-vary"&gt;
&lt;h2&gt;Verdict: &lt;img alt="ymmv" src="https://vijay.varadan.com/talks/images/ymmv.png" /&gt; &lt;strong&gt;YMMV (Your Mileage May Vary)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The authors state that the goal of the book is to provide an overview of agile methodology, but it only talks about Scrum. It's geared towards executives or decision makers who want more information &amp;amp; learn about its benefits. So, it's not particularly prescriptive or in-depth. I found it a little on the light side, but the information is well laid out with a fair number of case studies, so it doesn't get tedious.&lt;/p&gt;
&lt;div class="section" id="the-good"&gt;
&lt;h3&gt;The Good&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;If you're unfamiliar with agile, there's enough information here (including in the appendixes) to understand its benefits &amp;amp; what to reasonably expect both in the early stages of agile rollout as well as once it is implemented across the organization at large (see shortcomings in &amp;quot;The Bad&amp;quot; section below).&lt;/li&gt;
&lt;li&gt;Can serve as a quick refresher if you haven't done agile in a while.&lt;/li&gt;
&lt;li&gt;Reasonable amount of information without hand-waving.&lt;/li&gt;
&lt;li&gt;Fairly quick read, took me about 6 hours.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-bad"&gt;
&lt;h3&gt;The Bad&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Since it's written by the creators of Scrum, there is a fair amount of bias &amp;amp; the downsides of Scrum or agile methods in general are not given any real treatment.&lt;/li&gt;
&lt;li&gt;Waterfall is the whipping-boy &amp;amp; while its shortcomings are well-known, I've seen it work reasonably well in practice for core platform libraries &amp;amp; services - this is one weakness for agile, because the methodology doesn't allow for rumination or &amp;quot;simmer time&amp;quot; for design / architectural decisions based on which the foundation layer(s) is / are built. Foundation layers cannot keep changing; they must have firm, well-understood requirements, simply because other layers are built on top of them &amp;amp; any alterations to foundation layers will cause ripple effects all through the system. Yes, there are ways to mitigate some of that (e.g. via abstractions &amp;amp; loose coupling), but there are real world limits in terms of time &amp;amp; resources that dictate how much mitigation can be incorporated.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ugly"&gt;
&lt;h3&gt;The Ugly&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Making waterfall methodology the whipping boy, without acknowledging that when used with shorter milestones &amp;amp; regular integration, it works better for building foundation layers - design &amp;amp; architectural decisions require &amp;quot;simmer time&amp;quot; &amp;amp; in the real world, there is a pretty high cost to making changes to foundation layers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Management"/><category term="bookReview"/><category term="agile"/><category term="scrum"/><category term="engineering"/><category term="softwareEngineering"/><category term="projectManagement"/></entry><entry><title>Review: The Five Dysfunctions of a Team</title><link href="https://vijay.varadan.com/talks/review--the-five-dysfunctions-of-a-team/" rel="alternate"/><published>2017-02-02T23:50:00-08:00</published><updated>2017-02-02T23:50:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2017-02-02:/talks/review--the-five-dysfunctions-of-a-team/</id><summary type="html">&lt;p class="first last"&gt;Recommended. Well worth the time.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="post image" src="https://vijay.varadan.com/talks/images/the-five-dysfunctions-of-a-team.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Author&lt;/strong&gt;: Patrick Lencioni&lt;/p&gt;
&lt;div class="section" id="verdict-recommended-recommended"&gt;
&lt;h2&gt;Verdict: &lt;img alt="recommended" src="https://vijay.varadan.com/talks/images/recommended.png" /&gt; &lt;strong&gt;Recommended&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;This book is well worth the 5 hours I spent reading it. In my 10+ years of managing teams, I have encountered these dysfunctions &amp;amp; (bad?) behaviors in mid-level &amp;amp; senior-level management teams. So, even though the example used is of an executive team (C-level), the methods in the book to root out the behaviors applies at all levels of management. This would've been an invaluable read for me 12 years ago.&lt;/p&gt;
&lt;div class="section" id="the-good"&gt;
&lt;h3&gt;The Good&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The fable style of writing is engaging without dramatics. Clean &amp;amp; crisp; a fast read. I quite enjoyed it.&lt;/li&gt;
&lt;li&gt;There's a separate section &amp;quot;The Model&amp;quot; which outlines the five dysfunctions, symptoms thereof, their impact &amp;amp; an outline of potential solutions which are practical. So, if you don't like fables, skip directly to this section.&lt;/li&gt;
&lt;li&gt;I've used most of the techniques suggested to overcome the dysfunctions &amp;amp; can confirm that they work in practice. A few were new to me &amp;amp; I'll have to see how well they apply.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-bad"&gt;
&lt;h3&gt;The Bad&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The fable style of writing may not appeal to some folks, in which case skip to &amp;quot;The Model&amp;quot; section for the actual meat of the information. To be honest, I liked the fable style.&lt;/li&gt;
&lt;li&gt;The information within each dysfunction section within &amp;quot;The Model&amp;quot; section could be better structured to clearly &amp;amp; succinctly separate out causes, motivations behind behaviors indicative of causes, mitigation. Though there are separate sub-sections, the information still feels scattered about &amp;amp; repeated (repetition may be due to inter-relatedness, not sure).&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ugly"&gt;
&lt;h3&gt;The Ugly&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Nothing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="notes"&gt;
&lt;h2&gt;Notes&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: These are primarily written for my own future reference, but they may be useful to you, either to decide if you want to read / buy the book or as something to revisit. The information is not comprehensive, not in the least - so, please don't use it as a substitute for actually reading the book. As with all my content, some is verbatim from the original source, opinion may be interspersed &amp;amp; of course, &lt;strong&gt;YMMV&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="section" id="pyramid-of-5-dysfunctions"&gt;
&lt;h3&gt;Pyramid of 5 Dysfunctions&lt;/h3&gt;
&lt;p&gt;&lt;img alt="five-dysfunctions-pyramid" src="https://vijay.varadan.com/talks/images/five-dysfunctions-pyramid.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://iawir.wordpress.com/2012/07/26/the-five-dysfunctions-of-a-team/"&gt;Image source&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="absence-of-trust"&gt;
&lt;h3&gt;1. Absence of Trust&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Trust is the confidence that their peers' intentions are good, &amp;amp; that here is no reason to be protective around the group.&lt;/em&gt;&lt;/p&gt;
&lt;div class="section" id="causes"&gt;
&lt;h4&gt;Causes&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Instinctively, people compete with peers, don't want to seem weak by asking for help, are protective of their reputation &amp;amp; minimize / hide mistakes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="members-of-teams-with-an-absence-of-trust"&gt;
&lt;h4&gt;Members of Teams with an Absence of Trust&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Conceal their weakness &amp;amp; mistakes from one another.&lt;/li&gt;
&lt;li&gt;Hesitate to ask for help or provide constructive feedback.&lt;/li&gt;
&lt;li&gt;Hesitate to offer help outside their own areas of responsibility.&lt;/li&gt;
&lt;li&gt;Jump to conclusions about the intentions &amp;amp; aptitudes of others without attempting to clarify them.&lt;/li&gt;
&lt;li&gt;Fail to recognize &amp;amp; tap into one another's skills &amp;amp; experience.&lt;/li&gt;
&lt;li&gt;Waste time &amp;amp; energy managing their behaviors for effect.&lt;/li&gt;
&lt;li&gt;Hold grudges.&lt;/li&gt;
&lt;li&gt;Dread meetings &amp;amp; find reasons to avoid spending time together.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="members-of-trusting-teams"&gt;
&lt;h4&gt;Members of Trusting Teams&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Admit weaknesses &amp;amp; mistakes.&lt;/li&gt;
&lt;li&gt;Ask for help.&lt;/li&gt;
&lt;li&gt;Accept questions &amp;amp; input about their areas of responsibility.&lt;/li&gt;
&lt;li&gt;Give one another the benefit of the doubt before arriving at a negative conclusion.&lt;/li&gt;
&lt;li&gt;Take risks in offering feedback &amp;amp; assistance.&lt;/li&gt;
&lt;li&gt;Appreciate &amp;amp; tap into one another's skills &amp;amp; experiences.&lt;/li&gt;
&lt;li&gt;Focus time &amp;amp; energy on important issues, not politics.&lt;/li&gt;
&lt;li&gt;Offer &amp;amp; accept apologies w/o hesitation.&lt;/li&gt;
&lt;li&gt;Look forward to meeting &amp;amp; opportunities to work as a group.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="overcoming-absence-of-trust"&gt;
&lt;h4&gt;Overcoming Absence of Trust&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Requires shared experience over time, multiple instances of follow-through (build credibility), &amp;amp; an in-depth understanding of what each team member brings to the table.&lt;/li&gt;
&lt;li&gt;Personal histories exercise: Low risk, share information about non-sensitive information like number of siblings, hometown, unique challenges of childhood, favorite hobbies, first job &amp;amp; worst job. Encourages greater empath &amp;amp; discourages inaccurate behavioral attributions.&lt;/li&gt;
&lt;li&gt;Team effectiveness exercise: Team members need to identify sinble most important contribution that each peer makes to the team &lt;strong&gt;and&lt;/strong&gt; one area that must be improved / eliminated for the good of the team.&lt;/li&gt;
&lt;li&gt;Personality &amp;amp; behavioral preference profiles: e.g. Myers-Briggs Type Indicator (MBTI), Everything DiSC - provide practical &amp;amp; scientifically valid behavioral descriptions of team members. Tools require participation of a licensed consultant to avoid misuse.&lt;/li&gt;
&lt;li&gt;360-degree feedback: Higher risk since peers needs to make specific judgments &amp;amp; provide constructive criticism. Must be divorced entirely from compensation &amp;amp; formal performance evaluation to avoid political undertones, &amp;amp; fear impact on compensation &amp;amp; on repercussions.&lt;/li&gt;
&lt;li&gt;Experiential team exercises: Not sure what these are. Need to investigate.&lt;/li&gt;
&lt;li&gt;Revisit individual developmental areas to ensure momentum is sustained - atrophy can lead to erosion of trust.&lt;/li&gt;
&lt;li&gt;Leader must demonstrate &lt;strong&gt;genuine&lt;/strong&gt; vulnerability first to encourage building of trust.&lt;/li&gt;
&lt;li&gt;Leader must create an environment that does not punish vulnerability - no chastisement from anyone for admission of weakness / failure, discourages trust, however subtly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="connection-to-fear-of-conflict"&gt;
&lt;h4&gt;Connection to Fear of Conflict&lt;/h4&gt;
&lt;p&gt;Fear of punishment due to misinterpretation of what is said as destructive / critical when engaged in a passionate debate.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="fear-of-conflict"&gt;
&lt;h3&gt;2. Fear of Conflict&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Healthy long-term relationships require productive conflict, especially in business.&lt;/em&gt;&lt;/p&gt;
&lt;div class="section" id="causes-1"&gt;
&lt;h4&gt;Causes&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Desire to avoid hurt feelings.&lt;/li&gt;
&lt;li&gt;Misguided thinking that avoiding conflict increases efficiency.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Productive ideological conflict is very different from destructive fighting &amp;amp; interpersonal politics. Ideological conflict is about concepts &amp;amp; ideas, not personality-focused, mean-spirited attacks.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="teams-that-fear-conflict"&gt;
&lt;h4&gt;Teams that Fear Conflict&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Have boring meetings (? don't get this point).&lt;/li&gt;
&lt;li&gt;Create environments where back-channel politics &amp;amp; personal attacks thrive.&lt;/li&gt;
&lt;li&gt;Ignore controversial topics that are critical to team success.&lt;/li&gt;
&lt;li&gt;Fail to tap into all the opinions &amp;amp; perspectives of team members.&lt;/li&gt;
&lt;li&gt;Waste time &amp;amp; energy with posturing &amp;amp; interpersonal risk management.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="teams-that-engage-in-conflict"&gt;
&lt;h4&gt;Teams that Engage in Conflict&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Have lively, interesting meetings (? again, don't get this point).&lt;/li&gt;
&lt;li&gt;Extract &amp;amp; exploit the ideas of all team members.&lt;/li&gt;
&lt;li&gt;Solve real problems quickly.&lt;/li&gt;
&lt;li&gt;Minimize politics.&lt;/li&gt;
&lt;li&gt;Put critical topics on the table for discussion.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="overcoming-fear-of-conflict"&gt;
&lt;h4&gt;Overcoming Fear of Conflict&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Mining: Members of teams which tend to avoid conflict need to extract buried agreements, call out sensitive issues &amp;amp; force the team to work through them - requires objectivity &amp;amp; commitment to stay with the conflict till resolved.&lt;/li&gt;
&lt;li&gt;Real-time permission: coach one another not to retreat from healthy debate. Remind people when they become uncomfortable with level of discord that it's necessary - need to be careful not to come across as patronizing.&lt;/li&gt;
&lt;li&gt;Other tools: Thomas-Kilmann Conflict Mode Instrument, commonly know as TKI - Need to investigate, no idea about this tool.&lt;/li&gt;
&lt;li&gt;Leader should forego the desire to protect members from harm - avoid prematurely interrupting disagreements which prevents team members from developing conflict management skills.&lt;/li&gt;
&lt;li&gt;Leader should demonstrate restraint &amp;amp; allow resolution to occur naturally - can be messy.&lt;/li&gt;
&lt;li&gt;Leader should actively take on conflict when necessary &amp;amp; productive.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="connection-to-lack-of-commitment"&gt;
&lt;h4&gt;Connection to Lack of Commitment&lt;/h4&gt;
&lt;p&gt;How can a team buy into a decision &amp;amp; confidently commit to anything until it has engaged in productive conflict &amp;amp; members' perspectives &amp;amp; opinions have been considered?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="lack-of-commitment"&gt;
&lt;h3&gt;3. Lack of Commitment&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Commitment = clarity + buy-in&lt;/em&gt;&lt;/p&gt;
&lt;div class="section" id="causes-2"&gt;
&lt;h4&gt;Causes&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Desire for consensus.&lt;/li&gt;
&lt;li&gt;Need for certainty.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dysfunctional teams try to hedge bets &amp;amp; delay important decisions till they're certain of correctness. Analysis-paralysis breeds lack of confidence. Primary reason for dangerous ripple effects on subordinates - clashes will occur when employees reporting to different execs are marching to different tunes.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="a-team-that-fails-to-commit"&gt;
&lt;h4&gt;A Team that Fails to Commit&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Creates ambiguity among the team about direction &amp;amp; priorities.&lt;/li&gt;
&lt;li&gt;Watches windows of opportunity close due to excessive analysis &amp;amp; unnecessary delay&lt;/li&gt;
&lt;li&gt;Breeds lack of confidence &amp;amp; fear of failure&lt;/li&gt;
&lt;li&gt;Revisits discussions &amp;amp; decisions again &amp;amp; again&lt;/li&gt;
&lt;li&gt;Encourages second-guessing among team members&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="a-team-that-commits"&gt;
&lt;h4&gt;A Team that Commits&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Creates clarity around direction &amp;amp; priorities.&lt;/li&gt;
&lt;li&gt;Aligns the entire team around common objectives.&lt;/li&gt;
&lt;li&gt;Develops an ability to learn from mistakes.&lt;/li&gt;
&lt;li&gt;Takes advantage of opportunities before competitors do.&lt;/li&gt;
&lt;li&gt;Moves forward without hesitation.&lt;/li&gt;
&lt;li&gt;Changes direction without hesitation or guilt.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="overcoming-lack-of-commitment"&gt;
&lt;h4&gt;Overcoming Lack of Commitment&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Cascading messaging: Explicitly review key decisions &amp;amp; agree to what to communicate to employees / other constituents.&lt;/li&gt;
&lt;li&gt;Deadlines: Honor deadlines with discipline &amp;amp; rigidity. Also applies to milestones, since that's how misalignment is identified &amp;amp; addressed before costs become too great.&lt;/li&gt;
&lt;li&gt;Contingency &amp;amp; worst-case scenario analysis: Reduces fear that costs of incorrect decision are survivable.&lt;/li&gt;
&lt;li&gt;Low-risk exposure therapy: Teams with dysfunctions tend to overvalue research &amp;amp; analysis. Use low-risk situations to demonstrate success of decisiveness once they have had substantial discussion with sufficient information.&lt;/li&gt;
&lt;li&gt;Leader makes the decision in case of impasse - &lt;em&gt;a&lt;/em&gt; decision is better than &lt;em&gt;no&lt;/em&gt; decision. Better to be bold &amp;amp; wrong, &amp;amp; to change direction just as boldly. No waffling!&lt;/li&gt;
&lt;li&gt;Leader needs to push for closure on issues &amp;amp; must enforce adherence to schedules.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="connection-to-avoidance-of-accountability"&gt;
&lt;h4&gt;Connection to Avoidance of Accountability&lt;/h4&gt;
&lt;p&gt;How can someone be held accountable for something that was not made clear in the first place?&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="avoidance-of-accountability"&gt;
&lt;h3&gt;4. Avoidance of Accountability&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Willingness of team members to call out one another for performance or behaviors that might hurt the team.&lt;/em&gt;&lt;/p&gt;
&lt;div class="section" id="causes-3"&gt;
&lt;h4&gt;Causes&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Members' interpersonal discomfort.&lt;/li&gt;
&lt;li&gt;Tendency to avoid difficult conversations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="a-team-that-avoids-accountability"&gt;
&lt;h4&gt;A Team that Avoids Accountability&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Creates resentment among team members who have different standards of performance.&lt;/li&gt;
&lt;li&gt;Encourages mediocrity.&lt;/li&gt;
&lt;li&gt;Misses deadlines &amp;amp; key deliverables.&lt;/li&gt;
&lt;li&gt;Places an undue burden on the team leader as the sole source of discipline.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="a-team-that-holds-one-another-accountable"&gt;
&lt;h4&gt;A Team that Holds One Another Accountable&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Ensures that poor performers feel pressure to improve.&lt;/li&gt;
&lt;li&gt;Identifies potential problems quickly by questioning one another's approaches without hesitation.&lt;/li&gt;
&lt;li&gt;Establishes respect among team members who are held to the same high standards.&lt;/li&gt;
&lt;li&gt;Avoids excessive bureaucracy around performance management &amp;amp; corrective action.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="overcoming-avoidance-of-accountability"&gt;
&lt;h4&gt;Overcoming Avoidance of Accountability&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Publication of goals &amp;amp; standards: No one can ignore agreements kept in the open.&lt;/li&gt;
&lt;li&gt;Simple &amp;amp; regular progress reviews: Ensures people take action despite inclination not to.&lt;/li&gt;
&lt;li&gt;Team rewards: Create a culture of accountability by shifting rewards to team achievement instead of individual performance. Members will pitch in when another is not pulling his / her weight.&lt;/li&gt;
&lt;li&gt;Leader needs to be careful to not be the only source of discipline - this is indicative of members not holding one another accountable.&lt;/li&gt;
&lt;li&gt;Leader is arbiter of discipline when team fails - this should be the exception, not the rule. Be clear that accountability is a shared team responsibility, not relegated to a consensus approach.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="connection-to-inattention-to-results"&gt;
&lt;h4&gt;Connection to Inattention to Results&lt;/h4&gt;
&lt;p&gt;Absence of accountability results in team members focusing on personal advancement instead of collective results.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="inattention-to-results"&gt;
&lt;h3&gt;5. Inattention to Results&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Team members care about things other than collective group goals.&lt;/em&gt;&lt;/p&gt;
&lt;div class="section" id="causes-4"&gt;
&lt;h4&gt;Causes&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Lack of specific objectives.&lt;/li&gt;
&lt;li&gt;Lack of focus on specific objectives.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Results are not just profit, revenue or shareholder returns. Executives' goals (destination, strategy) &amp;amp; objectives (route, tactics) are representative of team results - these ultimately drive profit. Focus shifts to teams status &amp;amp; individual status when focus is not on outcome-based. Also, there is no cure for a lack of desire to win.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="a-team-that-is-not-focused-on-results"&gt;
&lt;h4&gt;A Team that is not Focused on Results&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Stagnates / fails to grow.&lt;/li&gt;
&lt;li&gt;Rarely defeats competitor.&lt;/li&gt;
&lt;li&gt;Loses achievement-oriented employees.&lt;/li&gt;
&lt;li&gt;Encourages team members to focus on their own careers &amp;amp; individual goals.&lt;/li&gt;
&lt;li&gt;Is easily distracted.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="a-team-that-focuses-on-collective-results"&gt;
&lt;h4&gt;A Team that Focuses on Collective Results&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Retains achievement-oriented employees.&lt;/li&gt;
&lt;li&gt;Minimizes individualistic behavior.&lt;/li&gt;
&lt;li&gt;Enjoys success &amp;amp; suffers failure acutely (meaning they are not oblivious when failing).&lt;/li&gt;
&lt;li&gt;Benefits from individuals who subjugate their own goals / interests for the good of the team.&lt;/li&gt;
&lt;li&gt;Avoids distractions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="overcoming-inattention-to-results"&gt;
&lt;h4&gt;Overcoming Inattention to Results&lt;/h4&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Make results clear &amp;amp; only rewards behaviors &amp;amp; actions that contribute to those results.&lt;/li&gt;
&lt;li&gt;Public declaration of results: Team works with strong desire to achieve published results.&lt;/li&gt;
&lt;li&gt;Results-based rewards: Tie rewards, especially compensation, to achieving specific outcomes.&lt;/li&gt;
&lt;li&gt;Leader must set the tone for a focus on results. A fish rots from the head down, so leader must value results.&lt;/li&gt;
&lt;li&gt;Leader must reward &amp;amp; give recognition only to those who make real contributions to the achievement of group goals.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Management"/><category term="bookReview"/><category term="management"/><category term="leadership"/></entry><entry><title>Review: Start with Why</title><link href="https://vijay.varadan.com/talks/review--start-with-why/" rel="alternate"/><published>2017-01-29T13:50:00-08:00</published><updated>2017-01-29T13:50:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2017-01-29:/talks/review--start-with-why/</id><summary type="html">&lt;p class="first last"&gt;Watch the 18 min TED Talk instead - there, I saved you 5 hours.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="post image" src="https://vijay.varadan.com/talks/images/start-with-why.jpg" /&gt;&lt;/p&gt;
&lt;div class="section" id="tl-dr-version-avoid"&gt;
&lt;h2&gt;tl;dr version: Avoid&lt;/h2&gt;
&lt;p&gt;Watch the &lt;a class="reference external" href="http://www.ted.com/talks/simon_sinek_how_great_leaders_inspire_action"&gt;18 min TED Talk&lt;/a&gt; instead - you'll waste
considerably less time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Author: Simon Sinek&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="verdict-not-recommended-avoid"&gt;
&lt;h2&gt;Verdict: &lt;img alt="not-recommended" src="https://vijay.varadan.com/talks/images/not-recommended.png" /&gt; &lt;strong&gt;Avoid&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;What should've been a 5 page essay is a 250 page book with lots of redundant information generously smeared with Apple fanboy-ism. You might want to watch his &lt;a class="reference external" href="http://www.ted.com/talks/simon_sinek_how_great_leaders_inspire_action"&gt;TED Talk&lt;/a&gt; instead - you'll waste considerably less time.&lt;/p&gt;
&lt;div class="section" id="the-good-sort-of-watch-the-18-min-ted-talk-instead"&gt;
&lt;h3&gt;The Good (sort of): Watch the &lt;a class="reference external" href="http://www.ted.com/talks/simon_sinek_how_great_leaders_inspire_action"&gt;18 Min TED Talk&lt;/a&gt; instead.&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Focus on 1 point: Successful companies are clear about their core purpose (other than making money); the ones that aren't or deviate from / lose sight of this core purpose fail / die.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-bad"&gt;
&lt;h3&gt;The Bad&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Is it a Circle, Bullhorn or Cone? Why is it &amp;quot;Golden&amp;quot;?&lt;/li&gt;
&lt;li&gt;The contradictions: Apple's success comes from innovation, but TiVo which also innovated failed because &lt;em&gt;&amp;lt;vague reasons&amp;gt;&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;States the obvious: a company needs to have a mission which derives from the vision of its leaders - in his examples, he talks about only 1 leader per company, which is not how most of us have experienced it in the real world.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ugly"&gt;
&lt;h3&gt;The Ugly&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;I can't get back the 5 hours I spent on this.&lt;/li&gt;
&lt;li&gt;Apple worship.&lt;/li&gt;
&lt;li&gt;Reaching quite a bit to draw parallels between Golden { Circle / Bullhorn / Cone } to well-known Golden Ratio - sorry, they are &lt;strong&gt;no&lt;/strong&gt; similarities.&lt;/li&gt;
&lt;li&gt;Playing amateur neuro-scientist linking Golden { Circle / Bullhorn / Cone } parts to human brain function - falls flat on its face.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Management"/><category term="bookReview"/><category term="management"/><category term="leadership"/></entry><entry><title>Python Mixed Metaphors</title><link href="https://vijay.varadan.com/talks/python-mixed-metaphors/" rel="alternate"/><published>2016-07-30T22:50:00-07:00</published><updated>2016-07-30T22:50:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2016-07-30:/talks/python-mixed-metaphors/</id><summary type="html">&lt;p class="first last"&gt;Python violates 'The Priciple of Least Astonishment' when using a mutable default value as a function parameter.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="python logo" src="https://vijay.varadan.com/talks/images/python-logo-notext-300px.png" /&gt;&lt;/p&gt;
&lt;p&gt;Python violates &amp;quot;The Principle of Least Astonishment&amp;quot; when using a mutable default value as a function parameter. Yeah,
it's a bold statement. But hear me out and then decide for yourself.&lt;/p&gt;
&lt;div class="section" id="principle-of-least-astonishment"&gt;
&lt;h2&gt;Principle of Least Astonishment&lt;/h2&gt;
&lt;p&gt;If you're not familiar with it, Wikipedia as a pretty good explanation about the
&lt;a class="reference external" href="https://en.wikipedia.org/wiki/Principle_of_least_astonishment"&gt;Principle of Least Astonishment&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;if a necessary feature has a high astonishment factor, it may be necessary to redesign the feature.&amp;quot; In general
engineering design contexts, the principle may be taken to mean that a component of a system should behave in a
manner consistent with how users of that component are likely to expect it to behave, i.e., users should not be
astonished at the way it behaves.&lt;/p&gt;
&lt;p&gt;... the principle aims to exploit users' pre-existing knowledge to minimize the learning curve, for instance by
designing interfaces that borrow heavily from &amp;quot;functionally similar or analogous programs with which your users are
likely to be familiar.&amp;quot; User expectations in this respect may be closely related to a particular computing platform
or tradition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="the-violation"&gt;
&lt;h2&gt;The Violation&lt;/h2&gt;
&lt;p&gt;In Python, when you write this code:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;it allocates an instance of &lt;tt class="docutils literal"&gt;list&lt;/tt&gt; and assigns it to the &lt;tt class="docutils literal"&gt;my_list&lt;/tt&gt; variable each time that line of code is
executed.&lt;/p&gt;
&lt;p&gt;Essentially, &lt;tt class="docutils literal"&gt;[]&lt;/tt&gt; is shorthand for &lt;tt class="docutils literal"&gt;list()&lt;/tt&gt; and anytime you see &lt;tt class="docutils literal"&gt;[]&lt;/tt&gt; in code, you would expect that a new
list object would be created. And it is perfectly fair to have such an expectation.&lt;/p&gt;
&lt;p&gt;But that's not the behavior when you use &lt;tt class="docutils literal"&gt;[]&lt;/tt&gt; as the default value for function parameter.&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;list_append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[]):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;So, if you wrote the following code to invoke &lt;tt class="docutils literal"&gt;list_append&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;first_name_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list_append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Vijay'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_name_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;last_name_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list_append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Varadan'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_name_list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;the output you'd see is:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
['Vijay']
['Vijay', 'Varadan']
&lt;/pre&gt;
&lt;p&gt;and not:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
['Vijay']
['Varadan']
&lt;/pre&gt;
&lt;p&gt;This result would definitely surprise me. I would expect to see 2 distinct lists with &lt;tt class="docutils literal"&gt;Vijay&lt;/tt&gt; in
&lt;tt class="docutils literal"&gt;first_name_list&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;Varadan&lt;/tt&gt; in &lt;tt class="docutils literal"&gt;last_name_list&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Note that the example I used would yield even more confusing results, when you invoke it initially with a pre-allocated
list instance, but subsequently with just one parameter.&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;first_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Jeff'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list_append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Vijay'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;first_names&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# output is ['Jeff', Vijay']&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;last_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list_append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Lu'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;list_append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Varadan'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last_names&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;# output is ['Lu', 'Varadan']&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;phone_numbers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;list_append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'+1-206-548-6565'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phone_numbers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# output is ['Lu', 'Varadan', '+1-206-548-6565']&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;As you can see, this would be very, very confusing; especially since the 2nd call to &lt;tt class="docutils literal"&gt;list_append&lt;/tt&gt; worked just fine
and created a new list when you didn't pass one in. The 3rd invocation doesn't create a new list and append it to the
new list; instead it simply appends it to the list that was created when the function was first invoked with one
parameter, using the default value for the second parameter.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="explanation-of-the-behavior"&gt;
&lt;h2&gt;Explanation of the Behavior&lt;/h2&gt;
&lt;p&gt;When you come across the code fragments above, you'd expect that Python would allocate a new instance of &lt;tt class="docutils literal"&gt;my_list&lt;/tt&gt;
each time you called the &lt;tt class="docutils literal"&gt;list_append&lt;/tt&gt; function with just one parameter. And your expectations would be dashed on
the rocks of Python's inconsistency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; Because Python only allocates a new list instance and assigns it to &lt;tt class="docutils literal"&gt;my_list&lt;/tt&gt; the &lt;strong&gt;first&lt;/strong&gt; time
&lt;tt class="docutils literal"&gt;list_append&lt;/tt&gt; is invoked. Subsequent invocations use the same &lt;tt class="docutils literal"&gt;my_list&lt;/tt&gt; instance that was allocated the first
time.&lt;/p&gt;
&lt;p&gt;This behavior is explained best by
&lt;a class="reference external" href="http://stackoverflow.com/questions/101268/hidden-features-of-python#comment3187590_113198"&gt;Jim Dennis' comment&lt;/a&gt;
for the answer about &amp;quot;mutable default arguments&amp;quot;, which I'll quote here:&lt;/p&gt;
&lt;blockquote&gt;
As the def statement is executed its arguments are evaluated by the interpreter. This creates (or rebinds) a name to
a code object (the suite of the function). However, the default arguments are instantiated as objects at the time of
definition. This is true of any time of defaulted object, but only significant (exposing visible semantics) when the
object is mutable. There's no way of re-binding that default argument name in the function's closure although it can
obviously be over-ridden for any call or the whole function can be re-defined)&lt;/blockquote&gt;
&lt;p&gt;To clarify further,
&lt;a class="reference external" href="http://stackoverflow.com/questions/101268/hidden-features-of-python#comment1557739_113198"&gt;using Robert Rossney's comment as reference&lt;/a&gt;,
&lt;strong&gt;default arguments to a function are stored in a tuple.&lt;/strong&gt; This tuple is an attribute of the function. Tuples are
immutable, so the mutable once allocated, cannot be allocated again. So, the same list instance is re-used in all
subsequent function invocations.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-fix"&gt;
&lt;h2&gt;The Fix&lt;/h2&gt;
&lt;p&gt;In order to get the right behavior, you would have to set the default value of &lt;tt class="docutils literal"&gt;my_list&lt;/tt&gt; to a sentinel value, check
for the sentinel value in body of the function and  if the check succeeded, allocate a new list and assign it to
&lt;tt class="docutils literal"&gt;my_list&lt;/tt&gt;. The code would look like this:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;list_append_fixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# note that you must explicitly compare against None and&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# can't check for &amp;quot;not my_list&amp;quot; in the if clause because the&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# &amp;quot;not my_list&amp;quot; check will evaluate to True when an empty list&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# is passed in, which does not equate to the sentinel check&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;my_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="some-thoughts"&gt;
&lt;h2&gt;Some Thoughts&lt;/h2&gt;
&lt;p&gt;The new code fragment defining &lt;tt class="docutils literal"&gt;list_append_fixed&lt;/tt&gt; feels unnatural.&lt;/p&gt;
&lt;p&gt;The behavior for allocation in case of default parameters for functions should be the same as for any other code that is
executed and should not appear as though it's special-cased for first time function execution versus subsequent
executions of the same function.&lt;/p&gt;
&lt;div class="section" id="additional-thoughts-rant"&gt;
&lt;h3&gt;Additional Thoughts (rant?)&lt;/h3&gt;
&lt;p&gt;There exists a Python idiom to check that a variable is not &lt;tt class="docutils literal"&gt;None&lt;/tt&gt;; see
&lt;a class="reference external" href="https://www.python.org/dev/peps/pep-0008/"&gt;PEP-8&lt;/a&gt; and yes, it applies to default parameter values. But when
checking collections (like lists or dictionaries), the recommended idiom, which covers both the &lt;tt class="docutils literal"&gt;None&lt;/tt&gt; value as
well as the empty collection cases, is:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;my_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# ...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The recommended idiom for checking a collection can't be used in this scenario. Why? Well, if an empty list is passed
in, the &lt;tt class="docutils literal"&gt;if not my_list&lt;/tt&gt; check would pass and a new list would be needlessly allocated. The only correct check is to
make an explicit check against &lt;tt class="docutils literal"&gt;None&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;It feels like Python mixed up its metaphors.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="other-references"&gt;
&lt;h2&gt;Other References&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://stackoverflow.com/questions/101268/hidden-features-of-python#113198"&gt;This answer&lt;/a&gt; to a Stack Overflow
question about &lt;a class="reference external" href="http://stackoverflow.com/questions/101268/hidden-features-of-python"&gt;&amp;quot;Hidden Features of Python&amp;quot;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;There's even an
&lt;a class="reference external" href="http://docs.quantifiedcode.com/python-code-patterns/correctness/mutable_default_value_as_argument.html"&gt;anti-pattern&lt;/a&gt;
for this exact behavior.&lt;/li&gt;
&lt;li&gt;This behavior seems to bite enough number of developers that it's part of the
&lt;a class="reference external" href="https://docs.python.org/3.5/faq/programming.html#why-are-default-values-shared-between-objects"&gt;Python programming FAQ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Technical"/><category term="programming"/><category term="python"/><category term="antiPattern"/></entry><entry><title>HOWTO: Develop a Prototyping Mindset</title><link href="https://vijay.varadan.com/talks/howto-develop-a-prototyping-mindset/" rel="alternate"/><published>2016-03-20T23:22:00-07:00</published><updated>2016-03-20T23:22:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2016-03-20:/talks/howto-develop-a-prototyping-mindset/</id><summary type="html">&lt;p class="first last"&gt;Lessons from prototyping games and other software while running my own company.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;A prototyping mindset is something that needs to be actively developed till it
becomes ingrained. Knowing and applying prototyping techniques is an important
part of the foundation, but that alone is not enough.  So, here are some
thoughts about how to develop a prototyping mindset.&lt;/p&gt;
&lt;p&gt;I'm an engineer by training. Having worked on core systems most of&amp;nbsp;my career, I
have a strong tendency to &lt;strong&gt;choose the &amp;quot;right&amp;quot; solution over&amp;nbsp;the &amp;quot;right now&amp;quot;
solution&lt;/strong&gt; almost every single time. This is a great trait for a software
architect to have, since by definition, the main goal of architecture is the
long term health of the systems&amp;nbsp;being built. So, the trade-off is to choose the
solution that is healthier for the long term rather than allow hacks in design
or code. In reality, shortcuts&amp;nbsp;are permitted, usually to respond to emergencies
or for business / competitive reasons. But these &lt;strong&gt;hacks&lt;/strong&gt; are recognized as
short term fixes which are &lt;strong&gt;scheduled for replacement&lt;/strong&gt; with more
appropriate&amp;nbsp;and viable long term solutions.&lt;/p&gt;
&lt;p&gt;&lt;img alt="pants hanger" src="https://vijay.varadan.com/talks/images/prototyping-pants-hanger-as-cookbook-holder.jpeg" /&gt;&lt;/p&gt;
&lt;p&gt;This worked out very well for me when I ran the architecture team at Hotwire in
one of my previous avatars, and there was naturally, a fair amount of tension
between choosing designs and solutions that met the needs of the business but
didn't damage&amp;nbsp;the health of the product in the long term. This &lt;strong&gt;push-pull&lt;/strong&gt;
or tension is a &lt;strong&gt;good thing&lt;/strong&gt; as long as the culture of the company is one
that respects that compromise is necessary&amp;nbsp;and understands that&amp;nbsp;concrete
mitigation must be put in place to replace&amp;nbsp;hacks / shortcuts in a timely
fashion. The engineering team at Hotwire was simply superb&amp;nbsp;at this. They had a
&amp;quot;maintenance queue&amp;quot; to which engineers were assigned on monthly rotation. The
architecture manager (me) owned this maintenance queue. It was my
responsibility to prioritize maintenance items and to devise a path to get
those fixes into production.&lt;/p&gt;
&lt;p&gt;The very trait of almost always picking&amp;nbsp;right solutions over &amp;quot;right now&amp;quot;
solutions proved&amp;nbsp;to be a major handicap when it came to running my own
technology shop, but I learned a very important lesson in the process: A
prototyping mindset is something that needs to be &lt;strong&gt;actively developed&lt;/strong&gt; till
it becomes &lt;strong&gt;ingrained&lt;/strong&gt;. Knowing and applying prototyping techniques is an
important part of the foundation, but that alone is not enough.&lt;/p&gt;
&lt;p&gt;So, here are some thoughts about how to develop a prototyping mindset.&lt;/p&gt;
&lt;div class="section" id="think-design-experiment"&gt;
&lt;h2&gt;Think: Design&amp;nbsp;Experiment&lt;/h2&gt;
&lt;p&gt;A prototype is a&amp;nbsp;design &lt;strong&gt;experiment&lt;/strong&gt;, which can broadly be classified based
on their intent as&amp;nbsp;functional (explore&amp;nbsp;an activity),&amp;nbsp;visual (appearance) and
user experience. Proof of concepts are slightly more complex design experiments
that typically explore two or all three of the above aspects, but the same
principles apply.&lt;/p&gt;
&lt;p&gt;Essentially, the goal is to learn something from the experiment, i.e. it
answers some question, which dovetails nicely into the next part.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="think-answer-one-specific-question"&gt;
&lt;h2&gt;Think: Answer One&amp;nbsp;Specific Question&lt;/h2&gt;
&lt;p&gt;Yes, &lt;strong&gt;only one&lt;/strong&gt; question; and it must be very specific. A question of
quantitative nature is easier to answer than a qualitative one. A qualitative
question would take some additional work post-creation of the prototype and is
subject to biases. An example of a specific question&amp;nbsp;in game development would
be: &amp;quot;Does changing the variability of player attack dice rolls from 2d6 to 3d4
increase or reduce boss battle times?&amp;quot; This question is very specific. To
answer the question, one parameter needs to be changed in the game, a number of
(automated) tests need to be run to measure the variance in boss battle time
and an analysis of the results needs to be performed.&lt;/p&gt;
&lt;p&gt;&lt;img alt="magnifying glass" src="https://vijay.varadan.com/talks/images/magnifying-glass-68207_640.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;It may seem a bit counter-intuitive initially, but if you find that yourself
seeking multiple answers from a single prototype, then you need to&amp;nbsp;&lt;strong&gt;break
down&lt;/strong&gt; the prototype into &lt;strong&gt;multiple phases&lt;/strong&gt; till each phase answers
exactly one specific question.&amp;nbsp;Answer the question in each phase and then
combine the information to answer the larger question. You may need to
introduce additional phases to accommodate for effect of multiple changes on
one another, but that does not alter the fundamental premise of answering one
specific question at a time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="think-cheap-and-fast"&gt;
&lt;h2&gt;Think: Cheap &lt;em&gt;and&lt;/em&gt; Fast&lt;/h2&gt;
&lt;p&gt;Prototyping needs to be cheap and fast. Not just cheap or fast, but both. You
have to pick the &lt;strong&gt;right tools&lt;/strong&gt; for the job and you must &lt;strong&gt;limit the
scope&lt;/strong&gt; of what you are prototyping. The way that I was able to get a handle
on this aspect was to ask, &amp;quot;What question does this prototype answer?&amp;quot; This is
a very different question from &amp;quot;What problem does the prototype solve?&amp;quot;, which
is the&amp;nbsp;absolutely wrong question to ask. &lt;strong&gt;Prototypes don't solve problems.&lt;/strong&gt;
They answer questions about viability of a proposed solution.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="think-tactics-not-strategy"&gt;
&lt;h2&gt;Think: Tactics, not Strategy&lt;/h2&gt;
&lt;p&gt;Strategy is about doing the right thing. Tactics are about doing things
correctly. Strategy is future oriented. Tactics are in the here and now. The
strategy portion &lt;strong&gt;was&lt;/strong&gt;&amp;nbsp;(note: past tense) making the decision to create
prototypes. The tactical portion is&amp;nbsp;the &lt;strong&gt;correct utilization&lt;/strong&gt; of the
appropriate&amp;nbsp;resources (tools, people, time, etc) to validate hypotheses.
Strategy is over-arching and&amp;nbsp;long term. Tactics are scope-limited and&amp;nbsp;&lt;strong&gt;short
term&lt;/strong&gt;. Strategy produces&amp;nbsp;goals, road maps and measurements to ensure that
things stay on course. Tactics, in our case, quickly and efficiently
&lt;strong&gt;validate hypotheses&lt;/strong&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="think-good-enough-not-perfect"&gt;
&lt;h2&gt;Think: Good Enough, not Perfect&lt;/h2&gt;
&lt;p&gt;Prototypes are &lt;strong&gt;not the final product&lt;/strong&gt;. They exist to validate (or
invalidate) a solution you've come up with. They need to be good enough for
that purpose. Do not waste time in spit and polish.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="think-temporary-not-permanent"&gt;
&lt;h2&gt;Think: Temporary, not Permanent&lt;/h2&gt;
&lt;p&gt;Prototypes are &lt;strong&gt;throwaway work&lt;/strong&gt;. Once their purpose is fulfilled, they will
probably never be seen / used again. So, limit the resources (time, money,
effort) you put into them to what is needed to fulfill the goal of the
prototype. No more, no less. Do not make the classic mistake of building your
product on&amp;nbsp;your prototype -- this is a well-trodden path to failure. You will
most likely spend more time on the prototype thinking you can re-use parts of
it for production and later find that the halfhearted compromises you made
hobble the final product.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="think-risk-reduction"&gt;
&lt;h2&gt;Think: Risk&amp;nbsp;Reduction&lt;/h2&gt;
&lt;p&gt;Prototypes reduce the risk of working on some feature or idea for an extended
period of time, expending large sums of money, putting in a lot of effort, only
to find out that it fails to meet targets and expectations. Have a clear goal
for what you expect to get out of the prototype. What risk does it mitigate?
What unknown dark corner does it shine a light on?&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="think-use-what-i-know-and-have"&gt;
&lt;h2&gt;Think: Use What I&amp;nbsp;Know and Have&lt;/h2&gt;
&lt;p&gt;Try to use existing skills, tools, knowledge and other resources you have at
your disposal. &lt;strong&gt;Do not conflate&lt;/strong&gt; prototyping with learning a new skill or
tool. It is best to spend whatever time is needed to acquire the skill, be it a
new piece of software, a programming / scripting language&amp;nbsp;or&amp;nbsp;a project
management methodology such as Scrum&amp;nbsp;&lt;strong&gt;before&lt;/strong&gt; you begin work on a
prototype.&lt;/p&gt;
&lt;p&gt;There's no such thing as the perfect way to prototype. There are ways that work
and ways that don't.&lt;/p&gt;
&lt;p&gt;As an example, I was told by developers at one company I worked at that Java
was way faster for prototyping and iterating than C++. I proved them wrong
multiple times, simply because I was considerably more familiar with C++ than I
was (or they were) with Java.&amp;nbsp;On that note, I've come to prefer
&lt;a class="reference external" href="http://python.org"&gt;Python&lt;/a&gt; (batteries included) for prototyping over these last
few years. It was a skill I picked up explicitly for speeding up the iterative
cycles when&amp;nbsp;prototyping games. I also use it for production code these days as
do companies like Google and Dropbox.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="think-i-will-be-wrong-mostly"&gt;
&lt;h2&gt;Think:&amp;nbsp;I will be Wrong, Mostly&lt;/h2&gt;
&lt;p&gt;Any&amp;nbsp;reasonably intelligent person already knows that s/he will be wrong more
than right in unfamiliar situations. Prototyping is all about &lt;strong&gt;the world of
the unknown and unfamiliar&lt;/strong&gt;. So, don't forget this. It's perfectly fine to
have your ideas and theories disproved many times over. Ultimately, you'll find
one that is proven right. That's all you need. The cost of&amp;nbsp;learning by doing
via prototypes is orders of magnitude faster and cheaper than guessing wrong.
You don't want to&amp;nbsp;stare failure in the face after the fact.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="think-idea-validation-not-problem-solving"&gt;
&lt;h2&gt;Think: Idea&amp;nbsp;Validation, not Problem Solving&lt;/h2&gt;
&lt;p&gt;Prototypes validate (or invalidate) ideas and theories. They don't solve
problems. That's up to you. If done right, you already have a slew of potential
solutions to the problem at hand. You build prototypes to quickly&amp;nbsp;&lt;strong&gt;try out
those solutions&lt;/strong&gt; to determine which one(s), if any, actually will work for
you in the real world.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="think-practice-in-private-perform-in-public"&gt;
&lt;h2&gt;Think: Practice in Private, Perform in Public&lt;/h2&gt;
&lt;p&gt;A few years ago, I started to learn how to play the saxophone. The early months
are best described in this tweet:&lt;/p&gt;
&lt;p&gt;&lt;img alt="my sax abilities" src="https://vijay.varadan.com/talks/images/my-sax-abilities-etymology-of-blows.png" /&gt;&lt;/p&gt;
&lt;p&gt;Essentially, when you're start learning to play a musical instrument, no one,
even your own mother, wants to hear you practice. So, you're free to make all
sorts of mistakes and sound as off-key and abysmal as you please. Prototyping
is a bit like that. A lot of your prototypes will simply not work. You won't
put them on display for&amp;nbsp;the world even to seek feedback. You'll mostly likely
destroy them. And that's just part of the process.&lt;/p&gt;
&lt;p&gt;After practicing your musical skill for some time, you will&amp;nbsp;try to show off you
newfangled abilities. Showing off your prototype is a bit like that. Reception
to it could vary wildly. But the feedback you get will be invaluable in making
changes which in turn will lead to improvements in your final product.&lt;/p&gt;
&lt;p&gt;Your &lt;strong&gt;final product&lt;/strong&gt; is the equivalent of a &lt;strong&gt;public performance&lt;/strong&gt; - you
want it to be stellar. Your prototypes are all those private practice sessions
and&amp;nbsp;rehearsals with your close friends and family - &lt;strong&gt;prototyping __is__&amp;nbsp;the
journey&lt;/strong&gt;, brickbats and bouquets included, of making your product successful.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="think-feedback-not-criticism"&gt;
&lt;h2&gt;Think: Feedback, not Criticism&lt;/h2&gt;
&lt;p&gt;You've figured out the purpose of your prototype, judiciously allocated
resources and built your prototype. Some types of prototypes require you to
show them to other people and solicit their opinions. It's important that you
have the right attitude when you get feedback. Not all of it will be positive,
nor should you expect it to be. When you do get positive feedback, accept it,
&lt;strong&gt;analyze it&lt;/strong&gt; and take it for what it's worth. When you get negative
feedback, do the same thing. Set aside&amp;nbsp;criticism that is not constructive, but
do pay attention&amp;nbsp;that which is constructive. Practice goes a long way in
&lt;strong&gt;filtering noise from signal&lt;/strong&gt; when you're hit with a barrage of opinions
opposing your own or what you expect. It might help to keep in mind that it's
not always easy to give negative feedback. Most people know it tends to usually
be discarded and you might want to try and appreciate the effort taken by
people who give your their honest opinion.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Technical"/><category term="engineering"/><category term="prototyping"/><category term="softwareEngineering"/></entry><entry><title>C++ Standard Library Gotcha: Include Headers Explicitly</title><link href="https://vijay.varadan.com/talks/cpp-standard-library-gotcha-include-headers-explicitly/" rel="alternate"/><published>2016-01-24T08:47:00-08:00</published><updated>2016-01-24T08:47:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2016-01-24:/talks/cpp-standard-library-gotcha-include-headers-explicitly/</id><summary type="html">&lt;p class="first last"&gt;Compiler errors aren't all that informative even in 2016. Case in point.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="tcpppl" src="https://vijay.varadan.com/talks/images/tcpppl.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;I was&amp;nbsp;using the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;boost::log&lt;/span&gt;&lt;/tt&gt; library component and when compiling my code, I ran into a rather odd error converting a derived shared pointer to a base class shared pointer, i.e.&amp;nbsp;implicitly converting a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;shared_ptr&amp;lt;std::ofstream&amp;gt;&lt;/span&gt;&lt;/tt&gt;&amp;nbsp;to a &lt;tt class="docutils literal"&gt;const &lt;span class="pre"&gt;shared_ptr&amp;lt;std::ostream&amp;gt;&lt;/span&gt; &amp;amp;&lt;/tt&gt;. Here's the code snippet, with the line causing the compiler error highlighed. Note that code has been simplified for clarity.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;boost&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sinks&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;asynchoronous_sink&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sinks&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;text_ostream_backend&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TextSink&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;logFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;didSucceed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;boost&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;TextSink&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lfstream&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;boost&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;make_shared&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ofstream&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;locked_backend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;add_stream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lfstream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// &amp;lt;-- COMPILER ERROR HERE&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;add_sink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;BOOST_LOG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lgr_gtl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;LogSystem initialized...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;didSucceed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;LogSystem::Initialize() failed.&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Details:&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;what&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;didSucceed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The compiler, Visual Studio 2015 Update 1, spat out the error pointing to the line above marked with the comment &lt;tt class="docutils literal"&gt;COMPILER ERROR HERE&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
error C2664: 'void boost::log::v2s_mt_nt6::sinks::basic_text_ostream_backend&amp;lt;char&amp;gt;::add_stream(const boost::shared_ptr&amp;lt;std::basic_ostream&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;&amp;gt;&amp;gt; &amp;amp;)': cannot convert argument 1 from 'boost::shared_ptr&amp;lt;T&amp;gt;' to 'const boost::shared_ptr&amp;lt;std::basic_ostream&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;&amp;gt;&amp;gt; &amp;amp;'
    with
    [
        T=std::ofstream
    ]
note: Reason: cannot convert from 'boost::shared_ptr&amp;lt;T&amp;gt;' to 'const boost::shared_ptr&amp;lt;std::basic_ostream&amp;lt;char,std::char_traits&amp;lt;char&amp;gt;&amp;gt;&amp;gt;'
    with
    [
        T=std::ofstream
    ]
note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
&lt;/pre&gt;
&lt;p&gt;I was flummoxed. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::ofstream&lt;/span&gt;&lt;/tt&gt; is a typedef for &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::basic_ofstream&lt;/span&gt;&lt;/tt&gt;, which is a class derived from &lt;tt class="docutils literal"&gt;basic_ostream&lt;/tt&gt;. So, there should be no reason why the error should be thrown. The conversion from non-const to const shouldn't be an issue either, though it's a red herring and would cause most folks to look at that first and maybe add a const qualifier. Adding the const qualifier won't make a jot of difference.&lt;/p&gt;
&lt;p&gt;I looked up the definition of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::ofstream&lt;/span&gt;&lt;/tt&gt; and sure enough, it looked like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;basic_ofstream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;char_traits&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ofstream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and a little further up in the same file is a forward declaration for basic_ofstream, which looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_Elem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_Traits&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;char_traits&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_Elem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;basic_ofstream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The one odd thing was that Intellisense found this in the &lt;tt class="docutils literal"&gt;iosfwd&lt;/tt&gt; header file and was a &lt;em&gt;forward declaration&lt;/em&gt;. But I wanted the &lt;em&gt;definition&lt;/em&gt;, which Intellisense stubbornly refused to show me. So, I tried finding all references which only yielded the earlier mentioned ofstream definition basic_ostream forward declaration. Even more odd.&lt;/p&gt;
&lt;p&gt;The standard says &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::ofstream&lt;/span&gt;&lt;/tt&gt; is defined in the &lt;tt class="docutils literal"&gt;fstream&lt;/tt&gt; header. So, I cracked that open to find the definition of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;std::basic_ofstream&lt;/span&gt;&lt;/tt&gt;, which was just as I had expected:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_Elem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_Traits&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;basic_ofstream&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;basic_ostream&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;_Elem&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_Traits&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// output stream associated with a C stream&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, I didn't &lt;tt class="docutils literal"&gt;#include &amp;lt;iosfwd&amp;gt;&lt;/tt&gt; explicitly anywhere. It was getting included by one of the standard C++ headers or one of the boost headers. MSDN says, of iosfwd:&lt;/p&gt;
&lt;blockquote&gt;
&lt;em&gt;Declares forward references to several template classes used throughout iostreams. All such template classes are defined in other standard headers. You include this header explicitly only when you need one of its declarations, but not its definition.&lt;/em&gt;&lt;/blockquote&gt;
&lt;p&gt;I figured, more along the lines of &amp;quot;Let me throw this at the wall and see if it sticks.&amp;quot;, that I should include the fstream header explicitly.&amp;nbsp;In hindsight, seeing that Intellisense could only show me the forward declaration, it should've been the first thing to try.&lt;/p&gt;
&lt;p&gt;So, I explicitly added a &lt;tt class="docutils literal"&gt;#include &amp;lt;fstream&amp;gt;&lt;/tt&gt; to my code. Voilà! The error disappeared and the code compiled just fine.&lt;/p&gt;
&lt;p&gt;It's a tad irritating (Who am I kidding? It's outright frustrating.) when the compiler throws out an error like the one above, but the definitions and declarations seem to be present - yeah, in this case a forward declaration only, but I would expect the compiler to complain that it didn't have enough information (in this case the &lt;em&gt;definition&lt;/em&gt;) to determine whether &lt;tt class="docutils literal"&gt;ofstream&lt;/tt&gt; / &lt;tt class="docutils literal"&gt;basic_ofstream&lt;/tt&gt; was derived from &lt;tt class="docutils literal"&gt;basic_ostream&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Lesson learned: Explicitly include headers that contain&amp;nbsp;the definitions, do not rely on indirect inclusions.&lt;/p&gt;
</content><category term="Technical"/><category term="programming"/><category term="cpp"/><category term="cppStandardLibrary"/><category term="VisualStudio"/></entry><entry><title>PowerShell HOWTO: Pass Command Line Arguments From One Script to Another</title><link href="https://vijay.varadan.com/talks/powershell-howto-pass-command-line-arguments-from-one-script-to-another/" rel="alternate"/><published>2016-01-22T20:10:00-08:00</published><updated>2016-01-22T20:10:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2016-01-22:/talks/powershell-howto-pass-command-line-arguments-from-one-script-to-another/</id><summary type="html">&lt;p class="first last"&gt;It's a bit harder than the baton hand-off in a relay race.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="PowerShellLogo" src="https://vijay.varadan.com/talks/images/PowerShell_5.0_icon.png" /&gt;&lt;/p&gt;
&lt;p&gt;I encountered another&amp;nbsp;PowerShell quirk when
porting my build environment scripts. This one had to do with passing
command-line arguments from one script to another. Essentially, I would
arguments when invoking&amp;nbsp;&lt;strong&gt;``script1.ps1``&lt;/strong&gt;, which do some processing
and would pass those same arguments to &lt;strong&gt;``script2.ps1``&lt;/strong&gt;. But
&lt;strong&gt;``script2.ps1``&lt;/strong&gt; wasn't getting the arguments as one might expect. It
took some jumping through hoops to figure it out.&lt;/p&gt;
&lt;div class="section" id="scenario"&gt;
&lt;h2&gt;Scenario&lt;/h2&gt;
&lt;p&gt;I have to invoke different sets of scripts conditionally for setting up the build environment based on which project(s) I want to build. This is related to porting my build environment scripts from bash to Powershell.&lt;/p&gt;
&lt;p&gt;Let's say, &lt;tt class="docutils literal"&gt;push0.ps1&lt;/tt&gt; is the main script and there are three other&amp;nbsp;scripts, viz.&amp;nbsp;&lt;tt class="docutils literal"&gt;quake.push0.ps1&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;doom.push0.ps1&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;wolf.push0.ps1&lt;/tt&gt;. I want to invoke &lt;tt class="docutils literal"&gt;push0.ps1&lt;/tt&gt; with some arguments from the command line and have &lt;tt class="docutils literal"&gt;push0.ps1&lt;/tt&gt; invoke one of the &lt;tt class="docutils literal"&gt;*.push0.ps1&lt;/tt&gt; scripts while passing all the command line arguments that &lt;tt class="docutils literal"&gt;push0.ps1&lt;/tt&gt; was invoked with.&lt;/p&gt;
&lt;p&gt;A bit of code would help make the example concrete: &lt;tt class="docutils literal"&gt;push0.ps1&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;# $args is the array of input arguments to any script&lt;/span&gt;
&lt;span class="c"&gt;# Do some work here common to all projects&lt;/span&gt;
&lt;span class="c"&gt;# like pushing code to the master repo for developer scripts, etc.&lt;/span&gt;

&lt;span class="c"&gt;# invoke project specific scripts here&lt;/span&gt;
&lt;span class="c"&gt;# $Env:Project will be set to quake, doom or wolf&lt;/span&gt;
&lt;span class="c"&gt;# call project specific push0 script if it exists&lt;/span&gt;
&lt;span class="c"&gt;# and pass all arguments to it&lt;/span&gt;
&lt;span class="nv"&gt;$scriptName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$Env:Project&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;.push0.ps1&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Test-Path&lt;/span&gt; &lt;span class="nv"&gt;$scriptName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$scriptName&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;quake.push0.ps1&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;# do quake specific work here&lt;/span&gt;
&lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:QuakeBaseDir&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;win32&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$pushFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="nv"&gt;$winSpecificFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="nv"&gt;$Env:QuakeWinSubDir&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$winSpecificFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="c"&gt;# now push any external sub-repos&lt;/span&gt;
&lt;span class="nv"&gt;$quakeExtBaseDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:ExtBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$QuakeExtWin32SubDir&lt;/span&gt;
&lt;span class="nv"&gt;$args&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$extFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$quakeExtBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;
    &lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$extFolder&lt;/span&gt;
    &lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;doom.push0.ps1&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;# do doom specific work here&lt;/span&gt;
&lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:DoomBaseDir&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;win16&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$pushFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="nv"&gt;$win16SpecificFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="nv"&gt;$Env:DoomWin16SubDir&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$win16SpecificFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="c"&gt;# now push assembly language library repos&lt;/span&gt;
&lt;span class="nv"&gt;$doomAsmBaseDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:AsmLibBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$doomAsmSubDir&lt;/span&gt;
&lt;span class="nv"&gt;$args&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$asmFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$doomAsmBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;
    &lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$asmFolder&lt;/span&gt;
    &lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wolf.push0.ps1&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;# do wolf specific work here&lt;/span&gt;
&lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:WolfBaseDir&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;dos&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$pushFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="nv"&gt;$dosSpecificFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="nv"&gt;$env:WolfDosSubDir&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$dosSpecificFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="c"&gt;# now push dos assembly language library repos&lt;/span&gt;
&lt;span class="nv"&gt;$wolfAsmBaseDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:AsmLibBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$wolfAsmSubDir&lt;/span&gt;
&lt;span class="nv"&gt;$args&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$asmFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$wolfAsmBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;
    &lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$asmFolder&lt;/span&gt;
    &lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;As you can see from the example above, the three project specific scripts push different sub-repos that are passed in as parameters.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="problem"&gt;
&lt;h2&gt;Problem&lt;/h2&gt;
&lt;p&gt;The three project specific scripts &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;{quake|doom|wolf}.push0.ps1&lt;/span&gt;&lt;/tt&gt;, work fine as they are now, if they are individually invoked from Powershell. But if they are &amp;nbsp;invoked from another Powershell script, then&amp;nbsp;they fail processing the arguments passed in via &lt;tt class="docutils literal"&gt;$args&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;The issue is that when &lt;tt class="docutils literal"&gt;$args&lt;/tt&gt; is passed to &lt;tt class="docutils literal"&gt;push0.ps1&lt;/tt&gt;, it's an array of parameters, but when you invoke another script from within &lt;tt class="docutils literal"&gt;push0.ps1&lt;/tt&gt;, the &lt;tt class="docutils literal"&gt;$args&lt;/tt&gt; array (i.e. all the parameters) is treated as a single parameter passed to the callee script. If I add a line to print out the arguments in &lt;tt class="docutils literal"&gt;quake.push0.ps1&lt;/tt&gt; like this:&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;quake.push0.ps1&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Quake:- args[=&amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;]: &amp;quot;&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And invoke &lt;tt class="docutils literal"&gt;push0.ps1&lt;/tt&gt; passing in some arguments, then the output looks like this:&lt;/p&gt;
&lt;pre&gt;    $&amp;gt; .\push0.ps1 boost libssl lua
    Quake:- args[=&lt;span style="color: #ff0000;"&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/span&gt;]: boost libssl lua&lt;/pre&gt;&lt;p&gt;As you can see, even though all 3 parameters are passed in, they are seen as &lt;em&gt;a single parameter&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Essentially it would appear, that when the callee script is invoked, all 3 parameters as passed in as &lt;tt class="docutils literal"&gt;$args[0]&lt;/tt&gt;. Now, Powershell is an object scripting language and it seems to pass an &lt;strong&gt;array of strings&lt;/strong&gt; from the caller script as the first and only parameter to the callee script.&lt;/p&gt;
&lt;p&gt;Knowing that since Powershell is built on top of .NET and deals with objects, we can verify this by checking the type of &lt;tt class="docutils literal"&gt;$args[0]&lt;/tt&gt; like this:&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;quake.push0.ps1&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nb"&gt;Write-Host&lt;/span&gt; &lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;IsArray&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;Output&lt;/tt&gt;&lt;/p&gt;
&lt;span style="color: #0000ff;"&gt;&lt;pre&gt;    True&lt;/pre&gt;&lt;/span&gt;&lt;/pre&gt;&lt;p&gt;And we're in business! :-)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="solution"&gt;
&lt;h2&gt;Solution&lt;/h2&gt;
&lt;p&gt;There are 2 solutions. The first uses PowerShell splatting, available as of PowerShell V2, but not easily found unless you use the term &lt;tt class="docutils literal"&gt;splatting&lt;/tt&gt; in your search. The second involves manual expansion, which I prefer even though it involves more changes. The second method can also be used on the command line when piping the output of native programs. Programs output raw strings rather than string arrays, since they don't care about the shell they're being invoked from.&lt;/p&gt;
&lt;div class="section" id="solution-1-using-splatting"&gt;
&lt;h3&gt;Solution 1: Using Splatting&lt;/h3&gt;
&lt;p&gt;Simply invoke the callees by prefixing the args array with an &amp;#64; sign rather than the $ sign, like this (see comment marked as &lt;tt class="docutils literal"&gt;CHANGE:&lt;/tt&gt;):&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;push0.ps1&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c"&gt;# $args is the array of input arguments to any script&lt;/span&gt;
&lt;span class="c"&gt;# Do some work here common to all projects&lt;/span&gt;
&lt;span class="c"&gt;# like pushing code to the master repo for developer scripts, etc.&lt;/span&gt;

&lt;span class="c"&gt;# invoke project specific scripts here&lt;/span&gt;
&lt;span class="c"&gt;# $Env:Project will be set to quake, doom or wolf&lt;/span&gt;
&lt;span class="c"&gt;# call project specific push0 script if it exists&lt;/span&gt;
&lt;span class="c"&gt;# and pass all arguments to it&lt;/span&gt;
&lt;span class="nv"&gt;$scriptName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$Env:Project&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;.push0.ps1&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Test-Path&lt;/span&gt; &lt;span class="nv"&gt;$scriptName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$scriptName&lt;/span&gt; &lt;span class="nv"&gt;@args&lt;/span&gt; &lt;span class="c"&gt;# CHANGE: use @args instead of $args&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;quake.push0.ps1&lt;/tt&gt; - no change&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;doom.push0.ps1&lt;/tt&gt; - no change&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wolf.push0.ps1&lt;/tt&gt; - no change&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="solution-2-manual-expansion"&gt;
&lt;h3&gt;Solution 2: Manual Expansion&lt;/h3&gt;
&lt;p&gt;What we need to do in the callees, is check if the incoming $args has only 1 parameter and if it's an array. If so, then simply use &lt;tt class="docutils literal"&gt;$args[0]&lt;/tt&gt; as the actual list of arguments and process it below.&lt;/p&gt;
&lt;p&gt;Since this bit of the code is common to multiple scripts, I put it in a function and stick it in the $PROFILE file or some other file that can be dot-sourced. Here's the function:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;UnwrapArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$unwrapped&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$params&lt;/span&gt; &lt;span class="o"&gt;-and&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="o"&gt;-eq&lt;/span&gt; &lt;span class="n"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-and&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;IsArray&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$unwrapped&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$unwrapped&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We make 0 (zero) changes in the caller and only 2 changes per callee. At the top of each callee file, we call &lt;tt class="docutils literal"&gt;UnwrapArguments&lt;/tt&gt; and store it in &lt;tt class="docutils literal"&gt;$myargs&lt;/tt&gt; (marked with comment: &lt;tt class="docutils literal"&gt;CHANGE #1&lt;/tt&gt;) and further down in the script, we use &lt;tt class="docutils literal"&gt;$myargs&lt;/tt&gt; instead of &lt;tt class="docutils literal"&gt;$args&lt;/tt&gt; (marked with comment: &lt;tt class="docutils literal"&gt;CHANGE #2&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;So our scripts end up looking like this:&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;push0.ps1&lt;/tt&gt; - no changes.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;quake.push0.ps1&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;$myargs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UnwrapArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# CHANGE #1&lt;/span&gt;

&lt;span class="c"&gt;# do quake specific work here&lt;/span&gt;
&lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:QuakeBaseDir&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;win32&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$pushFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="nv"&gt;$winSpecificFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="nv"&gt;$Env:QuakeWinSubDir&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$winSpecificFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="c"&gt;# now push any external sub-repos&lt;/span&gt;
&lt;span class="nv"&gt;$quakeExtBaseDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:ExtBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$QuakeExtWin32SubDir&lt;/span&gt;
&lt;span class="nv"&gt;$myargs&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;# CHANGE #2, we use the unwrapped $myargs instead of $args&lt;/span&gt;
    &lt;span class="nv"&gt;$extFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$quakeExtBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;
    &lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$extFolder&lt;/span&gt;
    &lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;doom.push0.ps1&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;$myargs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UnwrapArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# CHANGE #1&lt;/span&gt;

&lt;span class="c"&gt;# do doom specific work here&lt;/span&gt;
&lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:DoomBaseDir&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;win16&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$pushFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="nv"&gt;$win16SpecificFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="nv"&gt;$Env:DoomWin16SubDir&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$win16SpecificFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="c"&gt;# now push assembly language library repos&lt;/span&gt;
&lt;span class="nv"&gt;$doomAsmBaseDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:AsmLibBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$doomAsmSubDir&lt;/span&gt;
&lt;span class="nv"&gt;$myargs&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;# CHANGE #2, we use the unwrapped $myargs instead of $args&lt;/span&gt;
    &lt;span class="nv"&gt;$asmFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$doomAsmBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;
    &lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$asmFolder&lt;/span&gt;
    &lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wolf.push0.ps1&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nv"&gt;$myargs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UnwrapArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;# CHANGE #1&lt;/span&gt;

&lt;span class="c"&gt;# do wolf specific work here&lt;/span&gt;
&lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:WolfBaseDir&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;dos&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$pushFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="nv"&gt;$dosSpecificFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$pushFolder&lt;/span&gt; &lt;span class="nv"&gt;$env:WolfDosSubDir&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$dosSpecificFolder&lt;/span&gt;
&lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;

&lt;span class="c"&gt;# now push dos assembly language library repos&lt;/span&gt;
&lt;span class="nv"&gt;$wolfAsmBaseDir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$Env:AsmLibBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$wolfAsmSubDir&lt;/span&gt;
&lt;span class="nv"&gt;$myargs&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c"&gt;# CHANGE #2, we use the unwrapped $myargs instead of $args&lt;/span&gt;
    &lt;span class="nv"&gt;$asmFolder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Join-Path&lt;/span&gt; &lt;span class="nv"&gt;$wolfAsmBaseDir&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;
    &lt;span class="nb"&gt;cd &lt;/span&gt;&lt;span class="nv"&gt;$asmFolder&lt;/span&gt;
    &lt;span class="n"&gt;hg&lt;/span&gt; &lt;span class="n"&gt;push&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That's it. We're golden.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Technical"/><category term="programming"/><category term="PowerShell"/><category term="scripting"/></entry><entry><title>[SOLVED] Cocos Studio: 'Cocos Framework is not installed' Error</title><link href="https://vijay.varadan.com/talks/solved-cocos-studio-cocos-framework-is-not-installed-error/" rel="alternate"/><published>2016-01-16T14:45:00-08:00</published><updated>2016-01-16T14:45:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2016-01-16:/talks/solved-cocos-studio-cocos-framework-is-not-installed-error/</id><summary type="html">&lt;p class="first last"&gt;Tearing my hair out trying to get Cocos2dx to work.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="cocos2d-x" src="https://vijay.varadan.com/talks/images/cocos2d-x.jpg" /&gt;&lt;/p&gt;
&lt;div class="section" id="the-problem"&gt;
&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Install Cocos (without the framework) and cocos2d-x separately. Cocos2d-x works fine independently - I can create C++ (as well as Lua and JavaScript) projects just fine and build the C++ projects in Visual Studio 2015. Cocos Studio, unfortunately doesn't recognize that cocos2d-x is installed and won't let me create C++ projects that I can export and use in my game written in C++.&lt;/p&gt;
&lt;p&gt;In Cocos Studio, I get the error: &lt;span class="raw-html"&gt;&lt;span style="color: #800000"&gt;&lt;strong&gt;Cocos Framework is not installed&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt; The Preference menu item in the Edit menu looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="cocos-framework-is-not-installed" src="https://vijay.varadan.com/talks/images/cocos-framework-is-not-installed.png" /&gt;&lt;/p&gt;
&lt;p&gt;When I try to create a project and then add C++ as an option later, it looks like this (no engine is recognized and C++ radio option in the Project Language section is grayed out):&lt;/p&gt;
&lt;p&gt;&lt;img alt="cocos-studio-no-engine" src="https://vijay.varadan.com/talks/images/cocos-studio-no-engine.png" /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="easy-solution"&gt;
&lt;h2&gt;&lt;strong&gt;Easy Solution&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;On Windows (7 and 10), the &lt;a class="reference external" href="http://www.cocos2d-x.org/filedown/CocosForWinWithFramework-v2.3.3.exe"&gt;Cocos for Win with framework 2.3.3 installation&lt;/a&gt;&amp;nbsp;works right out of the box. So, if you want to get on with your gamedev life, just install that version and you'll be golden.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="tl-dr-version"&gt;
&lt;h2&gt;&lt;strong&gt;TL;DR&amp;nbsp;Version&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&amp;nbsp;I had troubles with earlier Cocos Studio versions (2.3.2.3, both with and without the framwork included) and jumped through a bunch of hoops with the non-framework installation package in order to try and get things working. Also, I realized that it's better to use the non-framework installation package and install multiple&amp;nbsp;framework versions separately, in order to be able to use them (side-by-side, if needed) with Cocos Studio. So, I'm documenting (a) what needs to be done to getting things working and (b) how I figured out what needed to be done.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="how-to-get-cocos-studio-to-recognize-cocos2d-x"&gt;
&lt;h2&gt;How to get Cocos Studio to Recognize cocos2d-x&lt;/h2&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Download and install &lt;a class="reference external" href="http://www.cocos2d-x.org/filedown/CocosForWin-v2.3.3.exe"&gt;Cocos&amp;nbsp;for Windows V2.3.3&lt;/a&gt; (the one without framework) to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;C:\Cocos&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Download and unzip &lt;a class="reference external" href="http://www.cocos2d-x.org/filedown/cocos2d-x-3.9.zip"&gt;cocos2d-x-3.9.zip&lt;/a&gt; to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;C:\Cocos\frameworks\cocos2d-x-3.9&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Download&amp;nbsp;&lt;a class="reference external" href="https://vijay.varadan.com/talks/files/cocos-framework.reg_.txt"&gt;this .REG file&lt;/a&gt;, change the name from &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cocos-framework.reg_.txt&lt;/span&gt;&lt;/tt&gt; to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cocos-framework.reg&lt;/span&gt;&lt;/tt&gt;&amp;nbsp;and run it. Alternately, you can manually create the following registry entries on Windows (64 bit):&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;HKLM\Software\Wow6432Node\CocosFramework\InstallDir&lt;/tt&gt; as a REG_SZ and set it to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;C:\Cocos&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;HKLM\Software\Wow6432Node\CocosFramework\3.9\EngineVersion&lt;/tt&gt; as a REG_SZ and set it to &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cocos2d-x-3.9&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;HKLM\Software\Wow6432Node\CocosFramework\3.9\Path&lt;/tt&gt; as a REG_SZ and set it to&amp;nbsp;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;C:\Cocos\frameworks\cocos2d-x-3.9&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Create&amp;nbsp;a file named &lt;tt class="docutils literal"&gt;version&lt;/tt&gt; with the contents &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cocos2d-x-3.9&lt;/span&gt;&lt;/tt&gt; in &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;C:\Cocos\frameworks\cocos2d-x-3.9&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;If you also want to do Android development, then Android SDK, Android NDK, Ant and JDK paths should be set in the Platform section of the Edit/Preferences&amp;nbsp;menu item, else skip this step.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ugly"&gt;
&lt;h2&gt;The Ugly&lt;/h2&gt;
&lt;p&gt;Note that none of this is documented anywhere on the cocos2d-x site or its forums. So, I'm posting this here and will include this information and a link to this post in my answer to &lt;a class="reference external" href="http://discuss.cocos2d-x.org/t/cocos-studio-cocos-framework-is-not-installed/26339"&gt;my own question&lt;/a&gt; in the cocos2d-x forum.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="how-i-figured-it-out"&gt;
&lt;h2&gt;How I Figured it out&lt;/h2&gt;
&lt;p&gt;I used 2 computers to sort this out. I removed all previous Cocos package installations completely from both - this includes both the Cocos Studio and the cocos2d-x framework.&lt;/p&gt;
&lt;p&gt;On my first computer (Windows 7), I installed Cocos Studio without the framework and extracted the framework to the appropriate sub-directory. Cocos Studio did not recognize that the framework was installed. I tried various suggestions that were provided in answers to identical questions in the forums. These included:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;editing the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;C:\Cocos\Cocos\CocosStudio2\Frameworks\FrameworkVersionList.xml&lt;/span&gt;&lt;/tt&gt; to ensure that the framework version I was using was listed there. It was already there. Note that this file doesn't even exist in the installation package that works out of the box. Total red herring.&lt;/li&gt;
&lt;li&gt;editing the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;C:\Cocos\frameworks\cocos2d-x-3.9\tools\console\bin\cocos2d.ini&lt;/span&gt;&lt;/tt&gt; file to correctly point to the cocos2d-x installation and the templates folders. They weren't, but fixing them made no difference.&lt;/li&gt;
&lt;li&gt;removing some and then all&amp;nbsp;cocos environment variables. This made no difference.&lt;/li&gt;
&lt;li&gt;adding a &lt;tt class="docutils literal"&gt;version&lt;/tt&gt; file with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;cocos2d-x-3.9&lt;/span&gt;&lt;/tt&gt; in the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;C:\Cocos\frameworks\cocos2d-x-3.9&lt;/span&gt;&lt;/tt&gt; directory. This is&amp;nbsp;a necessary step, but it didn't work by itself.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I then installed the &lt;a class="reference external" href="http://www.cocos2d-x.org/filedown/CocosForWinWithFramework-v2.3.3.exe"&gt;Cocos for Windows with framework v2.3.3&lt;/a&gt; on my second computer (Windows 10). Then I proceeded to compare the directory layout and files and their differences. Other than the &lt;tt class="docutils literal"&gt;version&lt;/tt&gt; file, I didn't find anything significant.&lt;/p&gt;
&lt;p&gt;I figured as a last, desperate (since Cocos Studio is cross platform) step, I'd do a registry search on the (second) computer, the one that had package installed of Cocos Studio with the framework included. That yielded the three registry entries that were not present on the first computer. I added those entries to the first computer and Cocos Studio recognized that the cocos2d-x framework was installed.&lt;/p&gt;
&lt;p&gt;Last set of steps was to revert each of the changes I'd made one by one to determine which ones were actually needed and which ones were not. It turned out that the only change from the forum answers that was actually needed in addition to the registry change was the creation of the version file (#4 in the &amp;quot;How to get Cocos Studio to Recognize cocos2d-x&amp;quot; section above).&lt;/p&gt;
&lt;p&gt;Hope this helps anyone else looking to figure this out.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Technical"/><category term="programming"/><category term="gamedev"/><category term="Cocos2d"/><category term="Cocos2dx"/><category term="CocosStudio"/></entry><entry><title>PowerShell: Dot Sourcing Scripts Quirks</title><link href="https://vijay.varadan.com/talks/powershell-dot-sourcing-scripts-quirks/" rel="alternate"/><published>2016-01-05T08:17:00-08:00</published><updated>2016-01-05T08:17:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2016-01-05:/talks/powershell-dot-sourcing-scripts-quirks/</id><summary type="html">&lt;p class="first last"&gt;Solutions to some PowerShell quirks when dot sourcing scripts.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="PowerShellLogo" src="https://vijay.varadan.com/talks/images/PowerShell_5.0_icon.png" /&gt;&lt;/p&gt;
&lt;p&gt;PowerShell&amp;nbsp;has some&amp;nbsp;rather quirky and
inconsistent behavior when dot-sourcing scripts. I ran into it when
porting my scripts from bash.&lt;/p&gt;
&lt;p&gt;I spent the last couple of days of 2015 porting my &lt;a class="reference external" href="https://vijay.varadan.com/talks/organization-of-build-environment-scripts/"&gt;build environment scripts&lt;/a&gt;&amp;nbsp;(recommend that you read that article first) over to PowerShell. I ran into some rather quirky and inconsistent behavior when dot-sourcing scripts.&lt;/p&gt;
&lt;p&gt;I wanted to stick to the same organization and file layout that I had for the MSYS and Linux platforms. Essentially, something like this:&lt;/p&gt;
&lt;pre&gt;~vijay
    |-&lt;span style="color: #800000;"&gt;$PROFILE [1]&lt;/span&gt;
    |-work
      |-repos
        |-0
        |-1
          |-private
            |-bin
              |-&lt;span style="color: #0000ff;"&gt;devenv.ps1 [3]&lt;/span&gt;
            |-developer
              |-bin
              | |-&lt;span style="color: #800080;"&gt;devenv.ps1 [4]&lt;/span&gt;
              |-project1
                |-&lt;span style="color: #ff6600;"&gt;project1.ps1 [5]&lt;/span&gt;
            |-artist
              |-bin
              | |-devenv.ps1
              |-project1
                |-project1.ps1
            |-vijay
              |-bin
                |-&lt;span style="color: #008000;"&gt;devenv.ps1 [2]&lt;/span&gt;&lt;/pre&gt;&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;span class="raw-html"&gt;&lt;span style="color: #800000"&gt;$PROFILE [1]&lt;/span&gt;&lt;/span&gt; contains the Start-Dev() function&lt;/li&gt;
&lt;li&gt;&lt;span class="raw-html"&gt;&lt;span style="color: #008000"&gt;devenv.ps1 [2]&lt;/span&gt;&lt;/span&gt; user specific overrides go here&lt;/li&gt;
&lt;li&gt;&lt;span class="raw-html"&gt;&lt;span style="color: #0000ff"&gt;devenv.ps1 [3]&lt;/span&gt;&lt;/span&gt; common to all projects, users and roles, like build / install directories&lt;/li&gt;
&lt;li&gt;&lt;span class="raw-html"&gt;&lt;span style="color: #800080"&gt;devenv.ps1 [4]&lt;/span&gt;&lt;/span&gt; role specific settings go here&lt;/li&gt;
&lt;li&gt;&lt;span class="raw-html"&gt;&lt;span style="color: #ff6600"&gt;project1.ps1 [5]&lt;/span&gt;&lt;/span&gt; project and sub-project (if any) specific settings go here&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So, I started off with the 1:1 port attempt with necessary adjustments to naming conventions (camel case for variables, title case for functions, etc). So, the &lt;span class="raw-html"&gt;&lt;span style="color: #800000"&gt;user profile script [1]&lt;/span&gt;&lt;/span&gt; has a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Start-Dev()&lt;/span&gt;&lt;/tt&gt; function which is the equivalent of &lt;tt class="docutils literal"&gt;startdev()&lt;/tt&gt; in .bashrc. Just like it works for the MSYS platform, this function in turn dot-sources the user specific &lt;span class="raw-html"&gt;&lt;span style="color: #008000"&gt;devenv.ps1 [2]&lt;/span&gt;&lt;/span&gt;. &lt;span class="raw-html"&gt;&lt;span style="color: #008000"&gt;devenv.ps1 [2]&lt;/span&gt;&lt;/span&gt; dot-sources the common &lt;span class="raw-html"&gt;&lt;span style="color: #0000ff"&gt;devenv.ps1 [3]&lt;/span&gt;&lt;/span&gt; and the role specific (in this case, developer) &lt;span class="raw-html"&gt;&lt;span style="color: #800080"&gt;devenv.ps1 [4]&lt;/span&gt;&lt;/span&gt;, which dot-sources the project specific &lt;span class="raw-html"&gt;&lt;span style="color: #ff6600"&gt;project1.sh [5]&lt;/span&gt;&lt;/span&gt; for that role.&lt;/p&gt;
&lt;p&gt;I expected things would work fine, but they didn't. It was a tad difficult to debug initially, since the environment variables were getting set and I could see them when I invoked the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Start-Dev()&lt;/span&gt;&lt;/tt&gt; function, but functions and aliases that were setup in the dot-sourced PS1 files were missing from the PowerShell environment. The inconsistency flummoxed me for a bit. So, I threw in some Write-Host statements immediately following the lines where the functions and aliases were defined and they were fine. Similarly, they existed in the caller, cascading upwards all the way to the initial dot-sourcing that happens in the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Start-Dev()&lt;/span&gt;&lt;/tt&gt; function.&lt;/p&gt;
&lt;p&gt;First I tried replacing the dot-sourcing with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Invoke-Expression&lt;/span&gt;&lt;/tt&gt;, but as I expected based on the documentation, that didn't work either. The behavior was inconsistent - environment variables were set / updated correctly, but function and alias definitions just disappeared, poof! I tried PowerShell modules instead of scripts to see if that fixed the problem, but no dice. The solution I ended up with was to create a &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Start-Dev.ps1&lt;/span&gt;&lt;/tt&gt; script with the contents of the function dumped into the script's global space. I dot-sourced the script like this:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
PS C:\Users\vijay&amp;gt; . Start-Dev 1 project1
&lt;/pre&gt;
&lt;p&gt;That did the trick. All functions and aliases defined in the dot-sourced files became defined and available in the PowerShell environment. I wrapped up the porting work by adding an alias to simplify invocation of the Start-Dev.ps1 script.&lt;/p&gt;
</content><category term="Technical"/><category term="programming"/><category term="dotSourcing"/><category term="PowerShell"/><category term="scripting"/></entry><entry><title>Organization of Build Environment Scripts</title><link href="https://vijay.varadan.com/talks/organization-of-build-environment-scripts/" rel="alternate"/><published>2016-01-04T10:42:00-08:00</published><updated>2016-01-04T10:42:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2016-01-04:/talks/organization-of-build-environment-scripts/</id><summary type="html">&lt;p class="first last"&gt;Layout and invocation of python scripts to set up my Scons based build system.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="logo" src="https://vijay.varadan.com/talks/images/scons-logo-128px.png" /&gt;&lt;/p&gt;
&lt;p&gt;Consistent organization is important when building code that uses multiple external and internal libraries. It all starts with scripts that are used to setup the build environment. The scripts need to accommodate customization on per project, per role (developer, scripter, artist, etc), per user and perhaps ever per computer basis.&lt;/p&gt;
&lt;p&gt;I use &lt;a class="reference external" href="https://www.mercurial-scm.org/"&gt;mercurial&lt;/a&gt; for version control. There are multiple repositories, typically 1 per game or product. If a game or product is complex enough, it will warrant multiple repos. The layout of the &amp;quot;sub-repos&amp;quot; within a project is fixed and the developer needs to ensure adherence to the layout to get the project to build. The need for multiple repos within a single project stems from having teams with different needs and schedules working on various pieces. E.g. artists and animators work on assets on a different schedule and publish content to their own repo. Developers, QA and automated build &amp;amp; test systems can use placeholder assets initially and subsequently integrate the final assets when they are ready. This also provides the flexibility of using a different version control system for art and sound assets which is better suited to binary files e.g. &lt;a class="reference external" href="https://www.perforce.com/"&gt;Perforce&lt;/a&gt; rather than mercurial.&lt;/p&gt;
&lt;p&gt;Coming to the actual layout, it looks something like this on Linux and MSYS2:&lt;/p&gt;
&lt;pre&gt;~vijay
    |-&lt;span style="color: #800000;"&gt;.bashrc [1]&lt;/span&gt;
    |-work
      |-repos
        |-0
        |-1
          |-private
            |-bin
              |-&lt;span style="color: #0000ff;"&gt;devenv.sh [3]&lt;/span&gt;
            |-developer
              |-bin
              | |-&lt;span style="color: #800080;"&gt;devenv.sh [4]&lt;/span&gt;
              |-project1
                |-&lt;span style="color: #ff6600;"&gt;project1.sh [5]&lt;/span&gt;
            |-artist
              |-bin
              | |-devenv.sh
              |-project1
                |-project1.sh
            |-vijay
              |-bin
                |-&lt;span style="color: #008000;"&gt;devenv.sh [2]&lt;/span&gt;
&lt;/pre&gt;&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;span class="raw-html"&gt;&lt;span style="color: #800000"&gt;.bashrc [1]&lt;/span&gt;&lt;/span&gt; contains the startdev() function&lt;/li&gt;
&lt;li&gt;&lt;span class="raw-html"&gt;&lt;span style="color: #008000"&gt;devenv.sh [2]&lt;/span&gt;&lt;/span&gt; user specific overrides go here&lt;/li&gt;
&lt;li&gt;&lt;span class="raw-html"&gt;&lt;span style="color: #0000ff"&gt;devenv.sh [3]&lt;/span&gt;&lt;/span&gt; common to all projects, users and roles, like build / install directories&lt;/li&gt;
&lt;li&gt;&lt;span class="raw-html"&gt;&lt;span style="color: #800080"&gt;devenv.sh [4]&lt;/span&gt;&lt;/span&gt; role specific settings go here&lt;/li&gt;
&lt;li&gt;&lt;span class="raw-html"&gt;&lt;span style="color: #ff6600"&gt;project1.sh [5]&lt;/span&gt;&lt;/span&gt; project and sub-project (if any) specific settings go here&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The way a build environment for a project is setup is to invoke a function, say &lt;tt class="docutils literal"&gt;startdev()&lt;/tt&gt;, from &lt;span class="raw-html"&gt;&lt;span style="color: #800000"&gt;.bashrc [1]&lt;/span&gt;&lt;/span&gt;. This function ensures that the local repository instance (1, 2, etc) and project are&amp;nbsp;set. It then dot-sources the user's &lt;span class="raw-html"&gt;&lt;span style="color: #008000"&gt;devenv.sh [2]&lt;/span&gt;&lt;/span&gt; script which internally dot-sources the main &lt;span class="raw-html"&gt;&lt;span style="color: #0000ff"&gt;devenv.sh [3]&lt;/span&gt;&lt;/span&gt; script in private/bin and the role specific (in this case developer) &lt;span class="raw-html"&gt;&lt;span style="color: #800080"&gt;devenv.sh [4]&lt;/span&gt;&lt;/span&gt; script. The role specific &lt;span class="raw-html"&gt;&lt;span style="color: #800080"&gt;devenv.sh [4]&lt;/span&gt;&lt;/span&gt; dot-sources&amp;nbsp;the project specific script, &lt;span class="raw-html"&gt;&lt;span style="color: #ff6600"&gt;project1.sh [5]&lt;/span&gt;&lt;/span&gt;. At every stage, the sourcing script can override settings in the sourced script. This keeps the main line settings separated out from the overrides. Similarly,&amp;nbsp;role and project specific settings are separated out into their own files.&lt;/p&gt;
&lt;p&gt;There are a couple of things that are missing from this setup. The first is the lack of per machine overrides. These would be useful if, for example, a developer worked on 2 computers side-by-side or even virtual machines; one for debug builds and another for release builds or one for server code and one for client code. The second is that all projects have settings stored in sub-folders under each role; as you can see from the example above project1 has its&amp;nbsp;build environment scripts split up, under artist and developer folders.&lt;/p&gt;
&lt;p&gt;I've chosen not to address either of the issues at this time, because the per-machine overrides are easy to add when I'll&amp;nbsp;actually need that feature in the future - it's only at that time I'll know the real requirements. Essentially, &lt;a class="reference external" href="https://en.wikipedia.org/wiki/You_aren't_gonna_need_it"&gt;YAGNI&lt;/a&gt;. As for the second issue, while it would remove clutter from the per-role folders and consolidate the files under each project, I haven't felt a need to change it at this time since the number of projects is realistically rather small. Once again YAGNI applies, and I can revisit and easily rejigger the organization without too much hassle.&lt;/p&gt;
</content><category term="Technical"/><category term="programming"/><category term="SCons"/><category term="buildSystem"/></entry><entry><title>HOWTO: Scons - Remove Extra Build Output Files</title><link href="https://vijay.varadan.com/talks/howto-scons-remove-extra-build-output-files/" rel="alternate"/><published>2016-01-03T20:57:00-08:00</published><updated>2016-01-03T20:57:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2016-01-03:/talks/howto-scons-remove-extra-build-output-files/</id><summary type="html">&lt;p class="first last"&gt;Getting SCons to correctly deal with 'extra' (ILK, PDB, etc) build output files.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="Scons Logo" src="https://vijay.varadan.com/talks/images/scons-logo-128px.png" /&gt;&lt;/p&gt;
&lt;p&gt;I spent the end of 2015 and the first couple of days of 2016 porting build environment scripts to &lt;a class="reference external" href="https://en.wikipedia.org/wiki/Windows_PowerShell"&gt;Powershell&lt;/a&gt; and fixing up &lt;a class="reference external" href="http://scons.org/"&gt;SCons&lt;/a&gt; based build scripts to work with Visual Studio 2015. When doing debug builds, incremental link (.ILK) and program database (.PDB) files are generated. These are considered extra files, since they're not the actual targets (like .OBJ, .EXE, .LIB or .DLL) being built.&lt;/p&gt;
&lt;p&gt;The recommended way to remove these files is to mark them as side effects and call the &lt;tt class="docutils literal"&gt;Clean()&lt;/tt&gt; method on the environment object passing these as parameters. So, looking at &lt;a class="reference external" href="http://permalink.gmane.org/gmane.comp.programming.tools.scons.user/21082"&gt;this forum post&lt;/a&gt;, I did just that. The change to my SConscript looked something like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SideEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;myproject.ilk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Clean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;myproject.ilk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And lo and behold, it &lt;strong&gt;didn't&lt;/strong&gt; work.&amp;nbsp;Unfortunately, SCons documentation is bit bare and scattered about with information split unevenly and non-intuitively in the &lt;a class="reference external" href="http://scons.org/doc/production/HTML/scons-user.html"&gt;user guide&lt;/a&gt;, &lt;a class="reference external" href="http://scons.org/doc/production/HTML/scons-man.html"&gt;man page&lt;/a&gt;, &lt;a class="reference external" href="http://scons.org/doc/production/HTML/scons-api/index.html"&gt;API (object model) docs&lt;/a&gt; and the &lt;a class="reference external" href="https://bitbucket.org/scons/scons/wiki/Home"&gt;wiki&lt;/a&gt;. The wiki, after repeatedly being hacked and abused was recently moved to BitBucket, but doesn't seem to be searchable [aaaarrrrgggghhhh!]. This is even more true for information about &lt;tt class="docutils literal"&gt;SideEffect()&lt;/tt&gt; and its use in conjunction with &lt;tt class="docutils literal"&gt;Clean()&lt;/tt&gt;. I tried the typical sort of debugging via print statements to ensure that I wasn't munging up any values and nothing seemed amiss.&lt;/p&gt;
&lt;p&gt;I ended up finding a clue in the &lt;a class="reference external" href="https://bitbucket.org/scons/scons/wiki/SConsMethods/SideEffect"&gt;wiki page for the 'SideEffect()' function&lt;/a&gt; - note that this page is not linked to from the main wiki page and neither is its parent. With search functionality missing for the wiki, I only found&amp;nbsp;that&amp;nbsp;page via a &lt;a class="reference external" href="http://duckduckgo.com"&gt;DuckDuckGo&lt;/a&gt; search because I was explicitly searching for documentation on the &lt;tt class="docutils literal"&gt;SideEffect()&lt;/tt&gt; function. On that wiki page, I noticed the function signature which clearly showed that the order of parameters to the &lt;tt class="docutils literal"&gt;SideEffect()&lt;/tt&gt; function is the reverse&amp;nbsp;of that of&amp;nbsp;&lt;tt class="docutils literal"&gt;Clean()&lt;/tt&gt;. To be fair, the user guide does have examples and a listing with the correct parameter order - but it's not obvious or pointed out explicitly.&lt;/p&gt;
&lt;p&gt;In my not-so-humble opinion, it is &lt;strong&gt;incredibly daft and very poor design&lt;/strong&gt;&amp;nbsp;to reverse parameter order in API functions. Moreover, in this case, there doesn't even seem to be a good reason to do so.&amp;nbsp;It results in&amp;nbsp;increased user errors, just like with me and&amp;nbsp;the original forum poster who posted the initial answer.&lt;/p&gt;
&lt;p&gt;I swapped the order of params and voilà!&amp;nbsp;It worked.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SideEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;color: #ff0000;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;myproject.ilk&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;color: #0000ff;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Clean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;color: #0000ff;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;color: #ff0000;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;myproject.ilk&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To ensure that I didn't run into this problem elsewhere, I added a function in my SConstruct that would take care of this, with an appropriate comment.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;AddSideEffectForClean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;side_effect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# NOTE: the order of params to SideEffect() is the reverse of Clean()&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SideEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;side_effect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Clean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;side_effect&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;global_env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AddSideEffectForClean&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;AddSideEffectForClean&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In my various SConscript files, I invoke it as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;variant&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSideEffectForClean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;myproject.ilk&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;myenv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSideEffectForClean&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;myproject.pdb&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I wasted a couple of hours on this, but it's sorted now. Hope this helps someone else looking to clean out extraneous build output files when using SCons.&lt;/p&gt;
</content><category term="Technical"/><category term="programming"/><category term="SCons"/><category term="sideEffects"/></entry><entry><title>Software Atrophy: An Example</title><link href="https://vijay.varadan.com/talks/software-atrophy-an-example/" rel="alternate"/><published>2015-09-10T12:51:00-07:00</published><updated>2015-09-10T12:51:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2015-09-10:/talks/software-atrophy-an-example/</id><summary type="html">&lt;p class="first last"&gt;Internal tools need regular maintenance, just like all other software systems.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="Scons Logo" src="https://vijay.varadan.com/talks/images/scons-logo-128px.png" /&gt;&lt;/p&gt;
&lt;p&gt;Somewhere along the way, as tends to happen with a lot of
software systems, the&amp;nbsp;build scripts used at Axham Games began showing
signs of atrophy and the discovery led to some important lessons when it
comes to engineering software.&lt;/p&gt;
&lt;p&gt;Previously, I'd put up an article describing the &lt;a class="reference external" href="https://vijay.varadan.com/talks/scons-build-system/"&gt;component object model&lt;/a&gt; of my &lt;a class="reference external" href="http://www.scons.org/"&gt;SCons&lt;/a&gt; based build system at Axham Games. If you haven't already read that, you might want to take a gander; it would ease understanding of what is discussed here. Somewhere along the way, as tends to happen with a lot of software systems, our build scripts began showing signs of atrophy.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is written with a view to help myself and others running development teams. This post goes into details about poorly done software development work, but the goal is not to cast blame, but to learn how to spot the signs early and make appropriate course corrections before reaching a point where a system needs to be completely re-written.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note 2:&lt;/strong&gt; This was originally written in Jan 2015, but was put on the back burner because I got injured in an accident.&amp;nbsp;I didn't find time till now to wrap it up and publish it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class="section" id="quick-recap"&gt;
&lt;h2&gt;Quick Recap&lt;/h2&gt;
&lt;p&gt;In our system we treat sets of libraries as a single component and a Python class represents a component. E.g. all the boost libraries have common parameters and are group together as a single component. Each project can choose which libraries within the set to use by specifying them in the SConstruct file and overriding them within per project SConscript files.&lt;/p&gt;
&lt;p&gt;Here's an example of the configuration used to link to Lua libraries.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LUA_DIR&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;externals_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;build_mode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;lua&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LUA_PLUGIN_LIBRARIES&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;lua52&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LUA_INCLUDE_DIR_EPILOG&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;include&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LUA_VARIANT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;externals_variant&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;LUA_VERSION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;5-2&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We also rely on the developer having correct environment variables set for paths to tools since they can be installed in different locations on any given machine. As can be seen from the example above, we construct any paths in an OS agnostic manner using Python's standard facilities. One critical rule that&amp;nbsp;has to be followed is &lt;span class="raw-html"&gt;&lt;span style="color: #FF0000"&gt;"&lt;strong&gt;No hard-coded paths&lt;/strong&gt;"&lt;/span&gt;&lt;/span&gt; since we compile using different tool chains (mingw GNU C++, Visual C++) and multiple platforms (Win32, Win64, Linux, etc).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="what-went-wrong"&gt;
&lt;h2&gt;What Went Wrong&lt;/h2&gt;
&lt;div class="section" id="core-libraries-component"&gt;
&lt;h3&gt;1. Core Libraries Component&lt;/h3&gt;
&lt;p&gt;On any given platform, there are usually core libraries like user32.lib on Windows or ws2_32.lib when using mingw. Additionally, there may be libraries such as stdc++-6 which will need to be linked to when compiling with the GNU C++ compiler. One way in which some core libraries are different from others within the component are that the corresponding dynamic libs are installed either as part of the system or via an external package; an easy way to think of them is as though they are similar to the Visual C++ runtime libraries, the .NET runtime or the Java runtime.&lt;/p&gt;
&lt;p&gt;Unfortunately, even though this had been explained to developers on the team, it was either forgotten or ignored. So, the result was that the developer set it up to copy the core dynamic libs from their location to the target directory. This is an &lt;strong&gt;absolute no-no&lt;/strong&gt; for system libraries.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="hard-coded-path"&gt;
&lt;h3&gt;2. Hard-coded Path&lt;/h3&gt;
&lt;p&gt;The developer further compounded the error of copying system libraries to the target directory,&amp;nbsp;by hard-coding the path of the system directory (in this case, the mingw-msys bin directory) in the core libraries component's Python class. But, it was done in a way that's not easy to detect, by constructing the path using Python's standard facilities.&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;dynamic_lib_path = &lt;span class="pre"&gt;util.join_path('c:',&lt;/span&gt; 'tools', 'mingw', 'bin')&lt;/tt&gt;&lt;/p&gt;
&lt;p&gt;Not only would this fail were mingw installed in a different directory, this is also OS specific. The build would fail in the&amp;nbsp;Linux and OSX environments.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="how-it-was-detected"&gt;
&lt;h2&gt;How it was Detected&lt;/h2&gt;
&lt;p&gt;Simple answer: Completely by accident. I have a couple of machines on which I do development, one of which is a laptop on which I was prototyping before I founded Axham Games. So, the various tools were installed in non-standard directories on that laptop. When I ran a build on the laptop, it promptly broke indicating that the dynamic lib in the above hard-coded path did not exist.&amp;nbsp;When used properly, the build system is designed to be able to deal with tools installed in non-standard directories, since their locations are supposed to be picked up from environment variables. Hard coding the path broke it.&lt;/p&gt;
&lt;p&gt;Why the developer did this is mystery (he is no longer at the studio); especially considering that there are pre-existing examples of how to do this according to established convention, which is to have each&amp;nbsp;developer define&amp;nbsp;an environment variable to specify the directory. At best, this piece of work is reflective of a poor work ethic i.e. that the developer adhered only to&amp;nbsp;the letter of the rule, not its spirit. At worst, this is insidious; the hard coding of the path was &amp;quot;cleverly&amp;quot; obfuscated by using Python's standard path construction facilities and unless one looks closely, everything seems kosher.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-fix"&gt;
&lt;h2&gt;The Fix&lt;/h2&gt;
&lt;p&gt;The correct fix is to allow any component to specify that certain libraries that are linked to do not (or should not) have dynamic libraries copied over to the target directory.&lt;/p&gt;
&lt;p&gt;To that effect, the base Component class from which each of the individual components derive needs to be modified to store the library list of what is not to be installed. We do this by adding one member list&amp;nbsp;&lt;tt class="docutils literal"&gt;_dynamic_libraries_dni&lt;/tt&gt; (dni = do not install) and two properties &lt;tt class="docutils literal"&gt;dynamic_libraries_dni&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;dynamic_libraries_installable&lt;/tt&gt; as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_dynamic_libraries_dni&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dynamic_libraries_dni&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_dynamic_libraries_dni&lt;/span&gt;&lt;span class="p"&gt;[:]&lt;/span&gt;

    &lt;span class="nd"&gt;@property&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dynamic_libraries_installable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="n"&gt;dl&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;dl&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_dynamic_libraries&lt;/span&gt;
                            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dl&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_dynamic_libraries_dni&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;

    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;These properties and member variable propagate through to the derived classes and are used in per-project&amp;nbsp;SConscript files which invoke the &lt;tt class="docutils literal"&gt;dynamic_libraries_installable&lt;/tt&gt; property to determine the libraries to install.&lt;/p&gt;
&lt;p&gt;We also remove the hard-coded path in the Core component implementation as it was incorrect and since it is no longer needed.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="quick-thoughts-on-atrophy-prevention"&gt;
&lt;h2&gt;Quick&amp;nbsp;Thoughts on Atrophy Prevention&lt;/h2&gt;
&lt;p&gt;&lt;span class="raw-html"&gt;&lt;span style="color: #008000"&gt;&lt;strong&gt;tl;dr version:&lt;/strong&gt; This problem could have been avoided if the build system changes had been code reviewed like all other production code.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Recalling some discussions with a former colleague, software is not a write-once-and-forget&amp;nbsp;sort of thing. All software is organic in nature; it's more like a tree. It needs to be nurtured, attended to, and from time to time,&amp;nbsp;pruned.&lt;/p&gt;
&lt;p&gt;All&amp;nbsp;code, particularly production code, ought&amp;nbsp;to be written carefully and code-reviewed as part of the check-in process, sometimes by more than one pair of eyes. But the same level of rigor is not applied to internal support systems like build systems and developer tools. In small teams like ours, there aren't sufficient&amp;nbsp;resources to pay attention at that level of detail to non-shipping code unless it is a significant pain point or as in this case, breaks in one or more environments.&lt;/p&gt;
&lt;p&gt;Looking back at this more critically, possible only with time and distance from the series of events that preceeded this find, the crux of the issue was:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;a bad hire - the hack engineer who implemented the broken solution&lt;/li&gt;
&lt;li&gt;a manager [me] who didn't oversee the engineer's work more closely, and more importantly, terminate the engineer months prior despite sufficient warning signs. Note that the termination is not for mistakes, it's for a myriad of reasons including poor work ethic.&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</content><category term="Technical"/><category term="engineering"/><category term="SCons"/><category term="softwareEngineering"/></entry><entry><title>Object Model of My SCons-based Build System</title><link href="https://vijay.varadan.com/talks/scons-build-system/" rel="alternate"/><published>2015-01-20T08:18:00-08:00</published><updated>2015-01-20T08:18:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2015-01-20:/talks/scons-build-system/</id><summary type="html">&lt;p class="first last"&gt;SCons, a python based build system, is what we use at Axham Technologies.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="logo" src="https://vijay.varadan.com/talks/images/scons-logo-128px.png" /&gt;&lt;/p&gt;
&lt;p&gt;We used&amp;nbsp;&lt;a class="reference external" href="http://www.scons.org"&gt;SCons&lt;/a&gt; as our&amp;nbsp;build system at Axham Games. SCons is implemented as a Python script and a set of modules. Configuration files in SCons are also Python scripts which are executed; this makes for a very potent build system for you have all of the power of Python, its modules and extensions available for use in your build system.&lt;/p&gt;
&lt;p&gt;In this post, I'll focus on the object model for our build system which essentially treats each group of libraries as a component. If warranted and there's sufficient interest, I'll get into details of the entire system in a future follow up post.&lt;/p&gt;
&lt;div class="section" id="primary-objectives"&gt;
&lt;h2&gt;Primary Objectives&lt;/h2&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;modularity and ease of extension; primarily be able to add libraries with minimum addition to the build system&lt;/li&gt;
&lt;li&gt;ability to build on multiple platforms without requiring additional steps&lt;/li&gt;
&lt;li&gt;flexibility to be able to swap&amp;nbsp;library versions with minimal alterations&lt;/li&gt;
&lt;li&gt;override build parameters at the command line&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="object-model"&gt;
&lt;h2&gt;Object Model&lt;/h2&gt;
&lt;p&gt;Each set of libraries in the build system is treated as a single component. One of the major issues I ran into early on when compiling for multiple platforms and architectures, particularly when using different compiler toolchains, was that they all followed vastly &lt;strong&gt;different and inconsistent naming conventions&lt;/strong&gt;. I found this to be true even for the same set of libraries built using the same compiler toolchain&amp;nbsp;where only the platform differed. The most common example is the prefixing of &amp;quot;lib&amp;quot; on POSIX&amp;nbsp;systems. On Windows, some libraries get built out on&amp;nbsp;POSIX emulation toolchains (like mingw-gcc) with library naming conventions similar to POSIX systems, while some libraries do not.&lt;/p&gt;
&lt;p&gt;All sets of libraries used typically have a fixed set of properties viz. include path, library path and libraries to statically or dynamically link to. So, in essence we can treat each set of libraries like boost or Ogre3d as a single component for the purposes of our build system.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="boost-as-an-example"&gt;
&lt;h2&gt;Boost as an Example&lt;/h2&gt;
&lt;p&gt;Let us take boost as an example for the purposes of explaining the usage of the object model. Boost, has a rather convoluted naming convention (with good reason, probably) for its libraries, wherein the boost version is embedded in the middle of the library name with a mixture of underscores and hyphens. e.g. &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;libboost_thread-mgw48-mt-d-1_55.dll.a&lt;/span&gt;&lt;/tt&gt;&lt;/p&gt;
&lt;p&gt;Let's break this example name down into its constituent parts:&lt;/p&gt;
&lt;p&gt;&lt;img alt="boost-lib-name-example" src="https://vijay.varadan.com/talks/images/boost-lib-name-example.png" /&gt;&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;strong&gt;lib&lt;/strong&gt; - this indicates that it's a library of some sort, could be static, dynamic or a stub library you link to use a dynamic library.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;boost&lt;/strong&gt; - name of the library &amp;quot;group&amp;quot; it's a part of&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;thread&lt;/strong&gt; - the actual library, in this case it's a&amp;nbsp;thread library&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mgw48&lt;/strong&gt; - compiler toolchain and version, in this case, mingw gcc 4.8&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;mt&lt;/strong&gt; - multi-threaded&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;d&lt;/strong&gt; - debug&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1_55&lt;/strong&gt; - boost version&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dll.a&lt;/strong&gt; - stub library to link to use the dynamic library&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is the name of the stub multi-threaded debug thread library from boost ver 1.55 built using the mingw gcc toolchain ver 4.8. On Visual C++ 2013, this same library would be named &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;libboost_thread-vc120-mt-gd-1_55.dll.a&lt;/span&gt;&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;The compiler toolchain used is project specific as is the version of boost. As long as the libraries used by the project are available, the developer will be able to use the libraries by minimally specifying the versions for the toolchains used in the project.&lt;/p&gt;
&lt;p&gt;The onerous task of building the specific library names per platform architecture and toolchain which are specific to the set of libraries is encapsulated within a simple Python class modeled as a component. All components have standard properties to provide include path(s), library path(s) and libraries to link to. These properties are assembled in the constructor of the component based on environment variables which can be overridden by the build environment and further by values specified as parameters on the command line when the build is fired off.&lt;/p&gt;
&lt;p&gt;So, in the SConstruct file of the project (which may have multiple sub-projects), the developer specifies the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="c1"&gt;# externals_dir is the base directory for 3rd party libs&lt;/span&gt;
&lt;span class="c1"&gt;# plat_arch is the platform-architecture&lt;/span&gt;
&lt;span class="c1"&gt;# externals_variant is the build variant e.g. debug&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;COMPONENT_NAMES&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;boost&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;BOOST_DIR&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;externals_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;plat_arch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;boost&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;BOOST_VARIANT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;externals_variant&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;BOOST_VERSION&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;1-55&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;BOOST_INCLUDE_DIR_EPILOG&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;include&amp;#39;&lt;/span&gt;

&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;BOOST_LIBRARY_EPILOGS&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s1"&gt;&amp;#39;win.mingw.x86&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-mgw48-mt-d-1_55&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="s1"&gt;&amp;#39;release&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-mgw48-mt-1_55&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="s1"&gt;&amp;#39;win.msvc.x86&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-vc120-mt-gd-1_55&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                        &lt;span class="s1"&gt;&amp;#39;release&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;-vc120-mt-1_55&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;BOOST_LIBRARIES&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="s1"&gt;&amp;#39;win.mingw.x86&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;boost_system&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="s1"&gt;&amp;#39;boost_thread&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                             &lt;span class="s1"&gt;&amp;#39;boost_program_options&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
      &lt;span class="c1"&gt;#Since boost::thread depends on boost_chrono in msvc alone.&lt;/span&gt;
      &lt;span class="s1"&gt;&amp;#39;win.msvc.x86&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;boost_system&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="s1"&gt;&amp;#39;boost_thread&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="s1"&gt;&amp;#39;boost_chrono&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                            &lt;span class="s1"&gt;&amp;#39;boost_program_options&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are a few basic assumptions that the components of the object model makes which are documented rather than enforced via codifying rules:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;the base directory for the component is specified as &lt;tt class="docutils literal"&gt;&amp;lt;COMPONENT_NAME&amp;gt;_DIR&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;libraries used by the component are specified in a nested dictionary with the platform-architecture as the outer dictionary key and the build-variant as the inner dictionary key&lt;/li&gt;
&lt;li&gt;components may require additional parameters to be specified, which are documented&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The main reason for not enforcing the rules via code checks within the build system is that we are a small team of at most four engineers and the work of codification of rules has not been seen as required. If the team grows larger (most likely indicated by the need to open a build engineer position), it may make sense codify the rules. Any errors that we run into due to missing or incorrectly specified parameters has caused the build to fail, and fail fast. Over the years, I've become a strong believer in YAGNI (you aren't going to need it) and that's one of the foundational principles of any software I write these days, including but not limited to build systems.&lt;/p&gt;
&lt;p&gt;At this point, the developer is ready to start using and linking against boost libraries for all sub-projects, which can choose to override these values.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Technical"/><category term="objectModel"/><category term="buildSystem"/><category term="SCons"/><category term="python"/></entry><entry><title>A Tour of C++ / Bjarne Stroustrup</title><link href="https://vijay.varadan.com/talks/a-tour-of-c-bjarne-stroustrup/" rel="alternate"/><published>2014-12-29T12:57:00-08:00</published><updated>2014-12-29T12:57:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2014-12-29:/talks/a-tour-of-c-bjarne-stroustrup/</id><summary type="html">&lt;p class="first last"&gt;Highly recommended. Great book to get started with modern C++, especially for those with prior C++ experience.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;a class="reference external image-reference" href="https://vijay.varadan.com/talks/images/image-e1420555503388.jpg"&gt;&lt;img alt="A Tour of C++" src="https://vijay.varadan.com/talks/images/image-e1420555503388.jpg" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This book is great to get you started writing modern C++ code that uses most
of the significant new features of C++11 and with appropriate pointers
to corresponding chapters in Stroustrup's tome (which I consider an
excellent reference) for in-depth study.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Verdict: Highly Recommended&lt;/strong&gt;&lt;/p&gt;
</content><category term="Technical"/><category term="productivity"/><category term="bookReview"/><category term="CPP"/><category term="BjarneStroustrup"/><category term="highlyRecommended"/></entry><entry><title>Weekly Planning</title><link href="https://vijay.varadan.com/talks/weekly-planning/" rel="alternate"/><published>2014-12-21T12:18:00-08:00</published><updated>2014-12-21T12:18:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2014-12-21:/talks/weekly-planning/</id><summary type="html">&lt;p class="first last"&gt;From Laura Vanderkam's 'What the Most Successful People Do at Work'.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;a class="reference external image-reference" href="https://vijay.varadan.com/talks/images/IMG_0320.png"&gt;&lt;img alt="IMG_0320.PNG" src="https://vijay.varadan.com/talks/images/IMG_0320-1024x1024.png" style="width: 720px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;With my annual goals in mind, I then make a priority list every Sunday
night of what I plan to accomplish in the next week. That priority list
will include both immediate assignments and steps toward my annual goals
... I tightly schedule Monday and loosely schedule the rest of the week.
Then on Monday night I schedule Tuesday more tightly, based on what’s
left on the priority list and what’s come up on Monday. Tuesday night I
schedule Wednesday, and so forth. I’ve usually gotten most things done
by Friday, which can be a mop up day or a time for more planning.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Laura Vanderkam (What the Most Successful People Do at Work)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
</content><category term="Productivity"/><category term="LauraVanderkam"/><category term="organizing"/><category term="planning"/><category term="productivity"/></entry><entry><title>Habits - Anthony Trollope</title><link href="https://vijay.varadan.com/talks/habits-anthony-trollope/" rel="alternate"/><published>2014-12-21T10:28:00-08:00</published><updated>2014-12-21T10:28:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2014-12-21:/talks/habits-anthony-trollope/</id><summary type="html">&lt;p class="first last"&gt;Chip away at the block, one bit at a time.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;a class="reference external image-reference" href="https://vijay.varadan.com/talks/images/IMG_0319.png"&gt;&lt;img alt="IMG0319" src="https://vijay.varadan.com/talks/images/IMG_0319-1024x384.png" style="width: 720px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A habit, Anthony Trollope once said, “has the force of
the water drop that hollows the stone. A small daily task, if it be
really daily, will beat the labors of a spasmodic Hercules.”&lt;/p&gt;
</content><category term="Productivity"/><category term="habits"/><category term="organizing"/><category term="planning"/><category term="AnthonyTrollope"/></entry><entry><title>3 Steps to New Habits</title><link href="https://vijay.varadan.com/talks/3-steps-to-new-habits/" rel="alternate"/><published>2014-12-20T06:51:00-08:00</published><updated>2014-12-20T06:51:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2014-12-20:/talks/3-steps-to-new-habits/</id><summary type="html">&lt;ol class="first last arabic simple"&gt;
&lt;li&gt;&lt;p class="first"&gt;Make it tiny. (2) Find a spot. (3) Train the cycle.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</summary><content type="html">&lt;p&gt;&lt;a class="reference external image-reference" href="https://vijay.varadan.com/talks/images/3-steps-to-new-habits.png"&gt;&lt;img alt="3StepsToNewHabits" src="https://vijay.varadan.com/talks/images/3-steps-to-new-habits-1024x763.jpg" style="width: 720px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Make it tiny.&lt;/li&gt;
&lt;li&gt;Find a spot.&lt;/li&gt;
&lt;li&gt;Train the cycle.&lt;/li&gt;
&lt;/ol&gt;
</content><category term="Productivity"/><category term="habits"/><category term="organizing"/><category term="planning"/><category term="productivity"/></entry><entry><title>My Fingers Thank Me - Profusely!</title><link href="https://vijay.varadan.com/talks/my-fingers-thank-me-profusely/" rel="alternate"/><published>2013-06-30T03:48:00-07:00</published><updated>2013-06-30T03:48:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2013-06-30:/talks/my-fingers-thank-me-profusely/</id><summary type="html">&lt;p class="first last"&gt;Your finger health - yes, it's time to talk about ergonomics.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Grab a seat. This is some important stuff. Stuff that you normally don't
pay a lot of attention to, but should. I'm talking about your health. A
bit more specifically, ergonomics. Even more to the point, your finger
health. As a developer, I spend the vast majority of my time writing
code, which means that my primary tool for input is a keyboard. Over the
three decades that I've been around computers, I've tried a large
variety of keyboards and have come to the conclusion that mechanical
keyboards are the only ones worth using.&lt;/p&gt;
&lt;p&gt;When buying gear for &lt;a class="reference external" href="http://axhamgames.com"&gt;the studio&lt;/a&gt;, I ordered
&lt;a class="reference external" href="http://gaming.logitech.com/en-us/product/g105-gaming-keyboard"&gt;Logitech G-105 Gaming
Keyboards&lt;/a&gt;
without doing much research. I didn't hold out much hope of getting
mechanical keyboards based on the difficulties I ran into trying to get
&amp;quot;high-end&amp;quot; game development workstations. A couple of weeks ago, when
talking about mechanical keyboards, their lack of availability in India
and the (relatively) high prices you have to pay to get your hands on
one, someone mentioned that developer friends of theirs would buy
mechanical keyboards on their trips to India and take them back for use
overseas in the UK or USA. I was a bit surprised to hear this. Computing
hardware of any kind is not the sort of thing you'd associate with being
&amp;quot;exported&amp;quot; from India. You usually bring that sort of thing into the
country, not take it out. Color me intrigued! The manufacturer turned
out to be &lt;a class="reference external" href="http://www.tvs.in/"&gt;TVS&lt;/a&gt;, who most folks, including me,
know for their rather high quality motor vehicles. They also have an
&lt;a class="reference external" href="http://www.tvs-e.in/"&gt;electronics division&lt;/a&gt; which manufactures
mechanical keyboards among other things.&lt;/p&gt;
&lt;p&gt;I contacted my supplier and had a sample delivered. And I was
&lt;strong&gt;floored&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external image-reference" href="https://vijay.varadan.com/talks/images/TVS-Gold-Mechanical-Keyboard.png"&gt;&lt;img alt="TVS Gold Mechanical Keyboard" src="https://vijay.varadan.com/talks/images/TVS-Gold-Mechanical-Keyboard.jpg" style="width: 720px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The keyboard was beautiful to look at and typing on it was such
pleasure. I fell in love with it instantly. It's hard to describe the
immense satisfaction as you hear the click of each key as you press it
down. It's like a symphony. Even typing mistakes are less irritating as
pounding away on the backspace key is also pure joy. One very nice thing
about the keyboard is that the spacebar key is stiffer than the others
and takes more pressure to bottom out. I have a tendency to bottom out
when typing due to the PC-XT keyboards I started out with in the 80s.
Those keys were considerably stiffer, needed more pressure and if I
recall correctly, I had to bottom out for the key press to register i.e.
the actuation point was at the bottom of the switch.&lt;/p&gt;
&lt;p&gt;So, I'm in love now. This is one of the best purchases I've made in a
long, long time. I look forward to sitting down at my workstations just
to hear the sweet sounds of the keyboard as I pound away on it.&lt;/p&gt;
&lt;iframe src="//www.youtube-nocookie.com/embed/_mRtgJPDS7s" width="640" height="480" frameborder="0" allowfullscreen="allowfullscreen"&gt;&lt;/iframe&gt;&lt;p&gt;A couple of things that took me about 2-3 days to get used to:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;The Enter key is non-rectangular and shaped like a mirrored fat L. This
design is rather uncommon these days with almost all keyboards having
a rectangular Enter key with the backslash key right above that.&lt;/li&gt;
&lt;li&gt;The backslash key is to the right of the equals key. This was the
hardest to get used to. I kept hitting the Enter key for the whole of
the first day when I meant to type backslash as a path separator at
the command prompt. I was very nervous that I might accidentally do
that while recursively removing a folder e.g. typing &lt;tt class="docutils literal"&gt;del /s C:&lt;/tt&gt;
when I meant to type &lt;tt class="docutils literal"&gt;del /s &lt;span class="pre"&gt;C:\junk&lt;/span&gt;&lt;/tt&gt;.&lt;/li&gt;
&lt;li&gt;The backspace key is a regular sized key rather than being double
sized. This wasn't as hard to get used to.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here's the sweet bit - the &lt;a class="reference external" href="http://www.tvs-e.in/product.php?detid=38"&gt;TVS Gold Mechanical
Keyboards&lt;/a&gt; are available at
about Rs. 1600 (less that USD 30 at the current exchange rates). This is
very inexpensive compared to the $100 minimum you pay for other
mechanical keyboards. TVS have a winner in this keyboard. Now, you can
stop reading and go out and buy one (or more) for yourself and your near
and dear ones - I now have 3 of them for use at both my work locations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Verdict:&lt;/strong&gt; Buy, definitely.&lt;/p&gt;
</content><category term="Productivity"/><category term="productivity"/><category term="gear"/><category term="keyboard"/><category term="mechanical"/><category term="tvsgold"/></entry><entry><title>Mercurial Diffs with vim on Windows</title><link href="https://vijay.varadan.com/talks/mercurial-diffs-with-vim-on-windows/" rel="alternate"/><published>2012-11-08T07:31:00-08:00</published><updated>2012-11-08T07:31:00-08:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2012-11-08:/talks/mercurial-diffs-with-vim-on-windows/</id><summary type="html">&lt;p class="first last"&gt;Banging my head feels soooo good compared to getting vim, dirdiff and mercurial to play nice on Windows.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="Using vim with Mercurial for diffs" src="https://vijay.varadan.com/talks/images/using-vim-with-mercurial-for-diffs.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="reference internal" href="#update-2017-jan-17"&gt;UPDATE 2017-Jan-17&lt;/a&gt; for newer versions of DirDiff.&lt;/p&gt;
&lt;p&gt;I had the devil of a time getting
vimdiff and mercurial to play nicely with with each other on Windows for
visual diffs. It worked great on posix systems using instructions from
the mercurial wiki both to diff single files as well as a multiple
files. But on Windows, it would only work for single files, giving me
rather strange errors when trying to diff multiple files. So, I spent a
bit of time getting it to work.&lt;/p&gt;
&lt;p&gt;According to the instructions, the following &lt;em&gt;changes&lt;/em&gt; to your mercurial.ini
or .hgrc ( depending on platform ) should enable you to use vimdiff for visual
diffs with mercurial. Note that you need to install the
&lt;a class="reference external" href="https://github.com/will133/vim-dirdiff"&gt;DirDiff plugin&lt;/a&gt; for vim.&lt;/p&gt;
&lt;pre class="literal-block"&gt;
[extensions]
hgext.extdiff=

[extdiff]
cmd.vdiff=gvim
opts.vdiff=-f '+next' '+execute &amp;quot;DirDiff&amp;quot; fnameescape(argv(0)) fnameescape(argv(1))'
&lt;/pre&gt;
&lt;p&gt;If you try using the above changes as are on Windows, all you'll end up with is
vim opening 7 empty buffers with names corresponding to the parts of opt.vdiff
that follow the -f parameter. This happens because of differences between the
way bash and cmd.exe treat single quotes and escaping. This part was relatively
easy to figure out especially with the use of the --debug option to mercurial
like this: &lt;tt class="docutils literal"&gt;hg &lt;span class="pre"&gt;--debug&lt;/span&gt; vdiff&lt;/tt&gt;, which tells you exactly how the command line
is invoked.&lt;/p&gt;
&lt;p&gt;So what I tried next was to replace the single quotes with double quotes and
escaping the double quotes surrounding DirDiff, like so:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
opts.vdiff=-f &amp;quot;+next&amp;quot; &amp;quot;+execute &amp;quot;DirDiff&amp;quot; fnameescape(argv(0)) fnameescape(argv(1))&amp;quot;
&lt;/pre&gt;
&lt;p&gt;That resulted in slightly more informative errors that looked like this:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
Illegal file name
Error detected while processing command line:
E119: Not enough parameters for function: &amp;lt;SNR&amp;gt;12_DirDiff
&lt;/pre&gt;
&lt;p&gt;Definitely an improvement since vim was correctly getting and interpreting
parameters passed. This indicated I had fixed the shell escaping and any
further errors were in vim land.&lt;/p&gt;
&lt;p&gt;I spent a bit of time looking at the DirDiff plugin code - wasn't too hard,
since it was just one file. But I was spinning my wheels, coz the issue
occurred in the invocation of the entry point function defined within the
DirDiff plugin. So, the issue was between what was being passed to vim and how
vim was interpreting it.&lt;/p&gt;
&lt;p&gt;Here's are the approximate steps ( determined empirically ) in how mercurial
invokes the visual diff program specified using the extdiff plugin:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;make a directory in the user's $TMP ( or %TMP% ) folder - let's call this
hgdiff-base&lt;/li&gt;
&lt;li&gt;within hgdiff-base create 2 directories - let's call these repo.original and
my.changes&lt;/li&gt;
&lt;li&gt;copy files that have changed into the my.changes folder and put unchanged,
repository versions of those files into the repo.original folder&lt;/li&gt;
&lt;li&gt;pass the two folders as arg0 and arg1 to the external diff program ( in our
case vimdiff )&lt;/li&gt;
&lt;li&gt;as soon as the external diff program exits, remove hgdiff-base and all
contents&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Since mercurial would cleanup the temp directories that contained the files
with differences, I just fudged my tests by using existing files that as passed
as parameters to vimdiff exactly as mercurial would have.&lt;/p&gt;
&lt;p&gt;In a couple of attempts, I'd narrowed it down to the trailing backslash that
was getting passed to vimdiff when multiple files were involved. Trailing
slashes are fine when working with posix systems, since they use the forward
slash as the path separator and not backslash like Windows does. The directory
names are enclosed in double quotes when passed as arguments to vim to account
for spaces in folder and file names. So, what vim sees in the case of multiple
file diffs is the folder names with a trailing backslash followed immediately
by a double quote. Vim ( correctly ) misinterprets the escaped double quote as
part of the file or path name of the parameter passed to DirDiff. This is what
resulted in the &amp;quot;Illegal file name&amp;quot; error I got earlier.&lt;/p&gt;
&lt;p&gt;The simple solution to the problem was to remove the trailing backslash if it
was present. The easiest way to do that is to use the vim built-in function
substitute. This function is the same one that is invoked within the editor
when you do a find-replace. So, I modified the arguments passed to vimdiff as
shown below and things were hunky dory.&lt;/p&gt;
&lt;pre class="literal-block"&gt;
opts.vdiff=-f &amp;quot;+next&amp;quot; &amp;quot;+execute 'DirDiff' fnameescape(substitute(argv(0), '\\$', '', '')) fnameescape(substitute(argv(1), '\\$', '', ''))&amp;quot;
&lt;/pre&gt;
&lt;div class="section" id="update-2017-jan-17"&gt;
&lt;h2&gt;UPDATE 2017-Jan-17&lt;/h2&gt;
&lt;p&gt;If you still run into an issue
after the above fix and get an error message &amp;quot;There is no diff at the current
line!&amp;quot;, you are most likely using a newer version of DirDiff which forces
UNIX-style locale specification at the command line without checking if it's
running on Windows. The fix is to add the following line to your _vimrc or
.vimrc file:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
let g:DirDiffForceLang=&amp;quot;&amp;quot;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="mixing-msys-and-native-windows-vim"&gt;
&lt;h2&gt;Mixing MSYS and &lt;em&gt;native&lt;/em&gt; Windows vim&lt;/h2&gt;
&lt;p&gt;If you're using MinGW under MSYS and use the Windows native version of gvim.exe
supplied by vim.org, then note that when launching gvim from the MSYS shell,
$HOME is your &lt;strong&gt;MSYS&lt;/strong&gt; home directory and that the Windows version of
gvim will look for plugins in the $HOME/vimfiles/plugin - I spent a bunch of
time wondering why gvim couldn't find DirDiff even though I put it in the
vimfiles/plugin folder under my &lt;strong&gt;Windows&lt;/strong&gt; home directory. That happens coz
the MSYS shell changes your HOME directory to be your home directory in MSYS.
If you were to use the vim.exe that ships with MSYS, then it looks for user
plugins in $HOME/&lt;strong&gt;.vim&lt;/strong&gt;/plugin where $HOME is naturally your MSYS home
folder.&lt;/p&gt;
&lt;p&gt;You might just be better off if you don't mix MSYS with native Windows vim,
unless you're like me and are willing to bang your head figuring out these
kinds of quirks. :-) Enjoy.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Technical"/><category term="programming"/><category term="DirDiff"/><category term="hg"/><category term="mercurial"/><category term="vi"/><category term="vim"/><category term="vimdiff"/><category term="windows"/></entry><entry><title>Building Ogre3D 1.8.1 on MinGW</title><link href="https://vijay.varadan.com/talks/building-ogre3d-1-8-1-on-mingw/" rel="alternate"/><published>2012-10-31T15:26:00-07:00</published><updated>2012-10-31T15:26:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2012-10-31:/talks/building-ogre3d-1-8-1-on-mingw/</id><summary type="html">&lt;p class="first last"&gt;Jumping through hoops of fire to get Ogre3D to build on MinGW.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="image0" src="https://vijay.varadan.com/talks/images/ogrehead-e1351708358688.gif" /&gt;&lt;/p&gt;
&lt;p&gt;Ogre3D on MinGW isn't covered very well on the Ogre site or
its forums. So, I made some notes about building Ogre from source on
MinGW.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Assumptions:&lt;/strong&gt; You're familiar with Windows &amp;amp; Unix utilities, shell scripting ( bash &amp;amp; cmd ), have knowledge of command line compilation and are generally fearless, like a lion.&lt;/p&gt;
&lt;p&gt;I put all third party code in ~/external, build them to ~/build/output and install them to ~/build/install. I eschew system wide installs and prefer to use local installation where possible, but I don't fight it too much - take the case of python. I'd prefer a simple unzip of python, but that doesn't work for a bunch of stuff ( like mercurial, NumPy, pygame ) that looks for registry entries in Windows for successful installation. So, I just use the installer from the python.org site.&lt;/p&gt;
&lt;div class="section" id="building-ogre"&gt;
&lt;h2&gt;Building Ogre&lt;/h2&gt;
&lt;p&gt;Here's my development setup:&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;Platform&lt;/td&gt;
&lt;td&gt;Windows 7 x64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Toolchain&lt;/td&gt;
&lt;td&gt;mingw gcc on msys which you can get &lt;a class="reference external" href="http://www.mingw.org/"&gt;here&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;gcc version&lt;/td&gt;
&lt;td&gt;4.7.0 - get this with mingw&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;python version&lt;/td&gt;
&lt;td&gt;2.7.3 for x86 from &lt;a class="reference external" href="http://python.org"&gt;python.org&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;mercurial version&lt;/td&gt;
&lt;td&gt;2.3.2 for x86, I use the &lt;strong&gt;python package&lt;/strong&gt;. From the &lt;a class="reference external" href="http://mercurial.selenic.com/"&gt;official site&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Ogre version&lt;/td&gt;
&lt;td&gt;1.8.1 from the &lt;a class="reference external" href="https://bitbucket.org/sinbad/ogre/src/461061ec4d470547fdcd8a73ded6aee29df20505/?at=v1-8"&gt;bitbucket repo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Ogre dependencies&lt;/td&gt;
&lt;td&gt;default branch from the &lt;a class="reference external" href="https://bitbucket.org/cabalistic/ogredeps"&gt;bitbucket repo&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Boost version&lt;/td&gt;
&lt;td&gt;1.51&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;DirectX SDK version&lt;/td&gt;
&lt;td&gt;&lt;a class="reference external" href="http://www.microsoft.com/en-us/download/details.aspx?id=6812"&gt;June 2010&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;If you run into issues, see &lt;a class="reference external" href="http://stackoverflow.com/questions/4102259/directx-sdk-june-2010-installation-problems-error-code-s1023"&gt;this Stack Overflow question&lt;/a&gt;||&lt;/p&gt;
&lt;div class="section" id="step-1-boost"&gt;
&lt;h3&gt;Step 1: Boost&lt;/h3&gt;
&lt;p&gt;This step is completely optional, as boost is not a required dependency. I'm planning on using multi-threading and a whole host of boost libraries. See the post &lt;a class="reference external" href="https://vijay.varadan.com/talks/building-boost-binaries-on-mingw/"&gt;Building boost on MinGW&lt;/a&gt;. &lt;strong&gt;Note:&lt;/strong&gt; I build &lt;strong&gt;everything&lt;/strong&gt; in boost, rather than just the bare minimum required for multi-threading.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="step-2-ogre-dependencies"&gt;
&lt;h3&gt;Step 2: Ogre Dependencies&lt;/h3&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Get a bitbucket account if you don't already have one. Add your ssh pub key to the account - there are instructions on the bitbucket site, if you don't already know how to do this. You can use https instead of ssh, but modify the URL passed to hg clone accordingly.&lt;/li&gt;
&lt;li&gt;Fetch the source code.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OGRE_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/external/ogre/v1-8
mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OGRE_SOURCE_DIR&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OGRE_SOURCE_DIR&lt;/span&gt;
hg&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;ssh://hg@bitbucket.org/cabalistic/ogredeps
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OGREDEPS_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$OGRE_SOURCE_DIR&lt;/span&gt;/ogredeps
&lt;/pre&gt;&lt;/div&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Set up some environment vars and build the deps:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BUILD_OUTPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/build/output
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OGRE_OUTPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BUILD_OUTPUT_DIR&lt;/span&gt;/ogre/v1-8
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OGREDEPS_OUTPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$OGRE_OUTPUT_DIR&lt;/span&gt;/ogredeps
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BUILD_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/build/install
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OGREDEPS_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BUILD_INSTALL_DIR&lt;/span&gt;/ogredeps
mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OGREDEPS_OUTPUT_DIR&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OGREDEPS_OUTPUT_DIR&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;If you're using MinGW under MSYS:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;cmake $OGREDEPS_SOURCE_DIR &lt;span class="pre"&gt;-G&lt;/span&gt; &amp;quot;MSYS Makefiles&amp;quot;&lt;/tt&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;or&lt;/strong&gt; if you're using MinGW without MSYS:&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;cmake $OGREDEPS_SOURCE_DIR &lt;span class="pre"&gt;-G&lt;/span&gt; &amp;quot;MinGW Makefiles&amp;quot;&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;make
mkdir&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$BUILD_INSTALL_DIR&lt;/span&gt;
make&lt;span class="w"&gt; &lt;/span&gt;install
mv&lt;span class="w"&gt; &lt;/span&gt;ogredeps&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OGREDEPS_INSTALL_DIR&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="step-3-ogre-sdk"&gt;
&lt;h3&gt;Step 3: Ogre SDK&lt;/h3&gt;
&lt;p&gt;This is rather similar to building the dependencies.&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Fetch the source code.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OGRE_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/external/ogre/v1-8
mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OGRE_SOURCE_DIR&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OGRE_SOURCE_DIR&lt;/span&gt;
hg&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;ssh://hg@bitbucket.org/sinbad/ogre
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OGRESDK_SOURCE_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$OGRE_SOURCE_DIR&lt;/span&gt;/ogre
&lt;/pre&gt;&lt;/div&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;We need to tell Ogre where boost is:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BOOST_ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/build/install/boost_1_51_0
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BOOST_INCLUDEDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BOOST_ROOT&lt;/span&gt;/include/boost-1_51
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BOOST_LIBRARYDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BOOST_ROOT&lt;/span&gt;/library
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On posix systems, you don't need to set BOOST_INCLUDEDIR or BOOST_LIBRARYDIR, but if you do set them, BOOST_INCLUDEDIR should be set as follows: &lt;tt class="docutils literal"&gt;export &lt;span class="pre"&gt;BOOST_INCLUDEDIR=$BOOST_ROOT/include&lt;/span&gt;&lt;/tt&gt;&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;And where the dependencies are: &lt;tt class="docutils literal"&gt;export &lt;span class="pre"&gt;OGRE_DEPENDENCIES_DIR=~/build/install/ogredeps&lt;/span&gt;&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;Set up some environment vars for build and install locations:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BUILD_OUTPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/build/output
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OGRE_OUTPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BUILD_OUTPUT_DIR&lt;/span&gt;/ogre/v1-8
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OGRESDK_OUTPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$OGRE_OUTPUT_DIR&lt;/span&gt;/ogre
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BUILD_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/build/install
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;OGRESDK_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BUILD_INSTALL_DIR&lt;/span&gt;/ogre
mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OGRESDK_OUTPUT_DIR&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OGRESDK_OUTPUT_DIR&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;If you're using MinGW under MSYS:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;cmake $OGRESDK_SOURCE_DIR &lt;span class="pre"&gt;-G&lt;/span&gt; &amp;quot;MSYS Makefiles&amp;quot;&lt;/tt&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;or&lt;/strong&gt;if you're using MinGW without MSYS:&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;cmake $OGRESDK_SOURCE_DIR &lt;span class="pre"&gt;-G&lt;/span&gt; &amp;quot;MinGW Makefiles&amp;quot;&lt;/tt&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;make
mkdir&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$BUILD_INSTALL_DIR&lt;/span&gt;
make&lt;span class="w"&gt; &lt;/span&gt;install
mv&lt;span class="w"&gt; &lt;/span&gt;sdk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OGRESDK_INSTALL_DIR&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At this point, you should have your boost stuff in &lt;tt class="docutils literal"&gt;#!bash ~/build/install/boost_1_51_0&lt;/tt&gt;, ogre dependencies in &lt;tt class="docutils literal"&gt;#!bash ~/build/install/ogredeps&lt;/tt&gt; and the ogre sdk in&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;To&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;applications,&lt;span class="w"&gt; &lt;/span&gt;simply&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;relevant&lt;span class="w"&gt; &lt;/span&gt;include&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;library&lt;span class="w"&gt; &lt;/span&gt;paths&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;compiler&lt;span class="w"&gt; &lt;/span&gt;and
linker&lt;span class="w"&gt; &lt;/span&gt;options.&lt;span class="w"&gt; &lt;/span&gt;On&lt;span class="w"&gt; &lt;/span&gt;posix&lt;span class="w"&gt; &lt;/span&gt;systems,&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;bin&lt;span class="w"&gt; &lt;/span&gt;directories&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;LD_LIBRARY_PATH&lt;span class="w"&gt; &lt;/span&gt;environment&lt;span class="w"&gt; &lt;/span&gt;variable.
On&lt;span class="w"&gt; &lt;/span&gt;Windows&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;MinGW,&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;bin&lt;span class="w"&gt; &lt;/span&gt;directories&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;PATH&lt;span class="w"&gt; &lt;/span&gt;environment&lt;span class="w"&gt; &lt;/span&gt;variable.
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Technical"/><category term="programming"/><category term="graphics"/><category term="ogre"/><category term="ogre3d"/><category term="gamedev"/></entry><entry><title>Building boost Binaries on MinGW</title><link href="https://vijay.varadan.com/talks/building-boost-binaries-on-mingw/" rel="alternate"/><published>2012-10-19T17:14:00-07:00</published><updated>2012-10-19T17:14:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2012-10-19:/talks/building-boost-binaries-on-mingw/</id><summary type="html">&lt;p class="first last"&gt;Jumping through hoops to get boost libraries built on MinGW.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;a class="reference external image-reference" href="http://boost.org"&gt;&lt;img alt="boost c++ library" src="https://vijay.varadan.com/talks/images/boost-logo.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I've been tied up with recruiting related work,
primarily reading resumes, looking at demo reels and doing phone
screens.&amp;nbsp;I got a bit tired of it all a couple of days back and decided
to spend a bit of time doing what I like - think of it as brief break
from the Axham Games studio setup work.&lt;/p&gt;
&lt;p&gt;Building the boost binaries is one of the optional steps for building the &lt;a class="reference external" href="http://ogre3d.org"&gt;Ogre&lt;/a&gt; graphics engine from source. I ran into a few difficulties building the &lt;a class="reference external" href="http://boost.org"&gt;boost&lt;/a&gt; binaries on MinGW.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Assumptions:&lt;/strong&gt; You're familiar with Windows &amp;amp; Unix utilities, shell scripting ( bash &amp;amp; cmd ), know about command line compilation and are generally fearless, like a lion.&lt;/p&gt;
&lt;p&gt;Here's my development setup:&lt;/p&gt;
&lt;table border="1" class="docutils"&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td&gt;Platform&lt;/td&gt;
&lt;td&gt;Windows 7 x64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Toolchain&lt;/td&gt;
&lt;td&gt;mingw gcc on msys which you can get &lt;a class="reference external" href="http://www.mingw.org/"&gt;here&lt;/a&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;gcc version&lt;/td&gt;
&lt;td&gt;4.7.0 - get this with mingw&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Boost version&lt;/td&gt;
&lt;td&gt;1.51 from &lt;a class="reference external" href="http://boost.org"&gt;boost.org&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I build all default libraries in boost, rather than just the bare minimum required for Ogre. Takes a couple of hours on my circa 2009 Intel Core i7 laptop with 4GB RAM &amp;amp; Seagate Momentus XT SATA II HDDs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note 2:&lt;/strong&gt; I've learned the hard way that using a tilde i.e. ~ in args that take a path to b2 under mingw, result in a directory with the name ~ being created in the current directory into which relevant files are placed. So, don't pass a ~ to b2.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note 3:&lt;/strong&gt; This one's slightly &amp;quot;duh&amp;quot;, but readlink will fail silently if you pass it a non-existent link, file or path. So, I pre-create directories where needed.&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Get boost 1.51 from &lt;a class="reference external" href="http://boost.org"&gt;boost.org&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Put it in &lt;tt class="docutils literal"&gt;~/external/boost&lt;/tt&gt;, so your boost source root will be &lt;tt class="docutils literal"&gt;~/external/boost/boost_1_51_0&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;We're going to use this a few times in the future, so set it as an environment var.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BOOST_SRC_ROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/external/boost/boost_1_51_0
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$BOOST_SRC_ROOT&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tools/build/v2
&lt;/pre&gt;&lt;/div&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;To build the binary parts of boost, we first need to build the boost build system.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;./bootstrap.sh&lt;span class="w"&gt; &lt;/span&gt;--with-toolset&lt;span class="o"&gt;=&lt;/span&gt;mingw
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Note that the documentation on the boost wiki is wrong. You &lt;strong&gt;must&lt;/strong&gt; pass the toolset you want to use using the above syntax for boost build to build in mingw. Simply passing gcc or mingw will cause the build to fail with something like this in the error log:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sh&lt;span class="w"&gt; &lt;/span&gt;bootstrap.sh
Bootstrapping&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;engine&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;toolset&lt;span class="w"&gt; &lt;/span&gt;gcc...
Failed&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;bootstrap&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;build&lt;span class="w"&gt; &lt;/span&gt;engine
Consult&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;bootstrap.log&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;more&lt;span class="w"&gt; &lt;/span&gt;details
$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;bootstrap.log
&lt;span class="c1"&gt;###&lt;/span&gt;
&lt;span class="c1"&gt;### Using &amp;#39;gcc&amp;#39; toolset.&lt;/span&gt;
&lt;span class="c1"&gt;###&lt;/span&gt;
rm&lt;span class="w"&gt; &lt;/span&gt;-rf&lt;span class="w"&gt; &lt;/span&gt;bootstrap
mkdir&lt;span class="w"&gt; &lt;/span&gt;bootstrap
gcc&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;bootstrap/jam0&lt;span class="w"&gt; &lt;/span&gt;command.c&lt;span class="w"&gt; &lt;/span&gt;compile.c&lt;span class="w"&gt; &lt;/span&gt;constants.c&lt;span class="w"&gt; &lt;/span&gt;debug.c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt;.c&lt;span class="w"&gt; &lt;/span&gt;glob.c&lt;span class="w"&gt; &lt;/span&gt;hash.c&lt;span class="w"&gt; &lt;/span&gt;hdrmacro.c&lt;span class="w"&gt; &lt;/span&gt;headers.c&lt;span class="w"&gt; &lt;/span&gt;jam.c&lt;span class="w"&gt; &lt;/span&gt;jambase.c&lt;span class="w"&gt; &lt;/span&gt;jamgram.c&lt;span class="w"&gt; &lt;/span&gt;lists.c&lt;span class="w"&gt; &lt;/span&gt;make.c&lt;span class="w"&gt; &lt;/span&gt;make1.c&lt;span class="w"&gt; &lt;/span&gt;object.c&lt;span class="w"&gt; &lt;/span&gt;option.c&lt;span class="w"&gt; &lt;/span&gt;output.c&lt;span class="w"&gt; &lt;/span&gt;parse.c&lt;span class="w"&gt; &lt;/span&gt;pathunix.c&lt;span class="w"&gt; &lt;/span&gt;regexp.c&lt;span class="w"&gt; &lt;/span&gt;rules.c&lt;span class="w"&gt; &lt;/span&gt;scan.c&lt;span class="w"&gt; &lt;/span&gt;search.c&lt;span class="w"&gt; &lt;/span&gt;subst.c&lt;span class="w"&gt; &lt;/span&gt;timestamp.c&lt;span class="w"&gt; &lt;/span&gt;variable.c&lt;span class="w"&gt; &lt;/span&gt;modules.c&lt;span class="w"&gt; &lt;/span&gt;strings.c&lt;span class="w"&gt; &lt;/span&gt;filesys.c&lt;span class="w"&gt; &lt;/span&gt;builtins.c&lt;span class="w"&gt; &lt;/span&gt;pwd.c&lt;span class="w"&gt; &lt;/span&gt;class.c&lt;span class="w"&gt; &lt;/span&gt;native.c&lt;span class="w"&gt; &lt;/span&gt;md5.c&lt;span class="w"&gt; &lt;/span&gt;w32_getreg.c&lt;span class="w"&gt; &lt;/span&gt;modules/set.c&lt;span class="w"&gt; &lt;/span&gt;modules/path.c&lt;span class="w"&gt; &lt;/span&gt;modules/regex.c&lt;span class="w"&gt; &lt;/span&gt;modules/property-set.c&lt;span class="w"&gt; &lt;/span&gt;modules/sequence.c&lt;span class="w"&gt; &lt;/span&gt;modules/order.c&lt;span class="w"&gt; &lt;/span&gt;execunix.c&lt;span class="w"&gt; &lt;/span&gt;fileunix.c
builtins.c:33:23:&lt;span class="w"&gt; &lt;/span&gt;fatal&lt;span class="w"&gt; &lt;/span&gt;error:&lt;span class="w"&gt; &lt;/span&gt;sys/wait.h:&lt;span class="w"&gt; &lt;/span&gt;No&lt;span class="w"&gt; &lt;/span&gt;such&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;directory
compilation&lt;span class="w"&gt; &lt;/span&gt;terminated.
execunix.c:17:26:&lt;span class="w"&gt; &lt;/span&gt;fatal&lt;span class="w"&gt; &lt;/span&gt;error:&lt;span class="w"&gt; &lt;/span&gt;sys/resource.h:&lt;span class="w"&gt; &lt;/span&gt;No&lt;span class="w"&gt; &lt;/span&gt;such&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;directory
compilation&lt;span class="w"&gt; &lt;/span&gt;terminated.
fileunix.c:98:17:&lt;span class="w"&gt; &lt;/span&gt;fatal&lt;span class="w"&gt; &lt;/span&gt;error:&lt;span class="w"&gt; &lt;/span&gt;ar.h:&lt;span class="w"&gt; &lt;/span&gt;No&lt;span class="w"&gt; &lt;/span&gt;such&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;directory
compilation&lt;span class="w"&gt; &lt;/span&gt;terminated.
&lt;/pre&gt;&lt;/div&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Set output and installation directories and build.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BUILD_OUTPUT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/build/output
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BUILD_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;~/build/install
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BOOST_VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1_51_0
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BOOST_BUILD_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BUILD_OUTPUT_DIR&lt;/span&gt;/boost_&lt;span class="nv"&gt;$BOOST_VERSION&lt;/span&gt;
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BOOST_INSTALL_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BUILD_INSTALL_DIR&lt;/span&gt;/boost_&lt;span class="nv"&gt;$BOOST_VERSION&lt;/span&gt;
mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$BOOST_BUILD_DIR&lt;/span&gt;
mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$BOOST_INSTALL_DIR&lt;/span&gt;
./b2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;toolset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;--prefix&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BOOST_BUILD_DIR&lt;/span&gt;/build&lt;span class="w"&gt; &lt;/span&gt;install
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$PATH&lt;/span&gt;:&lt;span class="nv"&gt;$BOOST_BUILD_DIR&lt;/span&gt;/build/bin
&lt;/pre&gt;&lt;/div&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;strong&gt;mingw specific:&lt;/strong&gt; Comment out the following line ( around line 486 ) in tools/python.jam:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;python-cmd&lt;/span&gt; = &lt;span class="pre"&gt;&amp;quot;$(python-cmd)&amp;quot;&lt;/span&gt; ;&lt;/tt&gt; It's within this if block:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;jam&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="mi"&gt;17&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;NT&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Now that the boost build system is built and installed, time to build the actual boost library binaries.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$BOOST_SRC_ROOT&lt;/span&gt;
b2&lt;span class="w"&gt;  &lt;/span&gt;--build-dir&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BOOST_BUILD_DIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;toolset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;--prefix&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$BOOST_INSTALL_DIR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tee&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$BOOST_BUILD_DIR&lt;/span&gt;/build.log
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That will build static and shared non-debug multi-threaded variants of the libraries. To build all variants, pass the additional option, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--build-type=complete&lt;/span&gt;&lt;/tt&gt;&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Check the build log for errors, you should have 12 failures due to missing unicode/uversion.h which you can safely ignore ( some internal check for optional stuff that should be warnings ). At the end of the build process, you should have the boost libs installed in &lt;tt class="docutils literal"&gt;~/build/output/boost_1_51_0/lib&lt;/tt&gt; and headers in the boost subdir under &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;~/build/output/boost_1_51_0/include/boost-1_51&lt;/span&gt;&lt;/tt&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Header files in mingw are in nested one level deeper than in posix builds i.e. in posix the dir structure looks like &lt;tt class="docutils literal"&gt;$BOOST_ROOT/include/boost&lt;/tt&gt; and in mingw it's &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;$BOOST_ROOT/include/boost-1_51/boost&lt;/span&gt;&lt;/tt&gt;. So, when using boost in multi-platform builds like I do, you need to adjust your include path accordingly.&lt;/p&gt;
&lt;div class="section" id="posix-build-specifics-ubuntu-lts-12-04"&gt;
&lt;h2&gt;Posix Build Specifics ( Ubuntu LTS 12.04 )&lt;/h2&gt;
&lt;p&gt;To get boost to build without errors under Ubuntu LTS 12.04, you need to install the following additional libraries via apt-get:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;python-dev&lt;/li&gt;
&lt;li&gt;libbz2-dev&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; Added posix build info.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update 2012-10-30:&lt;/strong&gt; Fixed paths and added note to comment out line 489 in &lt;tt class="docutils literal"&gt;tools/python.jam&lt;/tt&gt;&lt;/p&gt;
&lt;/div&gt;
</content><category term="Technical"/><category term="programming"/><category term="boost"/><category term="mingw"/><category term="cpp"/></entry><entry><title>Compression is not a UI decision...</title><link href="https://vijay.varadan.com/talks/compression-is-not-a-ui-decision/" rel="alternate"/><published>2009-05-12T19:24:00-07:00</published><updated>2009-05-12T19:24:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2009-05-12:/talks/compression-is-not-a-ui-decision/</id><summary type="html">&lt;p class="first last"&gt;Architecture non-dilemma: Is compression a UI theme responsibility? Hint: NO!&lt;/p&gt;
</summary><content type="html">&lt;p&gt;One of the dilemmas that any software designer goes through is determining in
which subsystem a particular behavior needs to be implemented and whether it
should be user configurable or not. By user, I don't necessarily mean the only
end user; in the case of plugins or server software, I also refer to the people
installing / configuring the plugin or software.&lt;/p&gt;
&lt;p&gt;Read on to learn how I tracked down and fixed a 10X slowdown rendering
Wordpress content which was the result of a terrible design decision by a theme
designer.&lt;/p&gt;
&lt;p&gt;&lt;img alt="image0" src="https://vijay.varadan.com/talks/images/zip.jpg" /&gt;&lt;/p&gt;
&lt;p&gt;I'd been pondering about subsystem decomposition after I ran into horrendous
performance issues with a Wordpress theme I used for my imagery blog, which
uses shared hosting. A theme, for those not aware, is the UI customization that
can be applied to a piece of software to change its look and feel - there's no
added functionality provided i.e. they're not plugins. The theme in question is
&lt;a class="reference external" href="http://wp-grain.wiki.sourceforge.net/"&gt;Grain&lt;/a&gt; - a plugin specific theme, it
requires
&lt;a class="reference external" href="http://johannes.jarolim.com/blog/wordpress/yet-another-photoblog/"&gt;Yet Another Photo Blog&lt;/a&gt;.
When using the specific theme for YAPB, the pages would take about &lt;strong&gt;16-17
seconds&lt;/strong&gt; to render. Since I had to put both the theme and the plugin into
service at the same time, it took me some time to figure out where the problem
lay.&lt;/p&gt;
&lt;p&gt;After some head scratching, I replaced the Grain theme with another YAPB
compatible theme and the pages began rendering in the standard 2-3 seconds as
before. So, definitely a problem with the theme. I visited other sites,
including the theme author's that used the Grain theme. They rendered pretty
fast i.e. in under 2 seconds. So, something was off with my config. But what?
There were a number of places things could go wrong.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1:&lt;/strong&gt; would be to use &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Wget"&gt;wget&lt;/a&gt; to
retrieve a imagery blog page. Page came back in 1-2 seconds.  So, it seemed it
was not a problem with the page itself.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2:&lt;/strong&gt; Was it problem with the browser?  Firefox is my default. So, I
tried with IE. No dice. Still the same 16-17 seconds to render a page. What do
browsers do that wget does not? They send headers automatically.&lt;/p&gt;
&lt;p&gt;Great - time for &lt;strong&gt;step 3:&lt;/strong&gt; look into the browser headers. I installed the
Web developer plugin for Firefox. Yes, I know. Shame on me for not having it
installed already. Then I got &lt;a class="reference external" href="http://developer.yahoo.com/yslow/"&gt;YSlow&lt;/a&gt;.
Awesome debugging aid. Turns out it &lt;strong&gt;__was__&lt;/strong&gt; the page itself that was
taking up almost all of the 16-17 seconds. Examine the headers - request and
response headers look normal. The browser accepts gzipped and deflated content
and the server was sending back gzipped content. Except, the compressed content
was larger than the uncompressed content. Hmmm, that's odd. HTML compresses
very well due to repeated patterns, so something was definitely off. The one
time that content increases in size when compressed, is if it's
&lt;strong&gt;__already__&lt;/strong&gt; been compressed - which is why one never compresses .jpg,
.gif or .png files. Those formats are compressed internally. So, was there
double compression going on? If so, how the browsers were able to double
decompress is still a bit of a mystery to me, but that part was definitely
working. IE doesn't have any option to turn off compression. There's the
sledgehammer of disabling HTTP 1.1, but that's overkill. So, I continued w/
Firefox. You can change many, many options by typing &lt;tt class="docutils literal"&gt;about:config&lt;/tt&gt; in the
address bar. I disabled compressed content acceptance and viola - the imagery
blog pages began rendering within 2-3 seconds.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4:&lt;/strong&gt; Time to revert the Firefox setting and start fiddling with the
server. Easiest thing to do was disable compression for the imagery blog using
.htaccess - my imagery blog is on a shared host using Linux / Apache. So, I
proceeded to do what seemed to be the obvious, viz. add the following lines to
the .htaccess file of my imagery blog:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;ifModule mod_gzip.c&amp;gt;
    mod_gzip_on No
&amp;lt;/ifModule&amp;gt;
&lt;/pre&gt;
&lt;p&gt;But, that didn't work. So, hunted for another solution, which was to use
rewrite rules to disable gzip, to be added in the mod_rewrite.c section:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
RewriteRule . - [E=no-gzip:1]
&lt;/pre&gt;
&lt;p&gt;No, dice again. I had also added the following mod_expires section based on
YSlow recommendation and those changes were getting picked up when I looked at
the response headers:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;IfModule mod_expires.c&amp;gt;
    ExpiresActive On
    ExpiresDefault &amp;quot;access plus 1 seconds&amp;quot;
    ExpiresByType text/html &amp;quot;access plus 1 seconds&amp;quot;
    ExpiresByType image/gif &amp;quot;access plus 2592000 seconds&amp;quot;
    ExpiresByType image/jpeg &amp;quot;access plus 2592000 seconds&amp;quot;
    ExpiresByType image/png &amp;quot;access plus 2592000 seconds&amp;quot;
    ExpiresByType text/css &amp;quot;access plus 604800 seconds&amp;quot;
    ExpiresByType text/javascript &amp;quot;access plus 216000 seconds&amp;quot;
    ExpiresByType application/x-javascript &amp;quot;access plus 216000 seconds&amp;quot;
&amp;lt;/IfModule&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Hmmm. Something else which was doing the compression was slowing things down.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5:&lt;/strong&gt; A search for php compression revealed that there was support for
compression available in the standard php libraries. Bingo! Grepping for the
use of php compression showed a function in the theme that enabled it if there
was support available and if the (system wide) php.ini file had it enabled.
Ouch! Therein lay the issue. I couldn't muck with the system wide php.ini file,
since I was on a shared host. Php compression was slow, not sure why, but it
was SLOW. There were no configuration options to disable php compression in the
theme. So, the only way to do it was to modify the source code. I commented out
a few lines to disable php compression and viola, everything worked fine
thereafter.&lt;/p&gt;
&lt;p&gt;This was quite a hassle. The major lesson here is that &lt;strong&gt;compression is not a
UI component decision&lt;/strong&gt;: The biggest offender here in this debacle is the
Grain theme designer. Whether to use compression is not a decision for a UI
component to make. Essentially, the theme designer overstepped his/her
bounds. While, s/he may have added compression with the best interests and
keeping mind scenarios that s/he had encountered, the decision was definitely
wrong.&lt;/p&gt;
</content><category term="Technical"/><category term="architecture"/><category term="design"/><category term="layering"/></entry><entry><title>Linux - Always a bridesmaid, never a bride...</title><link href="https://vijay.varadan.com/talks/linux-always-a-bridesmaid-never-a-bride/" rel="alternate"/><published>2009-05-05T06:09:00-07:00</published><updated>2009-05-05T06:09:00-07:00</updated><author><name>Vijay Varadan</name></author><id>tag:vijay.varadan.com,2009-05-05:/talks/linux-always-a-bridesmaid-never-a-bride/</id><summary type="html">&lt;p class="first last"&gt;My misadventures trying to use Linux as a desktop OS. Facepalm time.&lt;/p&gt;
</summary><content type="html">&lt;p&gt;&lt;img alt="fedora-logo" src="https://vijay.varadan.com/talks/images/fedora-logo.png" /&gt;&lt;/p&gt;
&lt;p&gt;It had been a little over 4 years since I last tried out Linux. That experience
wasn't half bad, but I didn't get much in the way of use out of having Linux on
one of my boxes - I wasn't doing any Linux specific development and there
didn't seem to be any particular programs of quality that I wanted or needed to
run. One of my main uses of a computer is to play video games and Linux is a
&lt;em&gt;poor&lt;/em&gt; choice at best for video gaming compared to a Windows based machine. But
with my growing interest in the audio side of game development, I figured it
wouldn't be a bad time to give it another shot.&lt;/p&gt;
&lt;p&gt;I had read that there were quite a few programs worth trying out, some of which
are in use by semi-pros and amateurs in the field of digital audio / music
creation and synthesis. I first tried out Ubuntu 8.04 - it wasn't too bad, but
I ran into issues with the onboard network card - it just plain wouldn't work.
I spent several days troubleshooting, reading various manuals, howtos, guides,
forum posts, etc but no dice. I figured I ought to try out another distro
before throwing in the towel and going back to WinXP. So, it was onto Fedora
Core 10. Still no dice. I then slapped in a network card I scavenged off an
older machine, disabled the onboard network card and was off to the races.&lt;/p&gt;
&lt;p&gt;The installation was not too bad - odd thing was that it detected my PATA
harddisk as the primary disk and the SATA one as the secondary; this is the
opposite of what is specified for boot order in the BIOS and also different
from what is reported by WinXP during installation. Still, got past that
easily. The rest of the installation was pretty smooth and I had an FC10 Linux
box up and running. That's when the problems began.&lt;/p&gt;
&lt;div class="section" id="where-money-is-not-a-motivating-factor-ego-is"&gt;
&lt;h2&gt;Where Money is not a Motivating Factor, Ego is.&lt;/h2&gt;
&lt;p&gt;In the world of open source / free software, most folks don't typically get
paid to work on various projects - they do it primarily due to self-interest,
either altruistically or not. Either way, since there isn't much in the way of
monetary compensation, egos often tend to run amok. I saw a classic example of
this when I ran into issues with IPV6 on FC10. Here's the long and short of the
problem: One of the common libraries (glibc) that shipped with FC10 broke
compatibility with well known and commonly used existing programs (firefox,
wget, traceroute, etc) that are IPV6 aware. Essentially, name lookups would
fail resulting in these programs not working. You could get around that in
firefox by disabling IPV6 via an internal, hidden setting that most folks
wouldn't know about or couldn't figure out (since they couldn't get to the
internet) unless they had another computer. One would think that something as
fundamental as this would have been caught in QA, but one would be dead wrong.&lt;/p&gt;
&lt;p&gt;It wasn't that the issue was not pointed out; in fact, a beta user filed a bug
one whole month before the release highlighting the problem. It was brushed off
as an oddity by one of the core developers. Further more, the developer claimed
that the problem was not severe enough to be patched. There were about a dozen
folks clamoring to convince him with facts that the issue was severe and had to
be addressed immediately. See &lt;a class="reference external" href="https://bugzilla.redhat.com/show_bug.cgi?id=459756"&gt;this bug report&lt;/a&gt; for details (&lt;a class="reference external" href="https://vijay.varadan.com/talks/files/fc10-bug-459756-dns-resolver.pdf"&gt;PDF[1]&lt;/a&gt;), if
you have the patience to read through it. It's not that the developer is
&lt;em&gt;technically&lt;/em&gt; wrong - it's just that being technically right isn't the be-all
and end-all of it. If your software (the core applications for the OS) doesn't
work for your users, they're not going to use your OS. So, Linux loses.&lt;/p&gt;
&lt;p&gt;Some additional blemishes are that the solution to this bug is non-trivial -
certainly not something that someone without a fair amount of knowledge and
expertise could figure out. I'm not a Linux expert, but I consider myself
technically savvy and it took me more than a day to figure out that this was
the bug I was running into. Most folks were content to disable IPV6 in firefox
and get on with their lives. Before I forget, this bug renders the software
update programs (yum on FC10) inoperable. So, you can't use yum to get the fix.&lt;/p&gt;
&lt;p&gt;Here's what needs to happen to get the fix: First you must fix firefox, so you
can browse the web. You then need to locate the patched library
packages, which is like navigating a maze - in the dark... without any light...
and some minotaurs thrown in for good measure. Once you find &lt;a class="reference external" href="http://koji.fedoraproject.org/koji/buildinfo?buildID=73861"&gt;the patches page&lt;/a&gt;
(&lt;a class="reference external" href="https://vijay.varadan.com/talks/files/fc10-bug-459756-dns-resolver-patches-page.pdf"&gt;PDF[2]&lt;/a&gt;) that lists the packages, you have to figure out from some
other source(s) which of those patched packages actually apply to your
installation. No, it's not obvious. Once you figure that out, you download the
packages and install them using &lt;strong&gt;rpm&lt;/strong&gt; - not yum, but rpm. Then everything
starts working and you can get system updates, etc.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="would-your-mom-go-through-this"&gt;
&lt;h2&gt;Would Your Mom Go Through This?&lt;/h2&gt;
&lt;p&gt;Or the more obvious question - would you put your mom through this? I wouldn't
- my mom would kick my ass if I didn't get her computer working in 10 minutes,
maybe 15 if she felt generous. ;-)&lt;/p&gt;
&lt;p&gt;Yes, I know Windows has problems, but with money being a motivating factor,
Microsoft gets most things right for most people. WinXP is a very solid
operating system - was when it came out as well and has only gotten better.
Yes, Vista is a slightly different story, but if you were on the inside, you'd
know that most issues are due to bad drivers supplied by hardware vendors.
Besides, SP1 makes it a fabulous system to work with for the most part.&lt;/p&gt;
&lt;p&gt;Linux is just not ready to go mainstream for desktop use - not only because of
debilitating bugs, but because of the attitude of the some folks in the
development community towards its &lt;strong&gt;end&lt;/strong&gt; users. Sad.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;__Hot off the presses__:&lt;/strong&gt; The just-released Ubuntu 9.04 distro has the
&lt;a class="reference external" href="https://bugs.launchpad.net/fedora/+source/glibc/+bug/313218"&gt;same dns resolver bug&lt;/a&gt; (&lt;a class="reference external" href="https://vijay.varadan.com/talks/files/ubuntu-904-dns-resolver-bug.pdf"&gt;PDF[3]&lt;/a&gt;) too. Yay!&lt;/p&gt;
&lt;/div&gt;
</content><category term="Technical"/><category term="engineering"/><category term="dnsResolver"/><category term="linux"/></entry></feed>