<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[A Programmer's Journal]]></title><description><![CDATA[Thoughts, recipes and ideas about programming and life]]></description><link>https://manujbhatia.com/</link><image><url>http://manujbhatia.com/favicon.png</url><title>A Programmer&apos;s Journal</title><link>https://manujbhatia.com/</link></image><generator>Ghost 4.48</generator><lastBuildDate>Mon, 10 Nov 2025 11:08:56 GMT</lastBuildDate><atom:link href="https://manujbhatia.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Integrated DB Access from the Shell - Part 2]]></title><description><![CDATA[Seamlessly access Postgres (or, any other DB) from the shell as if the database is an integrated part of the shell.]]></description><link>https://manujbhatia.com/2020/04/13/db-access-part-2/</link><guid isPermaLink="false">5e8e1b08911dbd00014b8aaa</guid><category><![CDATA[ksh93]]></category><category><![CDATA[database]]></category><category><![CDATA[Data Processing]]></category><category><![CDATA[ksh]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Mon, 13 Apr 2020 08:31:01 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1533750204176-3b0d38e9ac1e?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1533750204176-3b0d38e9ac1e?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Integrated DB Access from the Shell - Part 2"><p>As discussed in <a href="http://manujbhatia.com/2020/04/08/integrate-db-access-into-the-shell/">part 1</a> of this series, we are trying to build an idiomatic way of accessing the database from the shell. Here is a quick snippet of how we want the code to look like:</p><pre><code class="language-bash">## Setting the DSN opens a DB connection
DSN=&quot;host=localhost port=5432 user=postgres password=123456&quot;
SELECT id, email from guest | while read id email
do
    valid=$((is_email_valid $email))
    echo &quot;$id&quot; &quot;$valid&quot;
done | UPDATE guest set is_valid = $2 where id = $1
## Unset the DSN to close the connection
unset DSN</code></pre><p>Ideally, we would write custom shell built-ins in C, so we get full control over each db api invocation, but to keep things simpler, let&apos;s look at doing this purely within the shell using <a href="https://docstore.mik.ua/orelly/unix/ksh/ch08_05.htm">co-processes</a>. All the samples here are written for <code>ksh93</code>, but should be easily adaptable to any other shell.</p><p>To achieve this, we will be tackling the following:</p><ol><li>Implement <a href="http://www.mtxia.com/js/Downloads/Scripts/Korn/discipline.shtml">discipline functions</a> for the <code>DSN</code> variable, so the DB connection is opened and closed when this variable is set and unset.</li><li>Launch the <code>psql</code> utility as a co-process from these discipline functions, so we can communicate with it using <code>print -p</code> and <code>read -p</code>.</li><li>Define <code>SELECT</code> and <code>INSERT</code> functions to use the co-process to execute the database operations. You can model <code>DELETE</code> and <code>UPDATE</code> based on these examples.</li></ol><figure class="kg-card kg-code-card"><pre><code class="language-bash">function DSN.set
{
   typeset db=&quot;${.sh.value}&quot;

   ## launch psql as a co-process
   psql -d &quot;$db&quot; -t |&amp;
   typeset pid=$!

   .sh.value=( db=&quot;$db&quot; pid=&quot;$pid&quot; )
}

function DSN.unset
{
   ## close the co-process pipe for writing
   exec p&gt;&amp;- p&lt;&amp;-
}
</code></pre><figcaption>DSN Discipline Functions</figcaption></figure><p><code>|&amp;</code> is the way to create a co-process. A co-process is just like any other background job, except it gets a set of i/o pipes that can be accessed from the current process using <code>read -p</code> and <code>print -p</code>.</p><p>To close the background co-process, we simply close the pipe <code>p</code> for i/o using the <code>&gt;&amp;-</code> and <code>&lt;&amp;-</code> commands.</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">function SELECT
{
   typeset q=&quot;SELECT $@;&quot;

   if [[ -t 1 ]]; then
      ## If outputing to the terminal, use the expanded output and page by default
      _dbq &apos;\x on
      \pset format aligned
      \pset tuples_only off&apos; &gt;/dev/null
      _dbq &quot;$q&quot; | ${PAGER:-less}
   else
      ## For output to a file/pipe, use the unload syntax
      _dbq &apos;\x off
      \pset format unaligned
      \pset tuples_only on&apos; &gt;/dev/null
      _dbq &quot;$q&quot; | while read -r x; do print -r &quot;$x|&quot;; done
   fi
}

## Execute the given DB query on the co-process and print the results
function _dbq
{
   typeset __DSNSEP=&quot;--DONE--&quot;
   print -p &quot;${@}&quot;
   print -p &quot;\echo ${__DSNSEP}&quot;

   while read -p row
   do
      [[ &quot;$row&quot; == &quot;$__DSNSEP&quot; ]] &amp;&amp; break
      print -r -- &quot;$row&quot;
   done
}</code></pre><figcaption>SELECT</figcaption></figure><p>The key with the <code>SELECT</code> function is to customize the behavior depending on where the output is going. For terminal output, we want to make it easier for the user to read. However, for a file or a pipe output, we want the data to be more machine-readable.</p><p>The key to note in the <code>_dbq</code> function is that you do not want to get stuck in a <code>read</code> from the co-process. For each <code>print -p</code>, we need to make sure that we <code>read -p</code> all the output, but not keep waiting for anything extra to avoid a deadlock.</p><p>Since each query can return an unknown number of records, we need a pre-defined marker to determine when the output of the query is complete. That is the purpose of the <strong><code>DNSSEP</code> </strong>command. We ask the <code>psql</code> co-process to echo it after each query. Then, in the read loop we break when we find the <code>$__DNSSEP</code>. This guarantees that we always read the necessary amount of data from the co-process.</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">function INSERT
{
   typeset q=&quot;INSERT $@&quot;

   if [[ -t 0 ]]; then
      ## If input is the terminal, execute the query as-is
      _dbq &quot;$q;&quot;
   else
      ## For input from a file/pipe, use the load syntax
      _load &quot;$q&quot;
   fi
}

function _load
{
   typeset q=&quot;$@ VALUES&quot;
   typeset -i commit_limit=${COMMIT_LIMIT:-100}
   typeset sql=&quot;$q&quot;
   typeset -i cnt=0
   typeset -a vals
   while read -A vals
   do
      sql+=&quot;(&quot;
      for val in ${vals[@]}
      do
         if [[ -z $val ]]; then
            sql+=&quot;NULL,&quot;
         else
            sql+=&quot;&apos;$val&apos;,&quot;
         fi
      done
      sql=&quot;${sql%,}&quot;    ## trim the trailing &apos;,&apos;
      sql+=&quot;),&quot;
      cnt=$((cnt+1))
      if ((cnt%commit_limit == 0)); then
         sql=&quot;${sql%,}&quot;
         _dbq &quot;$sql;&quot;
         ## Reset the query
         sql=&quot;$q&quot;
      fi
   done

   ## Catch anything left over
   if [[ $sql != $q ]]; then
      sql=&quot;${sql%,}&quot;
      _dbq &quot;$sql;&quot;
   fi
}
</code></pre><figcaption>INSERT</figcaption></figure><p>Similar to the <code>SELECT</code> function, we check if the input is from the terminal or a file/pipe. For terminal input, run the query as-is. For a file/pipe input, we want to read the values in from the input and process the records in batches using the <code>COMMIT_LIMIT</code>.</p><p>Here is how this all works from the command-line.</p><pre><code class="language-shell-session">$ DSN=&quot;host=localhost port=5432 user=postgres password=123456&quot;
$ echo $DSN
( db=host\=&apos;localhost port=5432 user=postgres password=123456&apos; pid=47325 )

$ SELECT \* from guest
-[ RECORD 1 ]------------
id       | 10
email    | xxx
is_valid | t
-[ RECORD 2 ]------------
id       | 1
email    | test@test.com
is_valid |
-[ RECORD 3 ]------------
id       | 2
email    | test@test.com
is_valid | f
(END)

$ SELECT \* from guest &gt; guest.dat
$ cat guest.dat
10|xxx|t|
1|test@test.com||
2|test@test.com|f|

$ DELETE from guest

$ IFS=\| INSERT INTO guest &lt; guest.dat
INSERT 0 3

$ SELECT count\(\*\) from guest
-[ RECORD 1 ]
count | 3

(END)
</code></pre><p>In the next post, we will see how we can implement these functions as <code>C</code> builtins and enable a lot more sophisticated functionality.</p>]]></content:encoded></item><item><title><![CDATA[Reference Counting in C]]></title><description><![CDATA[A simple and light-weight way to implement Reference Counting in a C program.]]></description><link>https://manujbhatia.com/2020/04/11/reference-counting-in-c/</link><guid isPermaLink="false">59af9d66dac8930001351cd5</guid><category><![CDATA[C]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Sat, 11 Apr 2020 06:10:53 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1548175551-1edaea7bbf0d?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1548175551-1edaea7bbf0d?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Reference Counting in C"><p>Ever since computer programming has been around, the problem of dynamic memory management has plagued many a programs.</p><p>Now a days most programming languages rely on either <a href="https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)">Garbage Collection</a> or <a href="https://en.wikipedia.org/wiki/Reference_counting">Reference Counting</a>, but what is a C programmer to do?</p><p>Turns out, there is no magic to reference counting, it literally is what it sounds like. Each piece of memory has a counter to how many references it has. Each function that wants to keep the value outside of the given scope, should <code>retain</code> the value, and once it&apos;s done with it <code>release</code> it.</p><p>You can easily create thin wrappers around your allocation modules to build this capability.</p><p>Of course, without the help from the compiler, you cannot do <a href="https://en.wikipedia.org/wiki/Automatic_Reference_Counting">Automatic Reference Counting (ARC)</a>, and need to make sure your code properly calls <code>retain</code> and <code>release</code> and also avoid <a href="https://en.wikipedia.org/wiki/Reference_counting#reference_cycle">retention cycles</a>.</p><pre><code class="language-c">// A header for each memory block
typedef struct MEMHDR {
	int retain_cnt;
} MEMHDR;

#define MEMHDR_SIZ	     ALIGN(sizeof(MEMHDR))
#define MEMHDR_PTR(ptr)  ((MEMHDR *)((char *)(ptr) - MEMHDR_SIZ))

// align the size to word-boundry
#define ALIGN(siz)       ((siz) + sizeof(int) - ((siz) % sizeof(int)))

// Allocate extra header at the head of the memory pointer,
// but return the offset pointer.
// This gives you an internal header to maintain any attributes
// for this block of memory
#define allocate(siz) ((char *)malloc(MEMHDR_SIZ + ALIGN(siz))) + MEMHDR_SIZ))

// Simply increment ths retention counter and return the original pointer
// Allows the use like this:
//   str1 = retain(str)
#define retain(ptr)   (MEMHDR_PTR(ptr)-&gt;retain_cnt++, ptr)

// Release is a little more involved.
// decrement the retention counter and free the block,
// if the retain_cnt is zero
#define release(ptr)  ( \
	--(MEMHDR_PTR(ptr)-&gt;retain_cnt), \
    MEMHDR_PTR(ptr)-&gt;retain_cnt \
    	?ptr \
        :(free(ptr),NULL) \
)
</code></pre><p>Essentially, all we are doing is prepending a header to each piece of allocated memory and tracking a <code>retain_cnt</code> variable in it. When the <code>retain_cnt</code> hits zero, we will <code>free</code> the block.</p><p>Let&apos;s see how you would use this with an example. We will build an API to read a file.</p><figure class="kg-card kg-code-card"><pre><code class="language-c">typedef struct FILER {
    FILE *fd;
    char *buf;
} FILER;

FILER * filer_open(const char *path) {
    FILE *fd = fopen(path, &quot;r&quot;);
    FILER *filer = allocate(sizeof(FILER));
    filer.fd = fd;
    return filer;
}

void filer_close(FILER *filer) {
    fclose(filer-&gt;fd);
    if (filer-&gt;buf)
        release(filer-&gt;buf);
}

char * filer_read(FILER *filer) {
    if (!filer-&gt;buf)
        filer-&gt;buf = allocate(BUFSIZ);
    fgets(filer-&gt;buf, BUFSIZ, filer-&gt;fd);
    return filer-&gt;buf;
}

</code></pre><figcaption>filer.c</figcaption></figure><figure class="kg-card kg-code-card"><pre><code class="language-c">int main(void) {
    FILER *f = filer_open(&quot;/home/user/.profile&quot;);

    char *line = filer_read(f);
    char *first_line = retain(line);

    filer_close(f);

    // first_line is still valid here

    ...

    // clean up
    release(first_line);
}</code></pre><figcaption>main.c</figcaption></figure><p>As you can see in this example, a major side-benefit of using reference counting is the locality of memory operations. Both <code>filer.c</code> and <code>main.c</code> have equal numbers of <code>allocate/retain</code> and <code>release</code>, making reviewing the code for memory leaks very easy.</p><p>That&apos;s all there is to it!</p>]]></content:encoded></item><item><title><![CDATA[Integrated DB Access From the Shell]]></title><description><![CDATA[Dealing with databases from Shell scripts has always been clunky. Using custom shell built-ins we can develop an idiomatic, safe , and performant way of accessing the db from the Shell.]]></description><link>https://manujbhatia.com/2020/04/08/integrate-db-access-into-the-shell/</link><guid isPermaLink="false">5e8d03e2911dbd00014b892c</guid><category><![CDATA[database]]></category><category><![CDATA[Data Processing]]></category><category><![CDATA[shell scripting]]></category><category><![CDATA[ksh93]]></category><category><![CDATA[ksh]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Wed, 08 Apr 2020 19:08:35 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1468070454955-c5b6932bd08d?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1468070454955-c5b6932bd08d?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Integrated DB Access From the Shell"><p>One of the main things I do in my scripts regularly is work with databases using their cli.</p><pre><code class="language-bash">psql -d &quot;$DSN&quot; -t -c &quot;select id, email from guest&quot; | while IFS=\| read id email
do
    valid=$((is_email_valid $email))
    psql -d &quot;$DSN&quot; -t -c &quot;update guest set is_valid=&apos;$valid&apos; where id=$id&quot;
done</code></pre><p>Even though this is clunky, for a one-off script iterating on a few records, this approach works. It does not scale, however, due to violating the <a href="http://manujbhatia.com/2010/06/15/golden-rule-for-super-fast-shell-scripts/">golden rule</a>.</p><p>Some of the problems with this approach are:</p><ol><li><em>Ripe for <a href="https://en.wikipedia.org/wiki/SQL_injection">SQL-injection</a> attack</em>. We are essentially building SQL queries by string concatenation like the early 2000s and are prone to SQL-injection attacks as a result.</li><li><em>Poor DB Performance</em>. No prepared queries and persistent DB connections means, each update will have to establish a new DB connection and prepare/execute the query.</li><li><em>No transaction control</em>. Since each update is forced to establish a new DB connection, you effectively cannot batch updates.</li><li><em>Poor Scaling</em>. Since each update has to launch a child process, the overhead for a large input set piles up quickly and will almost become unworkable for a production issue.</li><li><em>Database Driver is Hard-Coded</em>. Try changing the database driver from <code>psql</code> to <code><a href="http://www.unixodbc.org/">isql</a></code> and you end up doing a lot of manual refactoring of the code base.</li><li><em>Not easily usable interactively</em>. Using the native db utilities in this way is not very comfortable for a terminal user. For example, I might want the headers and labels if I am outputting to my terminal, but would want a CSV when redirecting to a file. As a user, I would need to remember the flags for each of those operations.</li></ol><p>This approach also does not yield well to idiomatic shell scripting. Here is my attempt to do this in an idiomatic way.</p><pre><code class="language-shell">DSN=&quot;postgres&quot;
SELECT id, email from guest | while read id email
do
    valid=$((is_email_valid $email))
    echo &quot;$id&quot; &quot;$valid&quot;
done | UPDATE guest set is_valid = $2 where id = $1</code></pre><p>This relies on the capability of modern shells to define custom <a href="https://docs.oracle.com/cd/E36784_01/html/E36870/builtin-1.html#scrolltoc">built-ins</a>. Combine this with <a href="https://docs.oracle.com/cd/E36784_01/html/E36870/trap-1.html#scrolltoc">KEYBD traps</a> and you can do some fun things interactively too.</p><pre><code class="language-shell-session"># Download the results to a csv file
$ OFS=, SELECT \* from guest &gt; guest.csv
2 rows selected

$ cat guest.csv
1,test@test.com,Y
2,test1@test.com,N

# Delete the data
DELETE from guest
2 rows deleted

# Bulk load data from a csv file
$ IFS=, INSERT into guest &lt; guest.csv
2 rows inserted

# Dump data on the terminal from a query
# (will automatically use PAGER to give a sane user-experience)
$ SELECT \* from guest

id          1
email       test@test.com
is_valid    Y

id          2
email       test1@test.com
is_valid    N

2 rows deleted
</code></pre><p>Here is the keyboard trap I use with <code>ksh</code> to make typing these commands on the keyboard convenient and auto-escaping some of the special characters.</p><pre><code class="language-bash">## The trap to use for keyboard bindings (KEYBD) to properly escape SQL queries
function db_keybd
{
   ##############################################
   ## In the code below type Ctrl-V+Esc for ^[ ##
   ##############################################   
   if [[ ${.sh.edchar} == &apos; &apos; ]]; then
      ## Make the keyword consistent case,
      ## so you are not forced to type all upper-case for the keywords
      if [[ ${.sh.edtext} == [sS][eE][lL][eE][cC][tT] ]]; then
         .sh.edchar=&quot;^[0cwSELECT&quot;
      elif [[ ${.sh.edtext} == [uU][pP][dD][aA][tT][eE] ]]; then
         .sh.edchar=&quot;^[0cwUPDATE&quot;
      elif [[ ${.sh.edtext} == [dD][eE][lL][eE][tT][eE] ]]; then
         .sh.edchar=&quot;^[0cwDELETE&quot;
      elif [[ ${.sh.edtext} == [iI][nN][sS][eE][rR][tT] ]]; then
         .sh.edchar=&quot;^[0cwINSERT&quot;
      fi
   fi

   ## Escape the special characters, unless it is already escaped
   [[ ${.sh.edchar} == &apos;*&apos; || ${.sh.edchar} == $&apos;\&apos;&apos; || ${.sh.edchar} == &apos;&quot;&apos; || ${.sh.edchar} == &apos;(&apos; || ${.sh.edchar} == &apos;)&apos; ]] \
      &amp;&amp; [[ ${.sh.edtext} == @(SELECT|UPDATE|DELETE|INSERT)\ * ]] \
      &amp;&amp; [[ ${.sh.edtext:$((.sh.edcol-1)):1} != \\ ]] \
         &amp;&amp; .sh.edchar=\\${.sh.edchar}
}

trap db_keybd KEYBD</code></pre><p>In part 2 of this post we will look at how to develop the plugins to implement the actual functions.</p>]]></content:encoded></item><item><title><![CDATA[Let's Write a New Shell - Part 1]]></title><description><![CDATA[<p>In this series of posts, I&apos;ll make a case that Shell scripts are not used enough in mainstream data processing pipelines, what are the reasons behind that, and how we should develop a new shell based on Golang to address those issues.</p><h1 id="data-processing-pipelines">Data Processing Pipelines</h1><p>I have always</p>]]></description><link>https://manujbhatia.com/2020/04/07/lets-write-a-new-shell/</link><guid isPermaLink="false">5e8cd1e3911dbd00014b87ba</guid><category><![CDATA[shell scripting]]></category><category><![CDATA[utility]]></category><category><![CDATA[Data Processing]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Tue, 07 Apr 2020 21:13:03 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1493147380900-672b878fe69e?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1493147380900-672b878fe69e?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Let&apos;s Write a New Shell - Part 1"><p>In this series of posts, I&apos;ll make a case that Shell scripts are not used enough in mainstream data processing pipelines, what are the reasons behind that, and how we should develop a new shell based on Golang to address those issues.</p><h1 id="data-processing-pipelines">Data Processing Pipelines</h1><p>I have always been a big fan of Unix shell pipelines. I think they are a fantastic way to write rapid data processing pipelines.</p><p>Of course, there are many design patterns to present processing pipelines in mainstream languages. Look at this example of a simple pipeline from <a href="https://doc.akka.io/docs/akka/current/stream/stream-parallelism.html#pipelining">Akka Streams:</a></p><figure class="kg-card kg-code-card"><pre><code class="language-java">  // #pipelining
  Flow&lt;ScoopOfBatter, HalfCookedPancake, NotUsed&gt; fryingPan1 =
      Flow.of(ScoopOfBatter.class).map(batter -&gt; new HalfCookedPancake());

  Flow&lt;HalfCookedPancake, Pancake, NotUsed&gt; fryingPan2 =
      Flow.of(HalfCookedPancake.class).map(halfCooked -&gt; new Pancake());
  // #pipelining

  @Test
  public void demonstratePipelining() {
    // #pipelining

    // With the two frying pans we can fully cook pancakes
    Flow&lt;ScoopOfBatter, Pancake, NotUsed&gt; pancakeChef = fryingPan1.async().via(fryingPan2.async());
    // #pipelining
  }</code></pre><figcaption>Akka Stream Pipeline Example</figcaption></figure><p>Or, an example from <a href="https://github.com/apache/beam/blob/master/sdks/go/examples/minimal_wordcount/minimal_wordcount.go">Apache Beam</a> data processing:</p><figure class="kg-card kg-code-card"><pre><code class="language-go">var wordRE = regexp.MustCompile(`[a-zA-Z]+(&apos;[a-z])?`)

func main() {
	// beam.Init() is an initialization hook that must be called on startup.
	beam.Init()

	// Create the Pipeline object and root scope.
	p := beam.NewPipeline()
	s := p.Root()

	// Apply the pipeline&apos;s transforms.

	// This example reads a public data set consisting of the complete works
	// of Shakespeare.
	lines := textio.Read(s, &quot;gs://apache-beam-samples/shakespeare/*&quot;)

	words := beam.ParDo(s, func(line string, emit func(string)) {
		for _, word := range wordRE.FindAllString(line, -1) {
			emit(word)
		}
	}, lines)

	counted := stats.Count(s, words)

	formatted := beam.ParDo(s, func(w string, c int) string {
		return fmt.Sprintf(&quot;%s: %v&quot;, w, c)
	}, counted)

	textio.Write(s, &quot;wordcounts.txt&quot;, formatted)

	// Run the pipeline on the direct runner.
	direct.Execute(context.Background(), p)
}</code></pre><figcaption>Apache Beam Minimal Wordcount Example</figcaption></figure><p>Something similar in a shell script would look like this:</p><figure class="kg-card kg-code-card"><pre><code class="language-bash">scoop &lt; batter | cook_pancake_side | flip_to_other_pan | cook_pancake_side &gt; plate</code></pre><figcaption>Cook a Pancake in a Shell Script</figcaption></figure><p>Or, this for the word count:</p><figure class="kg-card kg-code-card"><pre><code class="language-bash"># Split text into words
function words
{
    while IFS=\ \n\t read -A line
    do
      for word in ${line[*]}
      do
         print &quot;$word&quot;
      done
    done
}

gsutil cat &quot;gs://apache-beam-samples/shakespeare/*&quot; | words | sort | uniq -c</code></pre><figcaption>Shell Word Count</figcaption></figure><p>As you can see, the shell pipeline is more precise and expressive on what the inputs &amp; outputs are, and what is happening in the processing.</p><h1 id="limitations-of-shell-pipelines">Limitations of Shell Pipelines</h1><p>Even though shell pipelines are very expressive and easy to write, there are several limitations when it comes to using them for complex data pipelines:</p><ol><li><em>Lack of structured data</em>. All data in a pipeline is a blob. If your data source is a <code>SELECT</code> query, you have to combine all fields of a row into a blob that is specific to your program before passing it to the next step in the pipeline. To work effectively with structured data, each program is required to be aware of which program it pipes to/from, which violates the universal principle of independent utilities combining to produce more sophisticated programs in Unix.</li><li><em>No type-safety</em>. All data in a shell pipeline is treated as a byte stream, typically a string. This again causes the programs to continually cast the input and output values and increases the risk of a run-time type error.</li><li><em>No compatibility check</em>. <code>echo Hello | ls</code> is a perfectly valid stream syntactically even though semantically it makes no sense.</li><li><em>No fan-in, fan-out</em>. You can linearly represent much of data processing, but there are always crucial use-cases where you need to either fan-out an input or fan-in an output. The shell pipelines lack this capability.</li><li><em>Lack of multi-threading</em>. Each step of the pipeline is run in an independent OS process, making invoking a pipeline an expensive operation. Although this overhead is usually not a problem for long-running pipelines, it can make the use of short-lived pipelines prohibitive. Also, in a fan-in/fan-out scenario, it is challenging to scale a process-model compared to a thread/co-routine/actor-based model.</li></ol><p>In the next post, we will focus on how we can enhance the syntax of a shell pipeline to handle some of these issues.</p>]]></content:encoded></item><item><title><![CDATA[When Preparation Meets Adversity]]></title><description><![CDATA["Luck is when preparation meets opportunity." All of us have heard this phrase at some point in our life. But what happens when preparation meets adversity??]]></description><link>https://manujbhatia.com/2020/04/07/when-preparation-meets-adversity-2/</link><guid isPermaLink="false">5e8cbf73911dbd00014b87a9</guid><category><![CDATA[philosophy]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Tue, 07 Apr 2020 18:38:34 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1495900158145-fa1e1786861b?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<blockquote>Luck is when preparation meets opportunity.</blockquote><img src="https://images.unsplash.com/photo-1495900158145-fa1e1786861b?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=2000&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="When Preparation Meets Adversity"><p>All of us have heard this phrase at some point in our life. But what happens when preparation meets adversity??</p><p>I had a taste of this a couple of years ago when I was on my annual working vacation stint at my parents&apos; home in India. I had just been rejected from a job I was confident I would get. I was bored and struggling to complete even the most basic tasks at my current job. My stress level was off the charts, and even though I was physically with my family, I was never there mentally. It was one of the lowest points of my adult life.</p><p>Usually, my biggest weapons against stress used to be Diet Coke, ice cream, and Food.</p><p>Now the year before this incident, I had realized how bad my dependence on Diet Coke was and had stopped using it. And, at this time, I was also Icecream-free for a few months for similar reasons. Both those things were not easy, but I was very determined to stick to my guns on staying off of them.</p><p>Not being at my own house, I did not have any of my other coping mechanisms available to me either. I could not go for a drive, go to the gym, read my favorite books, or watch my American TV shows.<br>And even though I don&apos;t drink to deal with stress, I could not have a single drink to unwind, owing to some health issues at the time.</p><p>That left food as the only alternative. However, being at my parents&apos; house meant that I was at a more structured regimen of 3-square meals a day and no access to my usual comfort foods.</p><p>All this forced me to think hard about my stress and tackle the real sources of that stress. For example, I squared with my project manager about my productivity and took some actual time off to enjoy with my family.</p><p>Cut to a couple of months after I came back home, and I realized I had been losing weight without any change to my non-existent exercise schedule! Upon some closer analysis, I discovered that my appetite had drastically reduced. I was not indulging with food, and would usually stop eating if I was not enjoying it (which was a polar opposite of my earlier self, who never cared how the food tasted).</p><p>That experience altered my relationship with food for the better. As a result, I lost 30 pounds in the following 6-months in a very healthy and sustainable manner (getting to a healthy weight has been a life long goal of mine).</p><p>In that moment of suffering, I could not see any silver lining. Reflecting on that time, however, I can see that had I not worked hard to stop my Diet Coke and ice cream habits before that incident, this change in my food habits would not have happened.</p><p>As I type this blog post, the whole world is dealing with probably the most significant adversity we ever faced caused by the Coronavirus. We are afraid, stuck away from family, losing jobs, and maybe the worst, losing hope.</p><p>I promise you that you are prepared to handle this adversity in some way that you don&apos;t yet realize. At some point in your life, you will look back and find out that this incident caused you to change your life for the better.</p><p>Keep working hard on yourself and your goals, and stay safe!</p>]]></content:encoded></item><item><title><![CDATA[Behavioral Impact of Tracking Metrics: Loading vs. Unloading a Dishwasher]]></title><description><![CDATA[<blockquote>TL;DR</blockquote><blockquote>Don&apos;t look at a metric just at it&apos;s face value; dig deeper and question the behavior promoted by tracking that metric.</blockquote><p>Metrics. The be-all and end-all of any IT ops team and something that most IT executive leaders track on a weekly, if not</p>]]></description><link>https://manujbhatia.com/2018/12/04/tracking-the-right-metrics-loading-or-unloading-a-dishwasher/</link><guid isPermaLink="false">5c060bec9835c80001df1229</guid><category><![CDATA[philosophy]]></category><category><![CDATA[DevOps]]></category><category><![CDATA[optimization]]></category><category><![CDATA[metrics]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Tue, 04 Dec 2018 07:46:18 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1535968541517-44f420ac7c6c?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" medium="image"/><content:encoded><![CDATA[<blockquote>TL;DR</blockquote><blockquote>Don&apos;t look at a metric just at it&apos;s face value; dig deeper and question the behavior promoted by tracking that metric.</blockquote><img src="https://images.unsplash.com/photo-1535968541517-44f420ac7c6c?ixlib=rb-1.2.1&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ" alt="Behavioral Impact of Tracking Metrics: Loading vs. Unloading a Dishwasher"><p>Metrics. The be-all and end-all of any IT ops team and something that most IT executive leaders track on a weekly, if not daily, basis.</p><p>I like that lately a lot more traditionally non-tech companies are focusing on metrics to increase efficiencies throughout the software life cycle. However, one thing I notice missing is an informed discussion on not only what metrics are important, but <em>what metrics promote the desired behavior in the teams</em>.</p><h1 id="to-load-or-unload-that-is-the-question-">To Load or Unload, that is the Question!</h1><p>To illustrate the importance of this point, lets look at a very simple regular life example of dishwashing.</p><p>Let&apos;s say you live with a roommate, and you need to divvy up the responsibility of dishwashing. A very reasonable thing to do is to alternate the responsibility between the two of you. Now the question is how do you track who did the dishes last. Most people will probably go by <em>&quot;Who loaded and ran the dishwasher last?&quot;</em>. I argue that <em>it is the wrong metric</em>. Not because it does not track the effort properly, but it promotes the wrong behavior. The correct metric to track should be <em>&quot;Who unloaded the dishwasher last?&quot;</em>.</p><h2 id="who-loaded-the-dishwasher-last">Who loaded the dishwasher last?</h2><p>First, lets look at the behavior it promotes:</p><ol><li>Once you have loaded and ran the dishwasher, you have no incentive to unload it.</li><li>Since, you are not unloading it, usually you end up having clean utensils in the dishwasher and just pulling out what&apos;s necessary.</li><li>This leads to the dirty dishes sitting in the kitchen sink till the dishwasher is organically emptied.</li><li>Also, its in your self-interest to load and run the dishwasher before its completely full, so you effectively have to rinse and load less dishes.</li></ol><p>So, the net effect is two-fold:</p><ol><li>Your kitchen sink is usually full of dirty dishes.</li><li>You pay higher energy costs, since dishwasher is not always run completely full.</li></ol><h2 id="who-unloaded-the-dishwasher-last">Who unloaded the dishwasher last?</h2><p>Again, looking at the behavior this promotes:</p><ol><li>The dishwasher usually always have dirty dishes in it.</li><li>Since the dishwasher is mostly on dirty, the dishes get rinsed and put in right away, instead of sitting in the kitchen sink.</li><li>There is no incentive to run the dishwasher early, so it gets run when its needed.</li></ol><p>As you can see out of the two metrics, if you only wanted to track one, tracking unloads promotes better behavior!</p><h1 id="tracking-software">Tracking Software</h1><p>Now lets take this example into the IT field. Couple of the most commonly tracked and cited metrics are:</p><ol><li>Number of Priority 1 (P1) tickets.</li><li>Number of Failed Change Requests (CR).</li></ol><h2 id="p1s">P1s</h2><p>Tracking number of P1s inherently is not bad, but when it becomes the primary factor in determining the stability and performance of a team, then its crosses a line into promoting bad behavior.</p><p>Here is what happens when the executive leadership of an IT department start monitoring P1s closely:</p><ol><li>The ops teams start down-grading P1s to P2s or even P3s.</li><li>Issues reported by business users directly sometimes don&apos;t even make it to the official ticket tracking system and just resolved off-the-books.</li></ol><h2 id="failed-crs">Failed CRs</h2><p>Tracking failed CRs basically sounds like a good metric, but in reality is probably worse than tracking P1s. Lets analyze what behavior we promote by doing this:</p><ol><li>The overall amount of paperwork done for CRs goes through the roof. Because if any CR fails, the &quot;remediation&quot; meeting will usually dissect the paperwork and not the true root cause of the failure, so everyone tries to cover their rear-ends.</li><li>There is an unreasonable amount of testing that starts happening; for the exact same reason as above. IF this CR fails, you don&apos;t want to be the guy who didn&apos;t do <em>enough</em> testing of your change. So, even a simple change to reduce the amount of data retained by a purge process has to go through multiple rounds of testing by a separate QA team.</li><li>The worst affect of all this is the delivery cycles just get longer, as all your dev and ops teams are worried about bureaucracy and distracted from the real things that matter, like <em>taking calculated risks to deliver business value as fast as possible</em>.</li></ol><h2 id="the-correct-metric-system-uptime">The Correct Metric: System Uptime</h2><p>I would argue that tracking System Uptime, both planned as well as unplanned, is a far more useful metric than the number of P1s and failed CRs.</p><p>First, unplanned downtime is a good indicator of P1s that matter. Since each P1 is not created equal (a crashed load balancer that took your whole website offline, is a lot worse than a rogue service instance, causing 5% of your call-center agents not to be able to book a room on the first try). Tracking system downtime, gives you a more normalized view of the problem than the number of P1s.</p><p>Second, it takes the pressure off the devs to have the paperwork to the tee; it focuses them on making sure their CR will not cause any downtime. No matter whether the actual CR needs to be rolled back, as long as the dev took proper precautions to ensure no downtime, everything is good. It also encourages your team to build more resilient architectures, hot swappable service instance, rolling upgrades, automated deployments/rollbacks etc.</p><h1 id="conclusion">Conclusion</h1><p>As I have put forth the case here, there could be devastating affects of tracking wrong metrics on your organization&apos;s speed and effectiveness.</p><p>Tracking the wrong metrics not just reduces the effectiveness of your data-driven decision making, it actively undermines the productivity and efficiency of your teams.</p><p>Think long and hard the next time you want to tie the performance bonus of your team to the reduction in number of P1s, unless you want your organization to become like the Japanese Police department<sup>[<a href="#japanese-police-1">1</a>][2]</sup>.</p><p></p><!--kg-card-begin: html--><p>
    <a name="japanese-police-1">1.</a>http://articles.latimes.com/2007/nov/09/world/fg-autopsy9
    <br>
    <a name="japanese-police-2">2.</a>https://www.vox.com/world/2015/12/13/9989250/japan-crime-conviction-rate
</p><!--kg-card-end: html-->]]></content:encoded></item><item><title><![CDATA[Rockets and the Human Condition]]></title><description><![CDATA[What can humans learn from rockets on how to overcome adversity and achieve new heights?]]></description><link>https://manujbhatia.com/2018/02/24/you-have-to-go-through-shit-to-improve-your-life/</link><guid isPermaLink="false">5a91a6c480f7880001f85016</guid><category><![CDATA[philosophy]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Sat, 24 Feb 2018 23:56:30 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1517976487492-5750f3195933?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=9e99add764dc1e7ca9db187ec0fa82cb" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1517976487492-5750f3195933?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=9e99add764dc1e7ca9db187ec0fa82cb" alt="Rockets and the Human Condition"><p>I have been watching a lot of SpaceX launches<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup> lately and one thing that amazes me is how easy it looks from the outside for the Rocket to break through the Earth&apos;s gravity and get to the orbit. In reality, it goes through immense pressure and stress to reach the orbit. Once in the orbit though, it&apos;s almost effortless for the satellite to stay up there.</p>
<p>I could not help but see parlance of this behavior in the human struggle to better themselves.<br>
Think of the satellite as a human being who is trying to change her<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup> circumstances (professional or personal). Earth is her current reality and the orbit is her dream.</p>
<p>To make her dream a reality, she has to work through similar stresses and pressures to break through the gravity of her current situation. Unsupportive spouse or parents, social pressures, risking a secure life at times to count just a few.</p>
<p>However, if she makes it through that high-stress period without <a href="https://youtu.be/WTVkhp0MxMc">imploding or exploding</a>, after a while all the stresses and pressures disappear. What remains is the freedom to navigate life with minimal effort.</p>
<blockquote>
<p>You cannot jump from one stable state of your life to a higher stable state, without going through a lot of pressure and stress.</p>
</blockquote>
<p>If you want that new job that you do not qualify for, but can&apos;t learn that skill as you have a full-time job already, you have to give up on sleep and other leisurly activities for some time, while you transition to that new job.</p>
<p>Want to lose weight but are always tired and barely scraping by getting all your daily duties done. You will have to dig deep and find that will-power to power through an exercise schedule for a few weeks, before you start feeling more energetic due to all that exercising and become more efficient in your daily tasks.</p>
<p>The other key factor in a successful launch is the <a href="https://en.wikipedia.org/wiki/Booster_(rocketry)">booster</a>. It helps the satellite power through the early stages of the flight when the external factors are the strongest.<br>
Similarly, we humans need a good support system of family and friends if we ever hope to break through our current realities and achieve new heights.</p>
<p>In short, success does not come easy. Keep your friends and family close and keep fighting the negative forces; they will evetually disappear and life will become easier again.</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p>If you have not seen any of the Falcon launches from SpaceX, I highly recommend you check out the <a href="https://youtu.be/wbSwFU6tY1c?t=21m27s">Falcon Heavy test flight</a> and watch through to the landing. <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p>I am not a feminist in any practical sense, and I just got tired of typing &quot;his/her&quot; everywhere. Considering that &quot;him&quot; got to represent mankind for so long in our literature, I think its time for us to switch gears and let &quot;her&quot; be a representative of all mankind for a while. <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[What is Something Worth?]]></title><description><![CDATA[Would you ever pay someone more than they make for you?]]></description><link>https://manujbhatia.com/2018/02/21/what-is-something-worth/</link><guid isPermaLink="false">5a8cdad080f7880001f8500b</guid><category><![CDATA[philosophy]]></category><category><![CDATA[economics]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Wed, 21 Feb 2018 02:54:43 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1518183214770-9cffbec72538?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=59b4ffaaec7683aa907e09bd20e72f5b" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<img src="https://images.unsplash.com/photo-1518183214770-9cffbec72538?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=59b4ffaaec7683aa907e09bd20e72f5b" alt="What is Something Worth?"><p>Stay tuned to find out which of these Bobbleheads is worth five thousand dollars.</p>
</blockquote>
<p>This was the teaser of a news report about Bobbleheads distributed at a football game showing up on e-bay that I saw this morning.<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup></p>
<p>It got me thinking. What is something worth? Is it what someone wants for it or what someone is willing to pay for it?</p>
<p>I happen to be in the latter camp. The iPhone is pricier than almost any other phone because people are willing to pay for that luxury.</p>
<blockquote>
<p>The worth of something is what someone is willing to pay for it.</p>
</blockquote>
<p>Now, there is a corollary to this rule when it comes to humans though.</p>
<blockquote>
<p>You are always worth more than what someone is willing to pay for you.</p>
</blockquote>
<p>Why is that you ask? It really comes down to basic economics.</p>
<p>Whenever you transact, whether to buy an object or time from another human, you always pay a little less than it is really worth, so you can derive some value from that transaction for yourself.</p>
<p>You spend that money on an iPhone because you think it will enrich your life more than what you pay for it in dollars.</p>
<p>In case of employing someone, you will always pay someone a little less than what they are worth to you, so you can pocket the rest as a profit.</p>
<p>So next time you go out for a job interview or ask for a raise, remember:</p>
<blockquote>
<p>You are worth more!</p>
</blockquote>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="https://www.ebay.com/i/112825450022">eBay Listing</a> <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Bitcoin vs. Gold: Store of Value]]></title><description><![CDATA[This is not a fact-based essay; it is my philosophical argument against Bitcoin being a true store of value. I argue for your Bitcoin to hold its value, how someone has to keep doing work after its mined.]]></description><link>https://manujbhatia.com/2018/02/18/bitcoin-vs-gold-store-of-value/</link><guid isPermaLink="false">5a885bda80f7880001f84ff5</guid><category><![CDATA[bitcoin]]></category><category><![CDATA[gold]]></category><category><![CDATA[economics]]></category><category><![CDATA[philosophy]]></category><category><![CDATA[crypto]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Sun, 18 Feb 2018 00:29:05 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1518544801976-3e159e50e5bb?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=786153ed12a108f00708b727d0092a90" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="tldr">TL;DR</h1>
<img src="https://images.unsplash.com/photo-1518544801976-3e159e50e5bb?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=786153ed12a108f00708b727d0092a90" alt="Bitcoin vs. Gold: Store of Value"><p>This is not a fact-based essay; it is my philosophical argument against Bitcoin being a true store of value. I argue for your Bitcoin to hold its value, how someone has to keep doing work after its mined.</p>
<p><strong>Disclaimer</strong>: As I write this, I have no significant investments in either Bitcoin/Crypto or Gold/Precious Metals.</p>
<h1 id="firstthingsfirst">First Things First</h1>
<p>Let me get this thing out the way first, I wish I had bought Bitcoin in 2013, or 2014, or the start of 2017! It has probably made more millionaires than anything else in history and I wish I had invested at the right time.<br>
I am not approaching this subject as a sore-loser though and am more than willing to listen to any criticism of arguments made here.</p>
<p>Also, this argument is specifically against Bitcoin and other Crypto-Currencies being a true store of value; not against their other uses and the revolutionary nature of the underlying technologies of <a href="https://en.wikipedia.org/wiki/Blockchain">Blockchain</a> and other Crypto Distributed Ledgers.</p>
<h1 id="value">Value</h1>
<p>When I hear the term <a href="https://en.wikipedia.org/wiki/Store_of_value">Store of Value</a>, I see long-term value; not a few months or years; the term should be measured in decades or even generations.</p>
<p>To understand how something can store value, you first need to understand how value is created. In case of both Bitcoin and Gold, the value is created by someone doing work to produce the asset. In case of Gold, its the mining company doing some physical work; for Bitcoin, its a mining computer solving a mathematical problem to produce a fixed amount of Bitcoin every 10 minutes.</p>
<h1 id="econ101">Econ 101</h1>
<p>To generate value, both Gold and Bitcoin miners have to invest <a href="https://en.wikipedia.org/wiki/Capital_(economics)">capital</a> to buy the equipment (computers, mining machines etc.) and incur <a href="https://www.investopedia.com/terms/p/production-cost.asp">production costs</a> and <a href="https://en.wikipedia.org/wiki/Capital_(economics)">operating expenses</a> to maintain and run that equipment (cooling, electricity, manual labor etc.). For simplicity, I am going to include operating expenses into production costs in the remainder of this article.</p>
<p>For a miner to keep producing the asset, the market price for the asset should be higher than at least the production cost (assuming all capital is already paid off).</p>
<p>For example, if the expenses to produce an ounce of Gold are $1000, but the price of Gold is $900/ounce, the miners will probably shut down the mine.<br>
Similarly, the Bitcoin miners will only keep mining if the <a href="https://en.wikipedia.org/wiki/Bitcoin#Supply">transaction fee + block reward</a> are more valuable than the production costs of the mining rig.</p>
<h1 id="scenario1gold">Scenario 1: Gold</h1>
<p>Consider that you bought some Gold at $1000/ounce and the current cost of mining Gold is $500/ounce. A couple years down the road the current mines are drying up and the cost of mining shoots up to $1500/ounce, while the market price holds at $1000/ounce; all of the miners shut down their operations<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup>. What is the value of <strong>your</strong> Gold now? Still $1000/ounce!<br>
In essence, the value of your Gold is independent of the continuing effort of others or even you. There is no action required on anybody&apos;s part for your Gold to retain its value.</p>
<h1 id="scenario2bitcoin">Scenario 2: Bitcoin</h1>
<p>Now, let&apos;s look at a similar example in Bitcoin. You bought your Bitcoin at $1000/coin. Cost of mining shot up to more than $1000/coin and all the miners shut down their operations.<br>
What value does your Bitcoin have? A big fat zero! Why?<br>
In contrast to Gold, where the value is stored in the physical asset, Bitcoin&apos;s value is based on a distributed ledger hosted on the network. And, the network requires constant upkeep for you to maintain the value of <strong>your</strong> Bitcoin.</p>
<h1 id="conclusion">Conclusion</h1>
<blockquote>
<p>Unlike Gold, Bitcoin requires a constant amount of work by the network to maintain its value. Hence, it is not a true store of value.</p>
</blockquote>
<p>In some respects, Bitcoin is more like a security<sup class="footnote-ref"><a href="#fn2" id="fnref2">[2]</a></sup>, where you are betting that value will be maintained on someone&apos;s future work and less like a <a href="https://en.wikipedia.org/wiki/Commodity">commodity</a>, where value has already been generated and is maintained by a demand for the commodity.</p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="http://www.mining.com/sibanye-stillwater-shuts-cooke-gold-mine-7000-laid-off/">http://www.mining.com/sibanye-stillwater-shuts-cooke-gold-mine-7000-laid-off/</a> <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
<li id="fn2" class="footnote-item"><p><a href="http://clintonlawfirm.blogspot.com/2011/01/what-is-security-under-federal.html">Definition of a Security</a> as interpreted by the Supreme Court... &quot;[a]n investment contract for purposes of the Securities Act means a contract, transaction or scheme whereby a person invests his money in a common enterprise and is led to expect profits solely from the efforts of the promoter or a third party. 66 S.Ct. at 1103.&quot; <a href="#fnref2" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Automation 201: Processes and Frameworks]]></title><description><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>We need more [better] processes to make this operation repeatable!</p>
</blockquote>
<p>Working in a corporate IT development environment, I hear that statement a lot. Every time something goes wrong with a deployment, a project is running late or over budget, a team is not meeting its objectives, the root cause meeting</p>]]></description><link>https://manujbhatia.com/2018/02/08/automation-201-processes-and-frameworks/</link><guid isPermaLink="false">59af9d66dac8930001351cd9</guid><category><![CDATA[philosophy]]></category><category><![CDATA[automation]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Thu, 08 Feb 2018 07:02:38 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1503551723145-6c040742065b?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjEzNDA2fQ&amp;s=dd172a15dd030cf60e8b9c317eda7d41" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<img src="https://images.unsplash.com/photo-1503551723145-6c040742065b?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjEzNDA2fQ&amp;s=dd172a15dd030cf60e8b9c317eda7d41" alt="Automation 201: Processes and Frameworks"><p>We need more [better] processes to make this operation repeatable!</p>
</blockquote>
<p>Working in a corporate IT development environment, I hear that statement a lot. Every time something goes wrong with a deployment, a project is running late or over budget, a team is not meeting its objectives, the root cause meeting always ends with this conclusion. Well, at least it seems to be!</p>
<p>Do I disagree with this conclusion? Not necessarily!<br>
I think there are better ways of handling these issues through tools, automation and organizational structure, but processes do have a critical role to play in a stable production environment.</p>
<p>Now there is nothing wrong with processes. However, processes are not free! While they make operations repeatable, they are not reusable.</p>
<blockquote>
<p>Repeatability adds consistency to an operation, reusability makes it faster.</p>
</blockquote>
<p>I came to a revelation recently that contrary to popular belief, processes do not add reusability. They only add repeatability and predictability.<br>
Think about it, a checklist to deploy an application is repeatable and provides consistency of the output (as long as the checklist is complete). However, it&apos;s not reusable! Every new person executing the checklist for the first time suffers from the same learning curve and pitfalls. Even on the millionth time, the time taken to follow the process is still the same.</p>
<blockquote>
<p>Processes are repeatable, frameworks are reusable.</p>
</blockquote>
<p>And the main reason behind that is that a process aims to replace the human intellect by &quot;documenting&quot; all tasks that need to be accomplished for repeatability, whereas frameworks insist on automation based on conventions that need to be followed.</p>
<p>Take for an example, memory management &quot;best practices&quot; in <code>C</code> programming language.<br>
One way to address memory saftey is by mandating memory-management be a line item on a code review checklist. This is a linear complexity operation. More memory operations in the code, more time it will take to verify during the code review.<br>
Conversley, you can come up with a memory management convention, like <code>Objective-C</code>&apos;s <a href="https://developer.apple.com/library/content/documentation/General/Conceptual/DevPedia-CocoaCore/MemoryManagement.html">memory management guidelines</a>.<br>
Now during the code review you only need to make sure the guidelines around memory allocation/deallocation have been followed or not; no matter the size of the application. Infact, Apple was able to take these conventions and codify them as <a href="https://en.wikipedia.org/wiki/Automatic_Reference_Counting">ARC</a>, completely automating the memory safety reviews.</p>
<blockquote>
<p>Process is a set of tasks to complete, framework is a convention to follow.</p>
</blockquote>
<p>And, this is the key difference. Next time you have a problem to solve, see if you can build a convention-based framework, instead of a task-based process.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Pretty Emails from Shell Scripts]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>One of the key usage of shell scripts is to monitor systems and jobs and send out notification alerts to email addresses. With the advent of smartphones and always-connected devices, these emails are not limited to 140-characters of plain text and can provide a rich layout and format to make</p>]]></description><link>https://manujbhatia.com/2016/08/14/pretty-emails-from-shell-scripts/</link><guid isPermaLink="false">59af9d66dac8930001351cd6</guid><category><![CDATA[ksh]]></category><category><![CDATA[utility]]></category><category><![CDATA[Unix]]></category><category><![CDATA[shell scripting]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Sun, 14 Aug 2016 06:18:54 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1483058712412-4245e9b90334?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=c5ac6d2dec8b86901f460790fbfbe79e" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1483058712412-4245e9b90334?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=c5ac6d2dec8b86901f460790fbfbe79e" alt="Pretty Emails from Shell Scripts"><p>One of the key usage of shell scripts is to monitor systems and jobs and send out notification alerts to email addresses. With the advent of smartphones and always-connected devices, these emails are not limited to 140-characters of plain text and can provide a rich layout and format to make it easier to understand the issue at hand and provide useful recovery information for support personnel.</p>
<p>You can combine <code>uuencode</code> and <code>sendmail</code> to send formatted html notification emails with attachments. Use some shell scripting glue and you can put everything in a simple script as shown below.</p>
<h3 id="synopsis">Synopsis</h3>
<pre><code class="language-language-bash">notify_html &lt;email&gt; &lt;subject&gt; [&quot;&lt;attach1&gt; [name1]&quot; ... &quot;&lt;attachN&gt; [nameN]&quot;] &lt; body.txt
</code></pre>
<p>Example,</p>
<pre><code class="language-language-bash">gen_error_html | notify_html notify@example.org &quot;Issue with job one&quot; \
       &quot;one.3212345.log one.log&quot;
</code></pre>
<h3 id="script">Script</h3>
<pre><code class="language-language-bash">
typeset -r UTILS_UUENCODE=uuencode
typeset -r UTILS_SENDMAIL=sendmail

## Takes a list of file names and encodes them properly to be attached to an email
function process_attachments
{

    ## loop over all the remaining parameters and create uuencode commands to encode attachments
    for arg in &quot;$@&quot;
    do
        ## The remote name for the attachment is optional, so append the same name if it is missing
        if [[ $arg != *\ * ]]; then
            $UTILS_UUENCODE $arg $arg
        else
            $UTILS_UUENCODE $arg
        fi
    done
}

function notify_html 
{
    typeset -r SYSTEM=$(uname -s)
 
    typeset email=&quot;$1&quot;
    typeset subject=&quot;$2&quot;
    shift 2
    
    (
        ## pass-through email body content
        cat
        ## Add a footer
        echo &quot;\n\rMessage generated from $system at $(date)&quot;
        ## Add any attachments
        process_attachments &quot;$@&quot;
    ) | sendmail_html &quot;$email&quot; &quot;$system: $subject&quot;

    return $?
}

function sendmail_html
{
    typeset email=&quot;$1&quot;
    typeset subject=&quot;$2&quot;

    (
        echo &quot;Subject: $subject&quot;
        echo &quot;MIME-Version: 1.0&quot;
        echo &quot;Content-Type: text/html&quot;
        echo &quot;Content-Disposition: inline&quot;
        ## pass-through email body content, including attachments
        cat
    ) | $UTILS_SENDMAIL $email
}

notify_html &quot;$@&quot;
</code></pre>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[K-shawk!]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Ok. I started writing this when I was standing in line to pick up an iPhone 4 (that&#x2019;s right, this post has been that long in the making!), so this post was planned to be short with few examples!</p>
<p>I just wanted to introduce <code>ksh93</code> to everyone (or</p>]]></description><link>https://manujbhatia.com/2016/08/14/kshawk/</link><guid isPermaLink="false">59af9d66dac8930001351cc4</guid><category><![CDATA[ksh]]></category><category><![CDATA[ksh93]]></category><category><![CDATA[Unix]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Sun, 14 Aug 2016 03:48:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1475018608413-f84fe2a42b7a?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=75234a0e4ebd154936b57f56ccb76b22" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1475018608413-f84fe2a42b7a?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=75234a0e4ebd154936b57f56ccb76b22" alt="K-shawk!"><p>Ok. I started writing this when I was standing in line to pick up an iPhone 4 (that&#x2019;s right, this post has been that long in the making!), so this post was planned to be short with few examples!</p>
<p>I just wanted to introduce <code>ksh93</code> to everyone (or as my very good friend calls it K-shawk!).</p>
<p>When it comes to shells most people know about <code>sh</code>, <code>csh</code>, <code>ksh</code>, <code>bash</code> etc. They know about strengths and weaknesses of each and what not. However, very few people know that there are 2 versions of ksh available out there.</p>
<ol>
<li><code>ksh</code> &#x2013; the most popular version packaged with pretty much all UNIX OSes. This is really <code>ksh88</code>. In other words, it&#x2019;s the version of <code>ksh</code> that was implemented in 1988.</li>
<li><code>ksh93</code> &#x2013; this is not as popular as <code>ksh88</code>, but in my experience, it&#x2019;s packaged in every commercial OS.</li>
</ol>
<p>I highly recommend upgrading to <code>ksh93</code> for all your shell scripts and interactive shell. Why? Simply because it has a lot of features that were available to you only if you mixed <code>awk</code> within your shell scripts (and hence the nickname K-shawk!). Here are some of the main ones:</p>
<ul>
<li>
<p><strong>Associative arrays</strong>. This is a big one. It helps you create associations (&#x2018;hashes&#x2019; in many languages) between strings. The traditional arrays can only use integers as indices, however, with associative arrays your can use strings as indices.</p>
<pre><code>  $ typeset -A x=( [A]=1 [B]=2 )
  $ echo ${x[A]},${x[B]}
  1,2
</code></pre>
</li>
<li>
<p><strong>Compound Variables</strong>. These are C-style structures that can be used to group multiple variables together and passed around to functions as parameters.</p>
<pre><code>  $ typeset -C y=( A=1 B=2 )
  $ echo ${y.A},${y.B}
  1,2
</code></pre>
</li>
<li>
<p><strong>Advanced Variable Substitution</strong>. You can perform substrings and string substitution within the variable substitution construct now.</p>
<pre><code>  $ x=Hello
  $ echo ${x//Hell/Problem}
  Problemo
  $ echo ${x:0:4}
  Hell
</code></pre>
</li>
<li>
<p><strong>New Date Capabilities</strong>. <code>printf</code> can now handle date time formatting and allows you to perform a lot of date calculations that were not possible without mixing some <code>perl</code> in your shell scripts.</p>
<pre><code>  $ printf &quot;%T\n&quot; now
  Sat Aug 13 20:41:54 CDT 2016
  $ printf &quot;%(%Y-%m-%d)T\n&quot; now
  2016-08-13
</code></pre>
</li>
</ul>
<p>There is a lot of depth to <code>ksh93</code> and the more recent versions of the shell expand the compound variable syntax to provide object-oriented programming constructs and a lot more.<br>
You can check what version comes with your OS distribution by running <code>ksh93 --version</code> or <code>ksh --version</code> (Most of the linux distributions will only have <code>ksh93</code> and they link it as <code>ksh</code>).</p>
<p>Visit David Korn&apos;s website <a href="http://KornShell.com">KornShell.com</a> for more details.<br>
Also, <a href="http://blog.fpmurphy.com/tag/ksh93">Musings of an OS Plumber</a> has great tutorials on some advanced <code>ksh93</code> features.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Fun with Pipes: Copy Directories Across Servers With SSH]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Many UNIX experts would swear by the use of pipes in the day-to-day operations, but very few know to combine it with <code>ssh</code> to perform operations across different servers.</p>
<p>The following command would copy the files contained in <code>$SOURCE_FILES</code> to <code>$TARGET_DIR</code> (any directory structure in <code>$SOURCE_FILES</code> will</p>]]></description><link>https://manujbhatia.com/2016/08/09/fun-with-pipes-copy-directories-across-servers-with-ssh/</link><guid isPermaLink="false">59af9d66dac8930001351ccf</guid><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Tue, 09 Aug 2016 05:43:15 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1512375305577-4dc349fcef0b?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=96ead22ddde76818816e40e42b6df314" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><img src="https://images.unsplash.com/photo-1512375305577-4dc349fcef0b?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=96ead22ddde76818816e40e42b6df314" alt="Fun with Pipes: Copy Directories Across Servers With SSH"><p>Many UNIX experts would swear by the use of pipes in the day-to-day operations, but very few know to combine it with <code>ssh</code> to perform operations across different servers.</p>
<p>The following command would copy the files contained in <code>$SOURCE_FILES</code> to <code>$TARGET_DIR</code> (any directory structure in <code>$SOURCE_FILES</code> will be created under <code>$TARGET_DIR</code> on the remote machine:</p>
<pre><code class="language-language-bash">export SOURCE_FILES=file1
export TARGET_DIR=/copy/file/here
export REMOTE_MACHINE=remote.server.net

tar -cvf - $SOURCE_FILES | gzip -9 -c \
    | ssh $REMOTE_MACHINE &quot;(cd $TARGET_DIR; gunzip -c | tar -xvf -)&quot;
</code></pre>
<p>You might wonder why you should not just use <code>sftp</code> or <code>scp</code> to perform the same function... few reasons:</p>
<ol>
<li>Not every server allows <code>scp</code>, since it requires interactive login for accounts and some service accounts are not allowed to perform interactive logins for security reasons. <code>sftp</code> is a subsystem build into <code>sshd</code>, so its a lot more restrictive and secure.</li>
<li><code>sftp</code> does not preserve the file permissions and behaves like <code>ftp</code> and marks all files as non-executable.</li>
<li>If you are behind multiple servers, which again is a network segmentation/security technique, you would have an <em>edge server</em> between your laptop and the destination server. This means you need to have enough disk space available on the edge server to stage the files before pushing them to the final destination. Following is an example of how you can extend this pattern to <em>hop</em> across multiple servers without requiring any disk space on intermediate servers.</li>
</ol>
<pre><code class="language-language-bash">export SOURCE_FILES=file1
export TARGET_DIR=/copy/file/here
export HOP_MACHINE=edge.server.net
export REMOTE_MACHINE=remote.server.net

tar -cvf - $SOURCE_FILES | gzip -9 -c \
    | ssh $HOP_MACHINE \
        &quot;ssh $REMOTE_MACHINE &apos;(cd $TARGET_DIR; gunzip -c | tar -xvf -)&apos;&quot;
</code></pre>
<p>This same pattern can be used to execute arbitrary code which reads from <code>stdin</code> and processes it. For example, I use this approach to dump data from an application server to a <code>hadoop</code> cluster via an edge server, without requiring to stage the files on the edge server.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[You Are Not Fully Utilizing Your VCS!]]></title><description><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<p>The primary purpose of a VCS is not to put stuff in it, but to take stuff out as needed.</p>
</blockquote>
<p>Ponder over that statement before you read on.</p>
<p>There is a fundamental difference between how big Corporate IT treats version control vs the Silicon Valley and Startups.</p>
<p>Most Corporate IT</p>]]></description><link>https://manujbhatia.com/2016/03/16/you-are-not-fully-utilizing-your-vcs/</link><guid isPermaLink="false">59af9d66dac8930001351cca</guid><category><![CDATA[VCS]]></category><category><![CDATA[DevOps]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Wed, 16 Mar 2016 08:03:21 GMT</pubDate><media:content url="http://manujbhatia.com/content/images/2018/02/dreamstime_xxl_61526938_1920.jpg" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><blockquote>
<img src="http://manujbhatia.com/content/images/2018/02/dreamstime_xxl_61526938_1920.jpg" alt="You Are Not Fully Utilizing Your VCS!"><p>The primary purpose of a VCS is not to put stuff in it, but to take stuff out as needed.</p>
</blockquote>
<p>Ponder over that statement before you read on.</p>
<p>There is a fundamental difference between how big Corporate IT treats version control vs the Silicon Valley and Startups.</p>
<p>Most Corporate IT teams use version control as Cavemen used fire... just stick raw food in it (just checkin your code into a VCS)!<br>
<img src="http://manujbhatia.com/content/images/2016/03/dreamstime_xxl_61526938.jpg" alt="You Are Not Fully Utilizing Your VCS!" loading="lazy"></p>
<p>Silicon Valley understands that fire drives cars, air planes, rockets and, yes, Jetpacks :-) (VCS is the very foundation of DevOps)!<br>
<img src="http://manujbhatia.com/content/images/2016/03/dreamstime_xxl_38690327.jpg" alt="You Are Not Fully Utilizing Your VCS!" loading="lazy"></p>
<p>Now this comparison is a little exaggerated, but the underlying point remains. You can use your VCS for basic code checkin and collaboration or you can make it the powerhouse that drives all of your development and operations.</p>
<p>Here are some things you are (probably) not using your VCS for!</p>
<h1 id="codereviews">Code Reviews</h1>
<blockquote>
<p>If you are not using a pre-commit code review system, you are not really doing code reviews!</p>
</blockquote>
<p>Developers are by definition lazy people (we write programs, so we don&apos;t have to do something manually!). An honor/convention-based code review that is conducted at the end of a coding cycle via emails, code-walkthrough, is mostly skipped or given lip-service to. The only effective way of doing proper code review is to stop the developer from finishing the commit, unless the code passes all quality checks and code reviews.</p>
<p>Now, don&apos;t confuse code reviews just with manual peer reviews. This is where all the magic happens, from automated static code analysis, syntax checks, build verification, unit test verification etc.</p>
<p>Using a modern version control system like Git with the help of tools like <a href="https://www.gerritcodereview.com/">Gerrit</a>, your version control becomes a code review hub with very little overhead for the developers.<br>
Developers use the same workflow that they are used to. For example, here is how a regular commit and a code review request looks like for a developer using Git + Gerrit.</p>
<h6 id="regularcommit">Regular Commit</h6>
<pre><code class="language-language-bash">$ vim file.c ## Make your changes
$ git commit -a -m &apos;Changed something&apos; file.c
$ git push origin master:master  ## Push directly to the main branch
</code></pre>
<h6 id="codereview">Code Review</h6>
<pre><code class="language-language-bash">$ vim file.c ## Make your changes
$ git commit -a -m &apos;Changed something&apos; file.c
$ git push origin master:refs/for/master   ## Push to a different destination to trigger a code review
</code></pre>
<p>As you can see there is nothing additional that the developer had to do to create a code review request.</p>
<h1 id="debugging">Debugging</h1>
<p>Using clean, atomic commits helps you debug when a bug was introduced in the code base very easily.<br>
You can use tools like <code>git bisect</code> to quickly identify when a particular regression was introduced in your codebase, if your VCS has maintained clean history.</p>
<h1 id="trackdeveloperproductivity">Track Developer Productivity</h1>
<p>Using Gerrit&apos;s changesets allows you to have your developers check-in work-in-progress (WIP) at the end of every day. Then you can report on the activity of each developer across days and months. This is especially useful when you have contractors working on your codebase. Not only can you oversee their productivity, you get all the work at the end-of-day in a central repository.<br>
Here is a default dashboard for a member&apos;s contribution from <a href="https://github.com">Github</a>.</p>
<h6 id="githubdevelopercontribution"><a href="https://github.com/salivian">Github Developer Contribution</a></h6>
<p><img src="http://manujbhatia.com/content/images/2016/02/Screen-Shot-2016-02-24-at-11-40-44-PM.png" alt="You Are Not Fully Utilizing Your VCS!" loading="lazy"></p>
<h1 id="identifyproductsatrisk">Identify Products at Risk</h1>
<p>Having a pulse of commits and committers on a repository is a very good indicator of how actively a product in your company is maintained. You can write reports based on the activity on a product&apos;s source code repository on whether it is actively supported or not. If a critical product in the company falls below a certain number of active contributors/commits-per-day, that could be a trigger to look into augmenting staff for that product.<br>
Again, here are in-built dashboards from github.com, indicating current product health.</p>
<h6 id="dailycommitactivity"><a href="https://github.com/FreeCodeCamp/FreeCodeCamp/graphs/punch-card">Daily Commit Activity</a></h6>
<p><img src="http://manujbhatia.com/content/images/2016/02/Screen-Shot-2016-02-24-at-10-27-04-PM.png" alt="You Are Not Fully Utilizing Your VCS!" loading="lazy"></p>
<h6 id="contributionhistoryandtopcommitters"><a href="https://github.com/FreeCodeCamp/FreeCodeCamp/graphs/contributors">Contribution History and Top Committers</a></h6>
<p><img src="http://manujbhatia.com/content/images/2016/02/Screen-Shot-2016-02-24-at-10-27-21-PM.png" alt="You Are Not Fully Utilizing Your VCS!" loading="lazy"></p>
<h6 id="commitsperweek"><a href="https://github.com/FreeCodeCamp/FreeCodeCamp/graphs/commit-activity">Commits per week</a></h6>
<p><img src="http://manujbhatia.com/content/images/2016/02/Screen-Shot-2016-02-24-at-10-28-03-PM.png" alt="You Are Not Fully Utilizing Your VCS!" loading="lazy"></p>
<h1 id="truecollaboration">True Collaboration</h1>
<p>Maintaining a VCS that allows a maintainer vs contributor model has tremendous benefit for the IT organizination.<br>
Allowing everyone in the organization access code to the code and submit a patch for review as a contributor, that the maintainers can accept or reject, creates a level playing field across your organization.<br>
Projects benefit from a wide range of people reviewing and contributing to the product and developers benefit by having the ability to expand their horizons into newer products and technologies.</p>
<h1 id="releases">Releases</h1>
<p>Instead of developers/build managers doing builds for stage/production, the VCS tags drive your build servers.<br>
If a particular version of your product is ready, you simply tag the version in your VCS as <code>release/3.0.1-beta1</code> and it triggers your build server to build that version and push it to your artifact repository.<br>
This eliminates developer mistakes of building a wrong version or picking up local changes in the build.<br>
Using immutable tags also makes tracking builds to source control versions very easy, providing very good audit-ability of the releases.<br>
Using digitally-signed tags, verified by the build server, can ensure that only authorized developers can actually release software.<br>
Also, maintaining clean commits allows the build server to automatically generate release notes for each build.</p>
<h1 id="deployments">Deployments</h1>
<p>Further using digitally-signed tags and a carefully crafted build/artifact server, developers can actually perform no-button deployments by appropriately tagging a particular version in the VCS for release.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Why Switch to Git?]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id="overview">Overview<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup></h1>
<p><a href="http://git-scm.com/about">Git</a> is a widely used source code management system for software development. It is a <a href="https://en.wikipedia.org/wiki/Distributed_version_control">distributed revision control</a> system with an emphasis on speed, data integrity, and support for distributed, non-linear workflows. Git was initially designed and developed in 2005 by Linux kernel developers (including Linus Torvalds) for</p>]]></description><link>https://manujbhatia.com/2016/03/13/why-switch-to-git/</link><guid isPermaLink="false">59af9d66dac8930001351ccd</guid><category><![CDATA[Git]]></category><category><![CDATA[VCS]]></category><dc:creator><![CDATA[Manuj Bhatia]]></dc:creator><pubDate>Sun, 13 Mar 2016 01:02:12 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1465447142348-e9952c393450?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=30c2837564064f98a3a3b79633cfcaed" medium="image"/><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id="overview">Overview<sup class="footnote-ref"><a href="#fn1" id="fnref1">[1]</a></sup></h1>
<img src="https://images.unsplash.com/photo-1465447142348-e9952c393450?ixlib=rb-0.3.5&amp;q=80&amp;fm=jpg&amp;crop=entropy&amp;cs=tinysrgb&amp;w=1080&amp;fit=max&amp;ixid=eyJhcHBfaWQiOjExNzczfQ&amp;s=30c2837564064f98a3a3b79633cfcaed" alt="Why Switch to Git?"><p><a href="http://git-scm.com/about">Git</a> is a widely used source code management system for software development. It is a <a href="https://en.wikipedia.org/wiki/Distributed_version_control">distributed revision control</a> system with an emphasis on speed, data integrity, and support for distributed, non-linear workflows. Git was initially designed and developed in 2005 by Linux kernel developers (including Linus Torvalds) for Linux kernel development.</p>
<p>As companies are adopting DevOps practices, they are realizing that their version control system is not only a place to track revisions of their code, but is the backbone of their whole DevOps practice! I highly recommend going through the recent blog post I wrote about <a href="http://manujbhatia.com/you-are-not-fully-utilizing-your-vcs">how you are not fully utilizing your VCS</a> for some background.</p>
<h1 id="disclaimer">Disclaimer</h1>
<p>While I would recommend any and all projects and teams to adopt Git as their primary VCS, please do not try to migrate your teams to Git without proper initial training.</p>
<p>Git (in general, any Distributed VCS) is fundamentally a very different system, compared to traditional VCSes like SVN. This can really confuse developers used to a central VCS. Take your time and develop a migration/training strategy before switching over.</p>
<p>Also, SVN does have very narrow advantages over Git in some edge use-cases. A good comparison of Git and SVN can be found at the <a href="https://git.wiki.kernel.org/index.php/GitSvnComparison">Linux Kernel Wiki</a> and at <a href="https://www.wikivs.com/wiki/Git_vs_Subversion">WikiVS</a>. You should consider whether one of these use-cases applies to your team.</p>
<h1 id="whygit">Why Git?</h1>
<h2 id="industryleader">Industry Leader</h2>
<p>Git&apos;s popularity has been rapidly increasing year-over-year. A testament to Git&apos;s popularity is that the founders of Subversion, <a href="http://www.collab.net/products/enterprise-git">CollabNet</a>, have moved Subversion to a <a href="http://subversion.apache.org/">Apache Software Foundation</a> project and are providing Enterprise Git solutions now<sup class="footnote-ref"><a href="#fn1" id="fnref1:1">[1:1]</a></sup>.</p>
<p>In the last published Eclipse Community Survey of developers (2014) Git overtook SVN as the most widely used version control system. <sup class="footnote-ref"><a href="#fn1" id="fnref1:2">[1:2]</a></sup><br>
<img src="http://manujbhatia.com/content/images/2016/03/Screen-Shot-2016-03-03-at-7-11-37-PM.png" alt="Why Switch to Git?" loading="lazy"></p>
<p>Although not very scientific, the Google search trends also show the interest in Git rising since 2009 and svn declining<sup class="footnote-ref"><a href="#fn1" id="fnref1:3">[1:3]</a></sup>:<br>
<img src="http://manujbhatia.com/content/images/2016/03/Screen-Shot-2016-03-09-at-9-00-18-AM.png" alt="Why Switch to Git?" loading="lazy"></p>
<p>As a developer, you will also increasingly see Git as a required job skill<sup class="footnote-ref"><a href="#fn1" id="fnref1:4">[1:4]</a></sup>:<br>
<img src="http://manujbhatia.com/content/images/2016/03/Screen-Shot-2016-03-09-at-9-26-00-AM.png" alt="Why Switch to Git?" loading="lazy"></p>
<h2 id="speed">Speed</h2>
<p>Due to its distributed nature, Git is an order of a magnitude faster than SVN. There is no network communication involved. Most operations in Git take only a few milliseconds. Operations like switching a branch takes sub-second on even big repositories like the linux kernel.</p>
<p>Here are some benchmarks<sup class="footnote-ref"><a href="#fn1" id="fnref1:5">[1:5]</a></sup><br>
<img src="http://manujbhatia.com/content/images/2016/03/Screen-Shot-2016-03-03-at-7-41-35-PM.png" alt="Why Switch to Git?" loading="lazy"></p>
<h2 id="integrations">Integrations</h2>
<p>Due to its industry leader status, almost every development tool out there supports Git. In fact, most new tools first support Git and later support SVN or not support SVN at all (Microsoft Visual Studio 2015 has in-built support for Git and not SVN<sup class="footnote-ref"><a href="#fn1" id="fnref1:6">[1:6]</a></sup>). Plugins for integration with <a href="https://help.rallydev.com/git">CA Rally</a>, <a href="https://marketplace.atlassian.com/plugins/com.xiplink.jira.git.jira_git_plugin/server/overview">Atlassian Jira</a>, and <a href="https://hpln.hpe.com/page/source-code-management-integration-ali">HP ALI</a> are available.</p>
<h2 id="defactocloudstandard">De facto Cloud Standard</h2>
<p>Almost every cloud-based service supports or requires Git out of the box; most don&apos;t even support SVN at all.</p>
<ul>
<li><a href="https://developer.ibm.com/bluemix/2016/02/22/github-enterprise-service/">IBM&apos;s BlueMix&apos;s DevOps</a> solution integrates with Github as the source code repository.</li>
<li><a href="https://cloud.google.com/source-repositories/docs/">Google&apos;s Cloud Platform</a> provides Git repository hosting and <a href="https://cloud.google.com/appengine/">AppEngine</a> integrates with Git.</li>
<li><a href="https://azure.microsoft.com/en-us/documentation/articles/web-sites-publish-source-control/">Microsoft Azure</a> integrates with Git to publish websites.</li>
<li><a href="https://aws.amazon.com/">Amazon AWS</a> provides a Git compatible repository hosting service with <a href="https://aws.amazon.com/codecommit/">CodeCommit</a> and has built-in integration with Github for their Continuous Delivery offering, <a href="https://aws.amazon.com/codepipeline/product-integrations/">CodePipeline</a>.</li>
</ul>
<h2 id="reliability">Reliability</h2>
<p>Git is very reliable when it comes to managing your code. All the commands that you would use on a day-to-day basis would never leave your working copy in an inconsistent state. Even if you get stuck somewhere</p>
<p>SVN on the other hand has a tendency to leave your working copy in an intermediate state on failed merges, branch switching etc., making you spend hours manually cleaning out your working copy. This is one of the big reasons that SVN users rarely switch branches in the same working copy; they always use and recommend a different working copy for each branch.</p>
<h2 id="developerproductivity">Developer Productivity</h2>
<p>Git has great branching and merging features which allow developers to perform multiple merges per day encouraging smaller units of work to be merged. This leads to a lot more manageable merging structure instead of monolithic merges.<br>
Here is an example of merges done on the Git repository itself by one of the maintainers<sup class="footnote-ref"><a href="#fn1" id="fnref1:7">[1:7]</a></sup>:<br>
<img src="http://manujbhatia.com/content/images/2016/03/Screen-Shot-2016-03-03-at-7-47-10-PM.png" alt="Why Switch to Git?" loading="lazy"></p>
<p>Also, due to the fast speed and some git-specific features like stashes, it becomes super easy for a developer to switch context.</p>
<h2 id="sourcecodeintegritysecurity">Source Code Integrity &amp; Security</h2>
<p>The underlying data model of a Git repository makes it tamper proof. A malicious user who has admin access to your source code repo cannot alter your repo&apos;s history without raising a red flag.<sup class="footnote-ref"><a href="#fn1" id="fnref1:8">[1:8]</a></sup></p>
<p>SVN offers no such guarantees and a malicious user with admin access to the SVN repo can easily inject arbitrary code into your repositories history without detection.</p>
<h1 id="references">References</h1>
<p><a href="http://www.itjobswatch.co.uk/default.aspx?page=1&amp;sortby=0&amp;orderby=0&amp;q=git+svn&amp;id=0&amp;lid=2618">http://www.itjobswatch.co.uk/default.aspx?page=1&amp;sortby=0&amp;orderby=0&amp;q=git+svn&amp;id=0&amp;lid=2618</a></p>
<hr class="footnotes-sep">
<section class="footnotes">
<ol class="footnotes-list">
<li id="fn1" class="footnote-item"><p><a href="http://git-scm.com/about/info-assurance">http://git-scm.com/about/info-assurance</a> <a href="#fnref1" class="footnote-backref">&#x21A9;&#xFE0E;</a> <a href="#fnref1:1" class="footnote-backref">&#x21A9;&#xFE0E;</a> <a href="#fnref1:2" class="footnote-backref">&#x21A9;&#xFE0E;</a> <a href="#fnref1:3" class="footnote-backref">&#x21A9;&#xFE0E;</a> <a href="#fnref1:4" class="footnote-backref">&#x21A9;&#xFE0E;</a> <a href="#fnref1:5" class="footnote-backref">&#x21A9;&#xFE0E;</a> <a href="#fnref1:6" class="footnote-backref">&#x21A9;&#xFE0E;</a> <a href="#fnref1:7" class="footnote-backref">&#x21A9;&#xFE0E;</a> <a href="#fnref1:8" class="footnote-backref">&#x21A9;&#xFE0E;</a></p>
</li>
</ol>
</section>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>