<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Parks Computing</title>
	<atom:link href="https://www.parkscomputing.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.parkscomputing.com</link>
	<description>Pedagogy for the autodidactic programmer</description>
	<lastBuildDate>Fri, 02 Dec 2022 01:25:40 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.1.1</generator>

<image>
	<url>https://www.parkscomputing.com/wp-content/uploads/cropped-Padma-Paul-Crest-500-32x32.png</url>
	<title>Parks Computing</title>
	<link>https://www.parkscomputing.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>FizzBuzz</title>
		<link>https://www.parkscomputing.com/2022/12/fizzbuzz/</link>
					<comments>https://www.parkscomputing.com/2022/12/fizzbuzz/#respond</comments>
		
		<dc:creator><![CDATA[paulmooreparks]]></dc:creator>
		<pubDate>Thu, 01 Dec 2022 03:57:03 +0000</pubDate>
				<category><![CDATA[cplusplus]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[writing]]></category>
		<guid isPermaLink="false">https://www.parkscomputing.com/?p=1838</guid>

					<description><![CDATA[This is just one of those things you have to write, apparently. Here is mine, in C++.]]></description>
										<content:encoded><![CDATA[
<p>This is just one of those things you have to write, apparently. Here is mine, in C++.</p>



<pre class="wp-block-preformatted"><code class="language-cpp">#include &lt;iostream>

int main() {
    int _3 {0};
    int _5 {0};

    for (int i = 1; i &lt;= 100; ++i) {
        ++_3;
        ++_5;

        if (_3 == 3) {
            _3 = 0;
            std::cout &lt;&lt; "Fizz";
        }

        if (_5 == 5) {
            _5 = 0;
            std::cout &lt;&lt; "Buzz";
        }

        if (_3 > 0 &amp;&amp; _5 > 0) {
            std::cout &lt;&lt; i;
        }

        std::cout &lt;&lt; " ";
    }
}</code></pre>



<p>Drink up, and let the debate begin.</p>



<figure class="wp-block-image size-full is-resized"><a href="https://www.parkscomputing.com/wp-content/uploads/fizzbuzz.png"><img decoding="async" src="https://www.parkscomputing.com/wp-content/uploads/fizzbuzz.png" alt="" class="wp-image-1875" width="512" height="512" srcset="https://www.parkscomputing.com/wp-content/uploads/fizzbuzz.png 1024w, https://www.parkscomputing.com/wp-content/uploads/fizzbuzz-300x300.png 300w, https://www.parkscomputing.com/wp-content/uploads/fizzbuzz-150x150.png 150w, https://www.parkscomputing.com/wp-content/uploads/fizzbuzz-768x768.png 768w, https://www.parkscomputing.com/wp-content/uploads/fizzbuzz-225x225.png 225w" sizes="(max-width: 512px) 100vw, 512px" /></a></figure>
]]></content:encoded>
					
					<wfw:commentRss>https://www.parkscomputing.com/2022/12/fizzbuzz/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Set-Associative Cache in C#, Part 2: Interface Design</title>
		<link>https://www.parkscomputing.com/2021/08/set-associative-cache-in-c-part-2-interface-design/</link>
					<comments>https://www.parkscomputing.com/2021/08/set-associative-cache-in-c-part-2-interface-design/#comments</comments>
		
		<dc:creator><![CDATA[paulmooreparks]]></dc:creator>
		<pubDate>Wed, 04 Aug 2021 12:06:15 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[writing]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software]]></category>
		<guid isPermaLink="false">https://www.parkscomputing.com/?p=1765</guid>

					<description><![CDATA[This is part 2 of a three-part series on implementing a set-associative cache in C#. In part 1, we looked at how set-associative caches work and sketched out the basic design. In this part, we’ll expand on the design a bit more and define a code interface for the cache. In part 3, we’ll turn &#8230;<br><a href="https://www.parkscomputing.com/2021/08/set-associative-cache-in-c-part-2-interface-design/" class="more-link pen_button pen_element_default pen_icon_arrow_double">Continue reading <span class="screen-reader-text">Set-Associative Cache in C#, Part 2: Interface Design</span></a>]]></description>
										<content:encoded><![CDATA[
<p>This is part 2 of a three-part series on implementing a set-associative cache in C#. In <a rel="noreferrer noopener" href="/2021/08/set-associative-cache-in-c-part-1-analysis-initial-design/" target="_blank">part 1</a>, we looked at how set-associative caches work and sketched out the basic design. In this part, we’ll expand on the design a bit more and define a code interface for the cache. In part 3, we’ll turn the design into working code.</p>



<h2>Interface</h2>



<p>Now that we have the overall design, it&#8217;s time to consider what interface to provide for users of the cache. Let&#8217;s consider the methods and properties that a cache type might provide.</p>



<ul>
<li>Methods
<ul>
<li>Store items in the cache</li>



<li>Retrieve items from the cache</li>



<li>Query for the presence of an item by key</li>



<li>Remove items from the cache</li>
</ul>
</li>



<li>Properties
<ul>
<li>Count of items in the cache</li>



<li>Capacity of the cache</li>



<li><span style="color: initial;">Number of sets in the cache</span></li>



<li>Number of items (ways) in each set</li>
</ul>
</li>
</ul>



<p>The cache should also provide the means to enumerate over cache items, as well as enumerate keys and value independently. In other words, it should function like an standard <a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic?view=net-5.0" target="_blank" rel="noreferrer noopener">.NET generic collection</a>. That means we should implement the interfaces that will allow the cache to work with <a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.icollection-1?view=net-5.0#extension-methods" target="_blank">several extension methods</a> as well as standard enumeration patterns like <a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-foreach-statement" target="_blank">foreach</a>. Generic collections in the .NET library implement the <a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.icollection-1?view=net-5.0" target="_blank"><em>ICollection&lt;T&gt;</em></a> interface, and that interface is derived from <em><a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ienumerable-1?view=net-5.0" target="_blank">IEnumerable&lt;T&gt;</a></em> and <em><a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.ienumerable?view=net-5.0" target="_blank">IEnumerable</a></em>. If we derive our cache interface from <em>ICollection&lt;T&gt;</em>, we&#8217;ll get a few of the methods and properties that we need, and we&#8217;ll be prepared to interoperate with existing .NET code that uses the <em>ICollection</em>, <em>IEnumerable&lt;T&gt;</em>, and <em>IEnumerable</em> interfaces.</p>



<p>Following is the <em>ICollection&lt;T&gt;</em> interface and the two interfaces it derives from, <em>IEnumerable&lt;T&gt;</em> and <em>IEnumerable</em>:</p>



<pre class="wp-block-preformatted"><code class="language-csharp">namespace System.Collections {
    // Exposes an enumerator, which supports a simple iteration over a non-generic collection.
    public interface IEnumerable {
        // Returns an enumerator that iterates through a collection.
        IEnumerator GetEnumerator();
    }
}

namespace System.Collections.Generic {
    // Exposes the enumerator, which supports a simple iteration over a collection of a specified type.
    public interface IEnumerable&lt;out T&gt; : IEnumerable {
        // Returns an enumerator that iterates through the collection.
        new IEnumerator&lt;T&gt; GetEnumerator();
    }

    // Defines methods to manipulate generic collections.
    public interface ICollection&lt;T&gt; : IEnumerable&lt;T&gt;, IEnumerable {
        // Gets the number of elements contained in the collection.
        int Count {
            get;
        }

        // Gets a value indicating whether the collection is read-only.
        bool IsReadOnly {
            get;
        }

        // Adds an item to the collection.
        void Add(T item);

        // Removes all items from the collection.
        void Clear();

        // Determines whether the collection contains a specific value.
        bool Contains(T item);

        // Copies the elements of the collection to an array, starting at a particular array index.
        void CopyTo(T[] array, int arrayIndex);

        // Removes the first occurrence of a specific object from the System.Collections.Generic.ICollection`1.
        bool Remove(T item);
    }
}</code></pre>



<p>We could derive our cache interface directly from <em>ICollection&lt;T&gt;</em>, since it provides several of the methods and properties in the list above. That&#8217;s definitely something we want for interoperability, but the problem for day-to-day users is that the methods accept a single generic object type, and our cache is designed to function as a dictionary, which uses keys to store and retrieve values. In <a rel="noreferrer noopener" href="https://www.parkscomputing.com/2021/08/set-associative-cache-in-c-part-1-analysis-initial-design/" target="_blank">part 1</a>, we considered using a <em>KeyValuePair&lt;TKey,TValue&gt;</em> type to store the cache data. Let&#8217;s look at how adding a cache item would work in practice using the <em>ICollection&lt;T&gt;</em> interface:</p>



<pre class="wp-block-preformatted language-csharp"><code class="language-csharp">// We have to create a new KeyValuePair for every method call.
coupleCache.Add(new KeyValuePair("Brad", "Angelina"));

// Maybe we could minimize the constructor...
coupleCache.Add(new("Brad", "Angelina"));</code></pre>



<p>It works, but it&#8217;s clunky. As for <em>Contains</em> and <em>Remove</em>, those are effectively useless because we would either have to know the value of the cache item in order to use those methods (which defeats the entire purpose of the cache), or we would have to specify that those methods would ignore the value. Neither approach is workable.</p>



<p>In part 1, we noted that the cache works a lot like the .NET <a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=net-5.0" target="_blank">generic <em>Dictionary</em> type</a>. That collection implements the <a href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=net-5.0" target="_blank" rel="noreferrer noopener"><em>IDictionary&lt;TKey,TValue&gt;</em></a> interface:</p>



<pre class="wp-block-preformatted"><code class="language-csharp">namespace System.Collections.Generic {
    // Represents a generic collection of key/value pairs.
    public interface IDictionary&lt;TKey, TValue&gt; : ICollection&lt;KeyValuePair&lt;TKey, TValue&gt;&gt;, 
                                                 IEnumerable&lt;KeyValuePair&lt;TKey, TValue&gt;&gt;, 
                                                 IEnumerable 
    {
        // Gets or sets the element with the specified key.
        TValue this[TKey key] {
            get;
            set;
        }

        // Gets an ICollection containing the keys of the IDictionary.
        ICollection&lt;TKey&gt; Keys {
            get;
        }

        // Gets an ICollection containing the values in the IDictionary.
        ICollection&lt;TValue&gt; Values {
            get;
        }

        // Adds an element with the provided key and value to the IDictionary.
        void Add(TKey key, TValue value);

        // Determines whether the IDictionary contains an element with the specified key.
        bool ContainsKey(TKey key);

        // Removes the element with the specified key from the System.Collections.Generic.IDictionary`2.
        bool Remove(TKey key);

        // Gets the value associated with the specified key.
        bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value);
    }
}</code></pre>



<p>That looks like exactly what we need. It gives us a method to add an item with the key and value in separate parameters, a method to check for the presence of an item by key, a method to remove an item by key, and a method to retrieve an item&#8217;s value by key. </p>



<p>There are two other advantages to using this interface as the basis of our cache. First, it&#8217;s a standard interface that would be familiar to experienced .NET developers. Second, it would interoperate with standard .NET libraries, idioms, and extension methods. On the strength of these advantages, we&#8217;ll derive our cache interface from <em>IDictionary&lt;TKey, TValue&gt;</em> (and, by extension, from <em>ICollection&lt;T&gt;</em>, <em>IEnumerable&lt;T&gt;</em>, and <em>IEnumerable</em> as well).</p>



<p>The remaining properties that aren&#8217;t provided by <em>IDictionary&lt;TKey, TValue&gt;</em> are the capacity, the number of sets, and the number of ways. We&#8217;ll add these to our cache interface. </p>



<p>There is also one other method that might be useful. Remember that when we add a new cache item, it might evict an existing cache item. Most of the time it won&#8217;t matter what item gets evicted, but there may be scenarios in which we would want to know which item would be evicted if a new cache item were added. To that end, we&#8217;ll add a method to support such a scenario and call it <em>TryGetEvictKey</em>, following the pattern of <em>TryGetValue</em>. </p>



<p>Now we can finally define our cache interface, <em>ISetAssociativeCache&lt;TKey, TValue&gt;</em>.</p>



<pre class="wp-block-preformatted"><code class="language-csharp">using System.Collections.Generic;

namespace ParksComputing.SetAssociativeCache {
    // Represents a generic set-associative cache of key/value pairs.
    public interface ISetAssociativeCache&lt;TKey, TValue&gt; : IDictionary&lt;TKey, TValue&gt; {
        // Gets the capacity of the cache.
        int Capacity { get; }

        // Gets the number of sets in the cache.
        int Sets { get; }

        // Gets the capacity in each set.
        int Ways { get; }

        // If the given key would cause an existing cache item to be evicted, returns true and sets 
        // evictKey to the key of the cache item that would be evicted if the new key were added.
        bool TryGetEvictKey(TKey key, out TKey evictKey);
    }
}</code></pre>



<p>This interface will be implemented by concrete classes which provide the behavior of the set-associative cache. </p>



<h2>Implementing Cache-Eviction Policies</h2>



<p>We discussed in part 1 how cache items are evicted when a new cache item is added to a set which is already full, and there are several policies that can be implemented, depending on the specific use case for the cache. So far we have not addressed how those policies will be provided or implemented. </p>



<p>One method that I played with early on was inspired by Andrei Alexandrescu&#8217;s C++ policy-based design as described in <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Modern_C%2B%2B_Design" target="_blank">Modern C++ Design</a>. It involved supplying a policy class as a generic parameter to the concrete class that implemented <em>ISetAssociativeCache&lt;TKey, TValue&gt;</em>. In practice, instantiating a cache instance would look like the following:</p>



<pre class="wp-block-preformatted"><code class="language-csharp">ISetAssociativeCache&lt;string, string&gt; = new SetAssociativeCache&lt;string, string, LruPolicy&gt;(4, 2);</code></pre>



<p>Implementing it was a fun exercise, but after playing with it a while I realized that it didn&#8217;t really gain me anything. There was no practical difference between the code above and the following code, in terms of what clients had to write:</p>



<pre class="wp-block-preformatted"><code class="language-csharp">ISetAssociativeCache&lt;string, string&gt; = new LruCache&lt;string, string&gt;(4, 2);</code></pre>



<p>In other words, it made more sense to just put the policy into a concrete class that implemented the cache interface. </p>



<p>The only other variation I could come up with was the scenario of changing the policy at runtime:</p>



<pre class="wp-block-preformatted"><code class="language-csharp">ICachePolicy lruPolicy = new LruCachePolicy();
ISetAssociativeCache&lt;string, string&gt; cache = new FlexCache&lt;string, string&gt;(4, 2, LruCachePolicy);

// some time later, for some reason...
cache.Policy = new LfuCachePolicy();</code></pre>



<p>I couldn&#8217;t come up with a specific reason to do this, but I could at least imagine that it could happen in practice. Even so, that is an implementation detail can be left to specific implementations, so the <em>ISetAssociativeCache&lt;TKey, TValue&gt;</em> interface already provides enough functionality for most mainstream use cases.</p>



<p>The three policies that I&#8217;ve implemented so far are <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)" target="_blank">least-recently used (LRU)</a>, <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_replacement_policies#Most_recently_used_(MRU)" target="_blank">most-recently used (MRU)</a>, and <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_replacement_policies#Least-frequently_used_(LFU)" target="_blank">least-frequently used (LFU)</a>. All three of them ultimately derive from a common class that implements nearly all of the cache code. </p>



<p>There are some key differences in behavior between policies based on recency of use (LRU, MRU) and policies based on frequency of use. The xRU policies based on how recently a cache item was stored, updated, or accessed can be managed by sorting the keys in a set so that the most recently stored, updated, or accessed cache item is moved to the lowest index in the set, pushing the least-recently used item to the highest index. No other metadata needs to be stored. For other policies, such as ones based on how frequently a cache item is used, some data to track the implementation of the policy must be provided.</p>



<p>In order to keep as much common code as possible in a single class, let&#8217;s re-evaluate how the key array is stored. In part 1 we considered this layout:</p>



<pre class="wp-block-preformatted"><code class="language-csharp">int[] keyArray;</code></pre>



<p>I hinted at the time that we would change this definition, and this is why. We need to provide another bit of data alongside the index into the value array. Let&#8217;s change the definition to the following:</p>



<pre class="wp-block-preformatted"><code class="language-csharp">KeyValuePair&lt;int, int&gt;[] keyArray;</code></pre>



<p>Even though LRU and MRU policies don&#8217;t use the second <em>int</em>, most other policies will make use of it. LFU will increment it each time a cache item is accessed. Policies based on a cache item&#8217;s age might use the second <em>int</em> to store a date/time stamp.</p>



<h2>The Class Structure</h2>



<p>Given that xRU policies and xFU policies diverge on how they track aging of cache items, but otherwise share the vast majority of the rest of their code, we can consider a class structure like the following:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://www.parkscomputing.com/wp-content/uploads/set-associative-cache-class-diagram.jpg"><img decoding="async" loading="lazy" width="804" height="430" src="https://www.parkscomputing.com/wp-content/uploads/set-associative-cache-class-diagram.jpg" alt="" class="wp-image-1811" srcset="https://www.parkscomputing.com/wp-content/uploads/set-associative-cache-class-diagram.jpg 804w, https://www.parkscomputing.com/wp-content/uploads/set-associative-cache-class-diagram-300x160.jpg 300w, https://www.parkscomputing.com/wp-content/uploads/set-associative-cache-class-diagram-768x411.jpg 768w" sizes="(max-width: 804px) 100vw, 804px" /></a></figure></div>


<p>The only class here that we haven&#8217;t discussed is <em><a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlydictionary-2?view=net-5.0" target="_blank">IReadOnlyDictionary&lt;TKey, TValue&gt;</a></em>. This allows clients to share the cache in a read-only manner, such that clients may access the data in the cache without being able to modify it.</p>



<h2>Coming Up</h2>



<p>In the next and final article, we’ll finally implement the class structure above and try the cache in some sample code.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.parkscomputing.com/2021/08/set-associative-cache-in-c-part-2-interface-design/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Set-Associative Cache in C#, Part 1: Analysis &#038; Initial Design</title>
		<link>https://www.parkscomputing.com/2021/08/set-associative-cache-in-c-part-1-analysis-initial-design/</link>
					<comments>https://www.parkscomputing.com/2021/08/set-associative-cache-in-c-part-1-analysis-initial-design/#respond</comments>
		
		<dc:creator><![CDATA[paulmooreparks]]></dc:creator>
		<pubDate>Sun, 01 Aug 2021 09:16:05 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[writing]]></category>
		<category><![CDATA[csharp]]></category>
		<guid isPermaLink="false">https://www.parkscomputing.com/?p=1599</guid>

					<description><![CDATA[A couple of weeks ago, I had never heard of a set-associative cache. Then, I was assigned an interview exercise on HackerRank entitled &#8220;Set-Associative Cache Optimization&#8221;. (I won&#8217;t give away the company or any details about the exercise, since that wouldn&#8217;t be fair.) Since I hadn&#8217;t heard of such a cache, I decided to learn &#8230;<br><a href="https://www.parkscomputing.com/2021/08/set-associative-cache-in-c-part-1-analysis-initial-design/" class="more-link pen_button pen_element_default pen_icon_arrow_double">Continue reading <span class="screen-reader-text">Set-Associative Cache in C#, Part 1: Analysis &#038; Initial Design</span></a>]]></description>
										<content:encoded><![CDATA[
<p>A couple of weeks ago, I had never heard of a set-associative cache. Then, I was assigned an interview exercise on <a href="https://www.hackerrank.com/">HackerRank</a> entitled &#8220;Set-Associative Cache Optimization&#8221;. (I won&#8217;t give away the company or any details about the exercise, since that wouldn&#8217;t be fair.) Since I hadn&#8217;t heard of such a cache, I decided to learn about it and implement one in C# before I started the assignment, just for practice.</p>



<p>The first thing I learned is that a set-associative cache is more of a hardware concept than a software one, but that they do exist in software. The second thing I learned is that they&#8217;re a topic of a fair amount of academic study — I slogged through one paper and queued up a few more in some browser tabs before, ultimately, I decided to implement something fairly straightforward and make it extensible. I find that I learn better by doing than by reading.</p>



<p>Once the project was on <a rel="noreferrer noopener" href="https://github.com/paulmooreparks/SetAssociativeCache/" target="_blank">my GitHub repository</a>, I decided to write this series of articles, where I walk through the code, describe how the cache works, explain why I made the design decisions I made, and generally show the process of writing a professional-grade data structure for .NET in C#.</p>



<p>In part 1, we&#8217;ll try to understand how set-associative caches work and come up with a basic design. In <a href="/2021/08/set-associative-cache-in-c-part-2-interface-design/" target="_blank" rel="noreferrer noopener">part 2</a>, we&#8217;ll expand on the design a bit more and define a code interface for the cache. In part 3, we&#8217;ll turn the design into working code.</p>



<h2>A Few Words About the Design Process</h2>



<p>While these articles will appear to present a somewhat linear process of design and implementation, the actual process was a more iterative and exploratory. I followed the basic steps in this series of articles, but I didn&#8217;t do so rigidly. My general approach to designing and developing a new bit of software is the following:</p>



<ul>
<li>Analysis: Understand the problem
<ul>
<li>Sketch it out on the whiteboard</li>



<li>Define the data involved in the problem</li>



<li>Discover the algorithms and step through them manually</li>



<li>Consider how the software will be used in production</li>
</ul>
</li>



<li>Design: Propose a solution
<ul>
<li>More of the steps above, but at a lower level this time</li>



<li>Consider platforms, languages, libraries</li>



<li>Examine and compare alternative designs</li>



<li>Consider usability, performance, testability, and all such requirements</li>



<li>Look for existing designs and implementations so that I don&#8217;t re-invent the wheel</li>



<li>Talk about and write about the problem and the proposed solution</li>
</ul>
</li>



<li>Implementation: Bring the design into reality to solve the problem
<ul>
<li>If I get stuck, reconsider the design or the analysis and see if I missed something</li>
</ul>
</li>
</ul>



<p>&#8220;OMG! That&#8217;s&#8230; that&#8217;s&#8230; <a href="http://www-scf.usc.edu/~csci201/lectures/Lecture11/royce1970.pdf" target="_blank" rel="noreferrer noopener">WATERFALL</a>!&#8221; No, no, it&#8217;s careful consideration of the problem before committing to an implementation. These aren&#8217;t rigid phases of any development process handed down from on high. It&#8217;s just a reasonable way to approach software development. I may even write exploratory, proof-of-concept code during analysis, and some of that code (maybe all, if I&#8217;m lucky) may find its way into the final implementation. I may get all the way into implementation and discover that I need to redo the design. In my experience, the more carefully I understand the problem, and the more diligently I design the solution, the smoother the implementation will be.</p>



<p>Even while writing these articles, I would update the implementation as better ideas occurred to me, and I fixed a few design and implementation bugs along the way as well. If you&#8217;re new to software development, don&#8217;t worry if you find yourself in a similar kind of loop. A little patience up front, and a willingness to admit later that you didn&#8217;t understand something as well as you thought you did, will pay dividends over the course of your career.</p>



<h2>How Does a Set-Associative Cache Work?</h2>



<p>I&#8217;m not going to dive too deeply into <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_(computing)" target="_blank">caching theory</a> here. As I said earlier, it&#8217;s a <a rel="noreferrer noopener" href="https://dspace.mit.edu/bitstream/handle/1721.1/87159/45168931-MIT.pdf" target="_blank">topic of study for computer scientists</a>. I&#8217;ll just present an overview of set-associative caches, and I&#8217;ll give you a few links along the way where you can dig deeper.</p>



<p>A <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_placement_policies#Set-associative_cache" target="_blank">set-associative cache</a> is a cache that is split into sets of cache entries, or cache lines. This is a compromise between two other extremes: a <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_placement_policies#Direct-mapped_cache" target="_blank">direct-mapped cache</a> and a <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_placement_policies#Fully_associative_cache" target="_blank">fully associative cache</a>. Each set may have one or more &#8220;ways&#8221;, where each &#8220;way&#8221; is single cache entry. </p>



<p>In order to make it easier to visualize how such a cache works, I&#8217;m going to use tables that represent a cache with 3 sets and 3 ways per set. Such a cache would be laid out as follows:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th colspan="3">Set 0</th><th colspan="3">Set 1</th><th colspan="3">Set 2</th></tr>
<tr><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th></tr></thead><tbody><tr>
    <td>Data</td>
    <td>Data</td>
    <td>Data</td>
    <td>Data</td>
    <td>Data</td>
    <td>Data</td>
    <td>Data</td>
    <td>Data</td>
    <td>Data</td>
</tr></tbody></table></figure>



<p>When a new cache item is added to the cache, it is assigned to a set, either via an intrinsic tag (like an address range) or some other algorithm, such as a hash function. I won&#8217;t get into all the ways that this can happen; instead, I&#8217;ll focus on this C# implementation, which uses a hash function on the key in order to choose which set the key/value pair is stored in.</p>



<p>Let&#8217;s say, for example, that we want to cache pairs of celebrity couples. Why you would want to do this in real life, I have no idea, but they&#8217;re a much more compact form of data to draw on whiteboards or type into WordPress than HTTP responses or database results. When we add an item to the cache with the key &#8220;Brad&#8221; and the value &#8220;Angelina&#8221;, the key is hashed using a <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function" target="_blank">Fowler-Noll-Vo 1a hash function</a> (FNV-1a). This returns the 64-bit value 7469233897810807560. This huge number isn&#8217;t terribly helpful on its own, so we take the number modulo the number of sets (in this example, 3) to determine which set, from 0 to 2, that the item should be placed into. This gives us the number 0, so this key/value pair will go into set 0. There are three ways in each set, but all are empty at the start, so Brad and Angelina will go into the first way (way 0) in the first set (set 0).</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th colspan="3">Set 0</th><th colspan="3">Set 1</th><th colspan="3">Set 2</th></tr>
<tr><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th></tr></thead><tbody><tr>
    <td>Brad, Angelina</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
</tr></tbody></table></figure>



<p>Let&#8217;s add another pair: &#8220;Kanye&#8221; and &#8220;Kim&#8221;. &#8220;Kanye&#8221; hashes to 12815697388183119611 which, modulo 3, yields 2, so Kanye and Kim go into the first empty way in set 2:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th colspan="3">Set 0</th><th colspan="3">Set 1</th><th colspan="3">Set 2</th></tr>
<tr><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th></tr></thead><tbody><tr>
    <td>Brad, Angelina</td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td></td>
    <td>Kanye, Kim</td>
    <td></td>
    <td></td>
</tr></tbody></table></figure>



<p>We can keep adding couples until, eventually, we encounter a situation where all three ways in a set are full. If we have added Brad &amp; Angelina, Kanye &amp; Kim, Ben &amp; Jennifer, and Burt &amp; Loni, the cache will look like the following:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th colspan="3">Set 0</th><th colspan="3">Set 1</th><th colspan="3">Set 2</th></tr>
<tr><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th></tr></thead><tbody><tr>
    <td>Brad, Angelina</td>
    <td>Ben, Jennifer</td>
    <td>Burt, Loni</td>
    <td></td>
    <td></td>
    <td></td>
    <td>Kanye, Kim</td>
    <td></td>
    <td></td>
</tr></tbody></table></figure>



<p>What happens if we try to add Kurt &amp; Goldie? Since the hash for &#8220;Kurt&#8221; modulo 3 is 0, that couple should go into set 0, but that set is already full. What do we do?</p>



<p>This is where the <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_replacement_policies" target="_blank">cache replacement policy</a> comes into effect. The cache needs a policy for how to remove existing cache items to make room for new ones. There are several policies to choose from, such as <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)" target="_blank">least-recently used (LRU)</a>, <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_replacement_policies#Least-frequently_used_(LFU)" target="_blank">least-frequently used (LFU)</a>, <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_replacement_policies#Most_recently_used_(MRU)" target="_blank">most-recently used (MRU)</a>, and <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Cache_replacement_policies" target="_blank">many others</a>. If we use a least-recently used, or LRU, policy, then we should remove the item that hasn&#8217;t been stored or accessed as recently as any other item in the set. In our example, that will be Brad &amp; Angelina, so they are evicted to make way for Kurt &amp; Goldie:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th colspan="3">Set 0</th><th colspan="3">Set 1</th><th colspan="3">Set 2</th></tr>
<tr><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th></tr></thead><tbody><tr>
    <td>Kurt, Goldie</td>
    <td>Ben, Jennifer</td>
    <td>Burt, Loni</td>
    <td></td>
    <td></td>
    <td></td>
    <td>Kanye, Kim</td>
    <td></td>
    <td></td>
</tr></tbody></table></figure>



<p>We can carry on adding couples to the cache and evicting other couples as necessary until the cache is finally full.
</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th colspan="3">Set 0</th><th colspan="3">Set 1</th><th colspan="3">Set 2</th></tr>
<tr><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th><th>Way 0</th><th>Way 1</th><th>Way 2</th></tr></thead><tbody><tr>
    <td>Kurt, Goldie</td>
    <td>Ben, Jennifer</td>
    <td>Burt, Loni</td>
    <td>Desi, Lucy</td>
    <td>John, Yoko</td>
    <td>Tom, Rita</td>
    <td>Kanye, Kim</td>
    <td>Sonny, Cher</td>
    <td>Johnny, June</td>
</tr></tbody></table></figure>



<p>If we add a new couple now, then no matter what set the couple ends up in, they will evict the least-recently used couple in that set.</p>



<h2>Design</h2>



<p>If you&#8217;re familiar with the design and implementation of hash tables, you may see some resemblance between the description above and the way that hash tables work. (If you&#8217;d like a good introduction to hash table implementation, read <a rel="noreferrer noopener" href="https://benhoyt.com/writings/hash-table-in-c/" target="_blank">Ben Hoyt&#8217;s excellent article on implementing a hash table in C</a>.) The key difference here is that in a hash table, the table expands to accommodate new key/value pairs, whereas in a cache there is a fixed capacity for elements and a policy for removing elements when the cache is full.</p>



<p>From the user&#8217;s point of view, I decided to make using the cache feel like using hash table (or, more generally, a dictionary). Inserting an element into the cache might be done using the same kind of indexing syntax used in a .NET dictionary, and retrieval of an element might be done with a <em>TryGetValue</em> method.</p>



<pre class="wp-block-preformatted"><code class="language-csharp">coupleCache["Brad"] = "Angelina";
string value;
bool hasBrad = coupleCache.TryGetValue("Brad", out value);</code></pre>



<p>These are probably the two most common operations on a cache, and they need to be <em>really, really</em> fast. Let&#8217;s look at what&#8217;s involved in making these operations work.</p>



<p>First of all, consider testing for the presence of a key in the cache. We need to be able to quickly hash the key, find the set the key is in, then search the set for the key. This needs to be done when adding an item to the cache,     and it also needs to be done when retrieving a value from the cache. Did I mention that this needs to be <em>really, really</em> fast? If it isn&#8217;t significantly faster to find and retrieve an item from the cache than from the     original data source, then the cache is pointless.</p>



<p>Let&#8217;s consider some possible <a rel="noopener" href="https://www.tutorialspoint.com/data_structures_algorithms/index.htm" target="_blank">data structures and algorithms</a>. A naïve implementation might use a linked list of key/value pairs to represent a single set, where the capacity of the linked list would be the number of ways in the set. Here are some pros:</p>



<ul>
<li>We can use the existing&nbsp;<em>LinkedList&lt;T&gt;</em> class to store our key/value pairs (using the <em>KeyValuePair&lt;TKey, TValue&gt;</em> class).</li>



<li>Adding, removing, and inserting items is fairly simple.</li>



<li>We can easily reorder the linked list if we need to (for example, to maintain removal policy).</li>
</ul>



<p>There are cons, however:</p>



<ul>
<li>We would be using a general purpose class, <em>LinkedList</em>, for a very special purpose.</li>



<li>Adding, removing, and inserting items is simple, and it&#8217;s generally faster in the worst case, but in the normal case it might not be as fast as we need it to be.</li>



<li>Cache data would be co-located with housekeeping data, which might limit our implementation and performance options.</li>



<li>Speaking of caches, linked lists are not very friendly to CPU caches.</li>
</ul>



<p>Let&#8217;s look again at the constraints of the cache specification.</p>



<ul>
<li>We need to create caches with a fixed numbers of sets, where each set has a fixed number of ways.</li>



<li>We need to allow clients to tune the numbers of sets and ways to obtain the best performance for their specific scenarios.</li>



<li>We need to store any type of key and any type of value.</li>



<li>We need to be <strong>FAST</strong>!</li>
</ul>



<p>Let&#8217;s consider how users might want to create a cache in the first place. Much like the generic <a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=net-5.0" target="_blank">Dictionary</a> type, users may want to provide the specific key and value types, so we&#8217;ll design for a generic interface. For our earlier example, which is a cache with string keys, string values, 3 sets of 3 items per set, and a least-recently used replacement policy, the code defining the cache instance might look like the following:</p>



<pre class="wp-block-preformatted"><code class="language-csharp">LruCache&lt;string, string&gt; coupleCache = new (sets: 3, ways: 3);</code></pre>



<p>If we presume this usage pattern, then we can see that, at compile time, we know the both the total capacity of the cache and the replacement policy for evicting cache items. A fixed capacity is a hint than instead of linked lists, maybe we should consider arrays.</p>



<p>Many of you may already be saying, &#8220;NO! Inserting and rearranging items in arrays is SLOW!&#8221; Some of you, however, may be nodding and saying, &#8220;<a href="https://knowyourmeme.com/memes/money-printer-go-brrr" target="_blank" rel="noreferrer noopener">Haha array go brrrrr</a>.&#8221;</p>


<div class="wp-block-image">
<figure class="aligncenter size-full is-resized"><a href="https://www.parkscomputing.com/wp-content/uploads/array-go-brrrrr.png"><img decoding="async" loading="lazy" src="https://www.parkscomputing.com/wp-content/uploads/array-go-brrrrr.png" alt="" class="wp-image-1682" width="601" height="338" srcset="https://www.parkscomputing.com/wp-content/uploads/array-go-brrrrr.png 800w, https://www.parkscomputing.com/wp-content/uploads/array-go-brrrrr-300x169.png 300w, https://www.parkscomputing.com/wp-content/uploads/array-go-brrrrr-768x432.png 768w" sizes="(max-width: 601px) 100vw, 601px" /></a></figure></div>


<p>Consider what we need to store, and what state we need to maintain, in order to make the cache work:</p>



<ul>
<li>Store the key/value pairs for the cache items.</li>



<li>Track what items are in what sets.</li>



<li>Track metadata in each set for maintaining the cache eviction policy.</li>



<li>Track whether a given set is full.</li>
</ul>



<p>We know that finding and retrieving a key/value pair has to be as fast as possible. Let&#8217;s step through the process again:</p>



<ol>
<li>Hash the key</li>



<li>Find the set that stores the key</li>



<li>Find which way in the set contains the key</li>



<li>Use the key to get the value</li>
</ol>



<p>We&#8217;ll consider step 1 to be a fixed cost, although it&#8217;s something we can possibly optimize later. Step two is just a modulo operation. Step three implies that we have to search the set for the key, and this is where the proverbial rubber meets the road. One of the advantages of using a set-associative cache is that it can minimize the impact of this step. Rather than searching every element in the cache, we only have to search the number of ways in a set, and we don&#8217;t want too many ways in a set anyway.</p>



<p>Let&#8217;s consider two arrays. The first array stores the actual data:</p>



<pre class="wp-block-preformatted"><code class="language-csharp">KeyValuePair&lt;TKey, TValue&gt;[] valueArray;</code></pre>



<p>In our example of celebrity couples, we used a 3-set, 3-way cache. That would mean our value array would have nine elements (3 times 3) when the cache is instantiated, and it would stay that size. When a key/value pair is placed into a location in the array, we want it to stay there until it needs to be removed to make room for another item. We definitely&nbsp;<strong>don&#8217;t </strong>want to do any sorting or insertion on this array, since there is a potential for storing arbitrarily large value types in the array. That means we need to manage the bookkeeping in a separate data structure. Since we already have the keys in this array, we only need to keep track of the indices into this array so that we can quickly find them when needed. Let&#8217;s make another array of integers.</p>



<pre class="wp-block-preformatted"><code class="language-csharp">int[] keyArray;</code></pre>



<p>This array stores the indices to items in <em>valueArray</em>. It is partitioned by set. It doesn&#8217;t matter where the actual key/value pairs are stored in the value array, as long as we track them here. (To be completely honest, we&#8217;re going to change this slightly in the implementation, but for simplicity we&#8217;ll stick with this definition for now.)</p>



<p>Let&#8217;s walk through our earlier examples above using this design.</p>



<p>When we create the key array and size it as sets times ways, we get this by default:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>0</td>
    <td>0</td>
    <td>0</td>
    <td>0</td>
    <td>0</td>
    <td>0</td>
    <td>0</td>
    <td>0</td>
    <td>0</td>
</tr></tbody></table></figure>



<p>That isn&#8217;t very helpful, since all of the elements point at the first index in the value array. We need a sentinel value to tell us when a location in the key array is available. We&#8217;ll fill the empty array with <em>int.MaxValue</em> when the cache is created or cleared, so that the fresh key array looks like the following in memory:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
</tr></tbody></table></figure>



<p>That&#8217;s a little bit better. This array will easily fit into the CPU cache, which means we can operate on it very quickly. </p>



<p>Now, when we add Brad and Angelina, we can quickly see that the first element in set 0, which also happens to be key-array index 0, is empty. Next, we just need to find an empty spot in the value array where we can place the key/value pair. Uh-oh&#8230; how do we do that? Remember, <em>KeyValuePair&lt;TKey,TValue&gt;</em> is a value type, so a fresh array of <em>KeyValuePair&lt;string,string&gt;</em> would look like the following:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>[null,null]</td>
    <td>[null,null]</td>
    <td>[null,null]</td>
    <td>[null,null]</td>
    <td>[null,null]</td>
    <td>[null,null]</td>
    <td>[null,null]</td>
    <td>[null,null]</td>
    <td>[null,null]</td>
</tr></tbody></table></figure>



<p>That might work if you assume that a null key, or maybe a null value, indicates an empty slot, but what if your key and value types are integers?</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>[0,0]</td>
    <td>[0,0]</td>
    <td>[0,0]</td>
    <td>[0,0]</td>
    <td>[0,0]</td>
    <td>[0,0]</td>
    <td>[0,0]</td>
    <td>[0,0]</td>
    <td>[0,0]</td>
</tr></tbody></table></figure>



<p>It&#8217;s entirely possible that zero is a valid key and/or value in such a cache. This definition won&#8217;t work. We need to make the array items <a rel="noopener" href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types" target="_blank">nullable</a> by adding a <em>?</em> after the type and before the array brackets so that we can distinguish an empty cache slot from an occupied one.</p>



<pre class="wp-block-preformatted"><code class="language-csharp">KeyValuePair&lt;TKey, TValue&gt;?[] valueArray; // The ? makes this nullable</code></pre>



<p>That way, by default, the value array is initialized thus:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
</tr></tbody></table></figure>



<p>Following these steps to add Brad &amp; Angelina, we get the following contents for the key array, where element 0 contains the index in the value array where Brad &amp; Angelina are stored (which also happens to be element 0).</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>0</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
</tr></tbody></table></figure>



<p>Likewise, for the value array:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>[Brad, Angelina]</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
</tr></tbody></table></figure>



<p>After we add Kanye &amp; Kim, we get the following contents for the key array, where now element 6 contains the index for the location of Kanye &amp; Kim in the value array (which, again, also happens to be element 6):</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>0</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>6</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
</tr></tbody></table></figure>



<p>Likewise, for the value array:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>[Brad, Angelina]</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>[Kanye, Kim]</td>
    <td>null</td>
    <td>null</td>
</tr></tbody></table></figure>



<p>So far it just looks like we have an unnecessary level of indirection to the value array, since the key array elements contain the corresponding indices into the value array, but let&#8217;s look at the case where we add another item to a set. Suppose that we want to add Ben &amp; Jennifer. They will end up in set zero next to Brad &amp; Angelina. However, we will need to do some bookkeeping now. If we&#8217;re using a least-recently used cache eviction policy, then we need to re-arrange the elements in the key array that correspond to the set so that, if we need to evict a cache item, we can easily find the least-recently used key. Let&#8217;s presume that we&#8217;ll always put the&nbsp;<em>most</em>-recently used key at the lowest index in the set, and we&#8217;ll move the other items to higher indices in the set up to make room for it.&nbsp;That will push the <em>least</em>-recently used key to the highest index in the set.</p>



<p>When we place Ben &amp; Jennifer into set 0 (elements 0, 1 and 2), then in the key array we shift the contents of element 1 into element 2 and element 0 into element 1, and we put the new value index into element 0. That makes Ben &amp; Jennifer the least-recently used cache item in the set. However, when we search for the next available value index in the value array, we find that Ben &amp; Jennifer will be stored at element 1. That means our key array will look like the following:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>1</td>
    <td>0</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>6</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
</tr></tbody></table></figure>



<p>The value array, however, will look like the following:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>[Brad, Angelina]</td>
    <td>[Ben, Jennifer]</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>[Kayne, Kim]</td>
    <td>null</td>
    <td>null</td>
</tr></tbody></table></figure>



<p>When we add Burt &amp; Loni into set 0, we do another shift in the key array so that the value index for Brad &amp; Angelina is stored in the key array&#8217;s highest index for set zero, meaning they&#8217;ll be up for eviction when another item is added to set zero, unless their key is accessed before then. The key array would look like the following:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>2</td>
    <td>1</td>
    <td>0</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>6</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
</tr></tbody></table></figure>



<p>The value array would look like the following:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>[Brad, Angelina]</td>
    <td>[Ben, Jennifer]</td>
    <td>[Burt, Loni]</td>
    <td>null</td>
    <td>null</td>
    <td>null</td>
    <td>[Kayne, Kim]</td>
    <td>null</td>
    <td>null</td>
</tr></tbody></table></figure>



<p>We also need to adjust the indices when cache items are retrieved. With the LRU policy, every time a cache item is accessed, its key should be moved into the lowest index, pushing the rest of the items higher. Consider what would happen if the client code retrieved the item with the key &#8220;Brad.&#8221; That item&#8217;s index (index 0) would be moved into the spot for the most-recently used item:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><tbody><tr><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th><th>5</th><th>6</th><th>7</th><th>8</th></tr><tr>
    <td>0</td>
    <td>2</td>
    <td>1</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
    <td>6</td>
    <td>0x7FFFFFFF</td>
    <td>0x7FFFFFFF</td>
</tr></tbody></table></figure>



<p>The actual cache data in the value array would not change, however.</p>



<p>You can now see that the indices in the key array float around independently of the actual values in the value array. Because the key array just contains integers and is quite compact, it&#8217;s <strong>blazing</strong> fast to reorder elements in the array, much faster than with a linked list. I know, I&#8217;ve tried it.</p>



<p>Let me add a disclaimer for the Yeahbutters and the Whataboutists. I&#8217;m not saying that linked lists are never a good idea, or that they never out-perform arrays. I&#8217;m saying that in this particular usage scenario, where arrays can make better use of CPU cache and optimizations and intrinsics, arrays generally perform better. One should, however, always benchmark one&#8217;s code and test one&#8217;s assumptions with real-world data under real-world conditions.</p>



<p>Now that we have the overall design, in <a href="/2021/08/set-associative-cache-in-c-part-2-interface-design/" target="_blank" rel="noreferrer noopener">the next article</a> we&#8217;ll dig a little deeper into the design and look at how to handle alternative cache-eviction policies. Then, we&#8217;ll consider what code interface to provide for users of the cache.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.parkscomputing.com/2021/08/set-associative-cache-in-c-part-1-analysis-initial-design/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>I&#8217;m Back!</title>
		<link>https://www.parkscomputing.com/2021/06/im-back/</link>
					<comments>https://www.parkscomputing.com/2021/06/im-back/#respond</comments>
		
		<dc:creator><![CDATA[paulmooreparks]]></dc:creator>
		<pubDate>Wed, 16 Jun 2021 13:12:44 +0000</pubDate>
				<category><![CDATA[writing]]></category>
		<guid isPermaLink="false">https://www.parkscomputing.com/?p=1560</guid>

					<description><![CDATA[&#8220;Hello, hello again.&#8221; The Cars This web site has languished long enough. It&#8217;s finally time to dust off those eleven draft posts that have been sitting around for years and start producing content again. Over the last couple of months I&#8217;ve been working on my wife&#8217;s web site for her psychology practice, a WordPress site &#8230;<br><a href="https://www.parkscomputing.com/2021/06/im-back/" class="more-link pen_button pen_element_default pen_icon_arrow_double">Continue reading <span class="screen-reader-text">I&#8217;m Back!</span></a>]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote"><p>&#8220;Hello, hello again.&#8221;</p><cite><a href="https://genius.com/The-cars-hello-again-lyrics" target="_blank" rel="noreferrer noopener">The Cars</a></cite></blockquote>



<p>This web site has languished long enough. It&#8217;s finally time to dust off those eleven draft posts that have been sitting around for years and start producing content again.</p>



<p>Over the last couple of months I&#8217;ve been working on <a rel="noreferrer noopener" href="https://padmajairam.com/" target="_blank">my wife&#8217;s web site for her psychology practice</a>, a WordPress site similar to this one, and it got me thinking that I should update my web development skills. I started writing HTML in 1995, but I&#8217;m just now learning things like <a rel="noreferrer noopener" href="https://reactjs.org/" target="_blank">ReactJS</a> and <a rel="noreferrer noopener" href="https://www.ecma-international.org/publications-and-standards/standards/ecma-262/" target="_blank">modern JavaScript</a> and all of the new tooling involved in professional web development.</p>



<p>Here are some of the things that are in the pipeline:</p>



<ul><li>A refresh of my <a href="https://www.parkscomputing.com/webapps/" target="_blank" rel="noreferrer noopener">web apps</a>, implemented with ReactJS, especially my <a href="/webapps/conways-game-of-life/" target="_blank" rel="noreferrer noopener">JavaScript implementation of Conway&#8217;s Game of Life</a>.</li><li>A web implementation of <a href="https://github.com/paulmooreparks/Tortilla" target="_blank" rel="noreferrer noopener">my virtual 64-bit CPU</a>.</li><li><em>Maybe</em> a web version of the <a href="/applications/pbrain/" data-type="URL" data-id="/applications/pbrain/" target="_blank" rel="noreferrer noopener">pbrain compiler</a>.</li><li>Those eleven draft articles I mentioned earlier.</li></ul>



<p>Of course, I might get into that list, get inspired, and make a left turn somewhere on the road between Serendipity and Distraction. We&#8217;ll see.</p>



<p>Whatever happens, it&#8217;s good to be back.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.parkscomputing.com/2021/06/im-back/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Barbecue and Project Management</title>
		<link>https://www.parkscomputing.com/2016/06/barbecue-and-project-management/</link>
					<comments>https://www.parkscomputing.com/2016/06/barbecue-and-project-management/#respond</comments>
		
		<dc:creator><![CDATA[paulmooreparks]]></dc:creator>
		<pubDate>Fri, 10 Jun 2016 21:10:16 +0000</pubDate>
				<category><![CDATA[analogies]]></category>
		<category><![CDATA[project management]]></category>
		<category><![CDATA[barbecue]]></category>
		<category><![CDATA[software]]></category>
		<guid isPermaLink="false">https://www.parkscomputing.com/?p=1299</guid>

					<description><![CDATA[As I begin to write this article, it&#8217;s 8:30 on the Saturday morning of Memorial Day weekend, the de facto start of the summer season in the United States. In most parts of the country, and especially in the South where I live, that means it&#8217;s also barbecue season. I take my barbecue seriously, so &#8230;<br><a href="https://www.parkscomputing.com/2016/06/barbecue-and-project-management/" class="more-link pen_button pen_element_default pen_icon_arrow_double">Continue reading <span class="screen-reader-text">Barbecue and Project Management</span></a>]]></description>
										<content:encoded><![CDATA[<p>As I begin to write this article, it&#8217;s 8:30 on the Saturday morning of Memorial Day weekend, the de facto start of the summer season in the United States. In most parts of the country, and especially in the South where I live, that means it&#8217;s also barbecue season.</p>
<p>I take my barbecue seriously, so I awoke at 4:00 this morning to start smoking a pork butt for a party this evening. I&#8217;m also rather old-fashioned about preparing barbecue, so I use a barrel smoker with a firebox rather than an electric smoker or an automatic pellet feeder. Not only do I like the end product better, but I also enjoy the process of smoking with an actual fire.</p>
<p>Preparing barbecue this way isn&#8217;t easy, though. There&#8217;s a lot of craft involved. I have to select the right kind of wood, with the right amount of seasoning (not too green, not too dry). I have to keep the fire just low enough to keep the temperature in the smoker in a narrow range. I also have to keep the fire burning and not smoldering to impart the best flavor to the meat.</p>
<p>Going through this process got me thinking about a few parallels with project management, particularly in the field of software development.</p>
<p><strong>The temperature trend is more important than the current temperature.</strong></p>
<p>Keeping the fire in the right range isn&#8217;t just about the current temperature. It&#8217;s about knowing which way the temperature is headed. If it&#8217;s headed up, I need to prepare to open the vent to let out a little more heat in case it gets too high. If it&#8217;s headed down, I might need to add a bit more wood. That&#8217;s not the whole story, though. I need to see where the temperature might settle before I do anything drastic. If it&#8217;s above 300° F or below 200° F, it&#8217;s clearly in a bad place, but I still need to know where it&#8217;s heading before I get too excited.</p>
<p><em>Parallel: It&#8217;s difficult to jump into a project and know just how it stands until you get a sense of what kind of progress, or lack of progress, is being made. A metric may tell a story, but multiple metrics tell a more complete story.</em></p>
<p><figure id="temperature" aria-describedby="caption-temperature" style="width: 600px" class="wp-caption alignnone"><a href="http://parkscomputing.com/images/temperature.jpg" target="_blank"><img decoding="async" loading="lazy" class="center" src="http://parkscomputing.com/images/temperature.jpg" alt="" width="800" height="600" /></a><figcaption id="caption-temperature" class="wp-caption-text">Should I add wood, open the vent, or leave the fire alone?</figcaption></figure></p>
<p><strong>Have a stack of wood chopped, split, and ready to add to the fire.</strong></p>
<p>I started working on my stack of wood yesterday afternoon, and even this morning I&#8217;m chopping, splitting, inspecting, and sourcing more wood. I don&#8217;t want to get caught with a dying fire and no prepared wood to add to it.</p>
<p><em>Parallel: When a project is critically understaffed, that&#8217;s the wrong time to start recruiting, interviewing, hiring, and training. A well-tended talent pipeline is critical for handling staffing disruptions on a long-running project.</em></p>
<p><strong>Add wood to the fire before you need it, not after.</strong></p>
<p>If I add a perfectly seasoned, quarter-split piece of wild cherry log to a dying bed of coals, the temperature in the smoker is going to drop precipitously, and I&#8217;ll find myself furiously blowing on the embers to &#8220;inspire&#8221; the fire to light so it can cook the meat.</p>
<p><em>Parallel: Adding an qualified, experienced hire to a staff that is overworked (and, like an ember, &#8220;burned out&#8221;) will not yield as effective a result as adding the same hire to a staff that is fully engaged. The new hire can get up to speed on the project more quickly when the team can take the time to train the hire and share their unique team culture.</em></p>
<p><strong>Add the right kind of wood, in the right amount.</strong></p>
<p>Different kinds or cuts of meat call for different kinds of wood. Hickory will impart a strong flavor to a couple of racks of ribs smoked for an afternoon. A large pork butt or brisket may call for a little bit milder smoke flavor, since those have to be smoked for several hours. Poultry may call for an even milder smoke. Even with the right wood, too little may not keep the fire going, and too much may either smother it or overheat it.</p>
<p><em>Parallel: Staffing a project, at the start and especially when it&#8217;s in-progress, calls for the same kind of care. Most of us probably have seen a project with too many bodies thrown at it, or without the right amount or mix of talent at inception.</em></p>
<p><strong>Messing with the fire makes the temperature go down before it goes up.</strong></p>
<p>Whenever I lift the lid on the firebox to check on the fire, I lose about 20° F of temperature in the smoker. It&#8217;s better to watch the trend on the thermometer or peek inside the firebox vent to see if it&#8217;s burning properly. Even so, I do have to open the lid to stoke the fire or add fuel. I can&#8217;t get too worked up when the fire&#8217;s &#8220;productivity&#8221; drops immediately after I&#8217;ve taken action to improve it. I have to trust that I&#8217;ve made the right change and let it take effect.</p>
<p><em>Parallel: Whenever a project is in trouble, managers tend to institute process changes and add status meetings and reports to track the effects of the changes. It&#8217;s not uncommon for those new reports to show that productivity has actually worsened. This can happen if there is overhead in learning the new process, or if the staff has to be trained on a new technology, or if there are additional meetings that initially take away from time that could be spent doing actual work. If the right changes have been made, however, productivity should eventually increase. A little trust and patience may be required.</em></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.parkscomputing.com/2016/06/barbecue-and-project-management/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Scheduling Every Minute, Revisited</title>
		<link>https://www.parkscomputing.com/2016/02/scheduling-every-minute-revisited/</link>
					<comments>https://www.parkscomputing.com/2016/02/scheduling-every-minute-revisited/#respond</comments>
		
		<dc:creator><![CDATA[paulmooreparks]]></dc:creator>
		<pubDate>Mon, 08 Feb 2016 16:08:20 +0000</pubDate>
				<category><![CDATA[productivity]]></category>
		<category><![CDATA[project management]]></category>
		<category><![CDATA[schedule control]]></category>
		<guid isPermaLink="false">https://www.parkscomputing.com/?p=1254</guid>

					<description><![CDATA[Note: I originally posted this article on LinkedIn.  “Planning is bringing the future into the present so that you can do something about it now.” —  Alan Lakein Late last year, I published an article entitled &#8220;How I Plan Every Minute of My Day to Stay Productive,&#8221; where I described my personal daily workflow of planning the &#8230;<br><a href="https://www.parkscomputing.com/2016/02/scheduling-every-minute-revisited/" class="more-link pen_button pen_element_default pen_icon_arrow_double">Continue reading <span class="screen-reader-text">Scheduling Every Minute, Revisited</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>Note: I originally <a href="https://www.linkedin.com/pulse/scheduling-every-minute-revisited-paul-parks">posted this article on LinkedIn</a>.</em></p>
<blockquote><p> “Planning is bringing the future into the present so that you can do something about it now.” —  <a href="https://en.wikipedia.org/wiki/Alan_Lakein" target="_blank" rel="noopener">Alan Lakein</a></p></blockquote>
<p>Late last year, I published an article entitled <a href="/2015/09/how-i-plan-my-day/" target="_blank" rel="noopener">&#8220;How I Plan Every Minute of My Day to Stay Productive,&#8221;</a> where I described my personal daily workflow of planning the tasks that I need to accomplish and then adjusting that plan as necessary throughout the day. I have a new job now, so I want to post an update on how well the approach is working in a new environment with new responsibilities, and how I&#8217;ve made a few tweaks to the process.</p>
<p>I&#8217;m now working in a vendor role embedded with the software-development team of a client company, and it&#8217;s easy to get pulled into many different directions. As with my previous position, I&#8217;m still working across time zones since my new employer is headquartered in the Pacific time zone and I&#8217;m three hours away in the Eastern time zone. There are also several more standing meetings and conference calls in this job, so finding large blocks of time for <a href="http://calnewport.com/books/deep-work/" target="_blank" rel="noopener">deep work</a> is even more challenging.</p>
<h3>Dealing With Email and Instant Messages</h3>
<p>I still have a lot of email to read and respond to every morning, most of it having arrived late the previous evening from the west-coast team. As before, I schedule time to dig through it in the morning and respond to whatever&#8217;s urgent, but mostly I flag items for review or response and schedule time later in the day to deal with them. One thing that I&#8217;ve started doing is taking a little more time between tasks to deal with emails, like peeking at my inbox to see if there&#8217;s anything urgent to be dealt with before I dive into the next task. I did this because <strong>I&#8217;ve disabled email notifications</strong>, both on my laptop and my phone. That way, I don&#8217;t have a constant barrage of bells and popups drawing my attention away from what I&#8217;m working on, like sirens calling me to the shoals of low productivity.</p>
<p>My new company makes more extensive use of instant messaging, which brings its own challenges. I usually prefer IM over phone calls, but again, I don&#8217;t want to have notifications popping up all the time. I&#8217;ll check my messages between tasks and give a quick response before starting the next task. If I&#8217;m working on a task that requires concentration over a long stretch of time, I&#8217;ll set my IM status to &#8220;busy&#8221; or even &#8220;do not disturb&#8221; to discourage frivolous interruptions.</p>
<h3>Scheduling Time for Recurring Tasks</h3>
<p>Besides dealing with email, I now make a weekly plan to set aside time during each day to deal with other recurring tasks. These tasks are usually at the end of the day (in the case of code reviews) or just before daily meetings (updating status). Once all the recurring tasks and meetings are scheduled, I fill in the open spaces with either important daily tasks or ongoing tasks that need to be chipped away.</p>
<p>The image below shows what my calendar looks like for the coming week, which will be particularly busy since I have a deliverable due (I&#8217;ve blurred some sensitive details). The first task of the day is 15 minutes spent on planning. The gold tasks are recurring tasks that need to be dealt with every day. I start by working through my email backlog, and I finish with code reviews. The brown blocks are meetings or meeting-related tasks, gray blocks are personal items such as lunch or commuting, and green items are administrative tasks unrelated to the customer.</p>
<p><a href="https://www.parkscomputing.com/images/next-week-calendar-blurred-1.png" target="_blank" rel="noopener"><img decoding="async" loading="lazy" class="center" src="https://www.parkscomputing.com/images/next-week-calendar-blurred-1.png" alt="" width="640" height="349" /></a></p>
<p>The orange blocks represent tasks related to the larger deliverable that is due by the end of the week. These are the items that I need to spend as much time on as possible, for as long a stretch of time as I can schedule. Some of the blocks are two hours or longer, which is a long time to sit at a laptop, so as I plan each day throughout the week I will probably break these down into one-hour chunks to give myself a chance to stand up, walk around, get a cup of fresh coffee, etc.</p>
<h3>Multi-Desktop Approach</h3>
<p>There is a risk to this approach. As I described in my first article, I will re-arrange tasks throughout the day as priorities change and new tasks appear. This can create a distraction of it&#8217;s own, with the temptation to switch to Outlook throughout the day and constantly fiddle with my schedule. To fight this, I create a new desktop in Windows 10 and keep my Outlook calendar window there. This way, I&#8217;m more likely to only change the schedule in between tasks.</p>
<h3>Scheduling Serendipity</h3>
<p>During weeks when there are not quite as many urgent tasks to be managed, I&#8217;ll schedule time for <a href="https://en.wikipedia.org/wiki/Serendipity" target="_blank" rel="noopener">serendipity</a>. This may sound like a contradiction, but finding innovative approaches to software development is a big part of my job and my career. A lot of these discoveries happen when reading articles linked from a few favorite web sites (lately, <a href="https://news.ycombinator.com/news" target="_blank" rel="noopener">Hacker News</a> has been a great source of these). If I allow myself to sneak a peek at these articles in between tasks, I run the risk of being pulled into a half-hour or more of link chasing. Instead, I&#8217;ll schedule time to peruse headlines or read articles that I&#8217;ve saved.</p>
<p>Serendipity may also derive from chance encounters with colleagues, so if you work in a field that tends to keep you chained to your desk (like software development), make a point of getting up and moving around periodically to connect with others around you. Schedule such time, if it helps. <a href="https://www.elementsbehavioralhealth.com/health-2/sit-less-desk-job/" target="_blank" rel="noopener">Besides, it&#8217;s good for you to get up from your desk and move.</a></p>
<h3>Moving Toward Deep Work</h3>
<p>My earlier article mentioned <a href="http://calnewport.com/blog/" target="_blank" rel="noopener">Cal Newport&#8217;s</a> research into what he calls <a href="http://calnewport.com/blog/2012/11/27/some-notes-on-deep-working/" target="_blank" rel="noopener">&#8220;deep work,&#8221;</a> and I&#8217;ve been trying to move my schedule toward that model. Anything I can do to reserve large blocks of time throughout the day to get completely engrossed in my work helps with this goal.</p>
<p>The modern work environment, with its open floorplans and tendency toward meetings and conference calls of little value, seems almost designed for shallowness. Look for ways to adjust your schedule and your environment so that you can get completely engrossed in a task. You&#8217;ll get more done, and the work you produce will be of a higher quality.</p>
<h3>Applying It To Your Schedule</h3>
<p>Here are a few ideas that have helped me with this approach:</p>
<ol>
<li><strong>Schedule at a finer resolution.</strong> For me, it&#8217;s fifteen-minute increments. Thirty minutes is too coarse for squeezing in everything I want to do. If I plan a thirty-minute block for a fifteen-minute task, I&#8217;ll be tempted to waste the remaining time or to expand the task to fill the reserved block.</li>
<li><strong>Use a calendar that works for you.</strong> I happen to like Outlook for a number of reasons, but you should use something that fits your style and your approach to your work. Maybe it&#8217;s a paper notebook, or a smart phone, or a different calendar application, or even a bare-bones text editor. As long as it&#8217;s something you can use easily that lets you make changes quickly, it&#8217;s good enough.</li>
<li><strong>Start on time – especially meetings!</strong> The biggest uncontrollable time sink I have every day is dealing with meetings that don&#8217;t start promptly. That topic is probably worth its own article, but starting tasks and meetings on time, and then finishing them on time or even earlier than scheduled, might net you an hour or more over the course of a day.</li>
<li><strong>Schedule flexibly, but not <em>too</em> flexibly.</strong> No schedule will remain perfect over the course of a day unless you&#8217;re able to work in isolation, and that&#8217;s a rare gig, indeed. Leave space in your schedule to deal with distractions and randomization, and allow yourself the freedom to adjust your schedule throughout the day. This is why I like to use Outlook, since I can drag and drop tasks around during the day with ease. This can be dangerous, however, if you let yourself get pulled into constantly tweaking your schedule. Be firm, and let your colleagues know when you have time scheduled for getting things done. Don&#8217;t be afraid to say, &#8220;No.&#8221;</li>
<li><strong>Review your schedule.</strong> Looking back over your schedule, especially if you carefully adjust it during the day to reflect what you actually did, is a great way to learn about your working style and adjust it to be more productive. Look for random items that crept in, and try to find ways to move those to a block of time where you can deal with them together so that you have more large blocks of time for concentrating on what you really need to do.</li>
</ol>
<p>I&#8217;d love to hear from you about how you plan your day, and what tips and tricks have worked for you.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.parkscomputing.com/2016/02/scheduling-every-minute-revisited/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>On Recruiting</title>
		<link>https://www.parkscomputing.com/2016/02/on-recruiting/</link>
					<comments>https://www.parkscomputing.com/2016/02/on-recruiting/#respond</comments>
		
		<dc:creator><![CDATA[paulmooreparks]]></dc:creator>
		<pubDate>Fri, 05 Feb 2016 01:38:38 +0000</pubDate>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[project management]]></category>
		<category><![CDATA[software]]></category>
		<guid isPermaLink="false">https://www.parkscomputing.com/?p=1244</guid>

					<description><![CDATA[I&#8217;ll have more to say about this later, but I want to get this quote out there now so that technical leads, engineering managers, engineering directors, and vice-presidents of software engineering can have it embroidered on a pillow, printed on a t-shirt, and taped to their bathroom mirrors: The quality of your company&#8217;s software will &#8230;<br><a href="https://www.parkscomputing.com/2016/02/on-recruiting/" class="more-link pen_button pen_element_default pen_icon_arrow_double">Continue reading <span class="screen-reader-text">On Recruiting</span></a>]]></description>
										<content:encoded><![CDATA[<p>I&#8217;ll have more to say about this later, but I want to get this quote out there now so that technical leads, engineering managers, engineering directors, and vice-presidents of software engineering can have it embroidered on a pillow, printed on a t-shirt, and taped to their bathroom mirrors:</p>
<blockquote><p><strong>The quality of your company&#8217;s software will never exceed the quality of your company&#8217;s software developers. <br /> &#8212; Paul M. Parks</strong></p></blockquote>
<p>If you&#8217;re not recruiting the best developers you can possibly afford and training the ones you have, you&#8217;re losing to the companies that are.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.parkscomputing.com/2016/02/on-recruiting/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Conway&#8217;s Game of Life in JavaScript</title>
		<link>https://www.parkscomputing.com/2015/11/conways-game-of-life-in-javascript/</link>
					<comments>https://www.parkscomputing.com/2015/11/conways-game-of-life-in-javascript/#respond</comments>
		
		<dc:creator><![CDATA[paulmooreparks]]></dc:creator>
		<pubDate>Fri, 20 Nov 2015 15:27:59 +0000</pubDate>
				<category><![CDATA[games]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[scripting]]></category>
		<guid isPermaLink="false">https://www.parkscomputing.com/?p=1113</guid>

					<description><![CDATA[I realized yesterday that I had never implemented Conway&#8217;s Game of Life, which is something of a rite of passage for young computer-science students. As I opted for a more non-traditional path to the software profession, I somehow missed that fun, even though I&#8217;ve made a point of implementing other computer-sciency things like it. Here &#8230;<br><a href="https://www.parkscomputing.com/2015/11/conways-game-of-life-in-javascript/" class="more-link pen_button pen_element_default pen_icon_arrow_double">Continue reading <span class="screen-reader-text">Conway&#8217;s Game of Life in JavaScript</span></a>]]></description>
										<content:encoded><![CDATA[<p>I realized yesterday that I had never implemented <a href="https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life">Conway&#8217;s Game of Life</a>, which is something of a rite of passage for young computer-science students. As I opted for a more non-traditional path to the software profession, I somehow missed that fun, even though I&#8217;ve made a point of implementing other computer-sciency things like it.</p>
<p>Here are some links to interesting board layouts: </p>
<p><a href="/webapps/conways-game-of-life/">The basic page, which implements a glider.</a></p>
<p><a href="/webapps/conways-game-of-life/?boardSize=200&#038;cellSize=5&#038;wrap=false&#038;init=1,5;2,5;2,6;1,6;11,5;11,6;11,7;12,8;13,9;14,9;12,4;13,3;14,3;16,4;17,5;17,6;17,7;16,8;15,6;18,6;21,5;22,5;22,4;21,4;21,3;22,3;23,2;23,6;25,2;25,1;25,6;25,7;35,3;35,4;36,4;36,3">A Gosper glider gun</a></p>
<p><a href="/webapps/conways-game-of-life/?boardSize=50&#038;cellSize=5&#038;speed=0&#038;wrap=false&#038;init=1,5;2,5;2,6;1,6;11,5;11,6;11,7;12,8;13,9;14,9;12,4;13,3;14,3;16,4;17,5;17,6;17,7;16,8;15,6;18,6;21,5;22,5;22,4;21,4;21,3;22,3;23,2;23,6;25,2;25,1;25,6;25,7;35,3;35,4;36,4;36,3;">A Gosper glider gun running at top speed, probably faster than your screen&#8217;s refresh rate.</a></p>
<p><a href="/webapps/conways-game-of-life/?boardSize=10&#038;init=4,1;4,2;4,3;7,3;7,4;7,5;4,7;4,6;4,5">A set of cells that devolves into a single spinner.</a></p>
<p><a href="/webapps/conways-game-of-life/?boardSize=10&#038;cellSize=20&#038;init=2,1;3,2;4,2;2,3;3,3;6,4;7,5;8,5;6,6;7,6">A pair of gliders which follow each other endlessly.</a></p>
<p><a href="/webapps/conways-game-of-life/?boardSize=183&#038;cellSize=5&#038;init=45,51;47,51;47,50;49,49;49,48;49,47;51,48;51,47;51,46;52,47;">A large board with a long-running pattern</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.parkscomputing.com/2015/11/conways-game-of-life-in-javascript/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Updated Barcode Generator</title>
		<link>https://www.parkscomputing.com/2015/09/updated-barcode-generator/</link>
					<comments>https://www.parkscomputing.com/2015/09/updated-barcode-generator/#respond</comments>
		
		<dc:creator><![CDATA[paulmooreparks]]></dc:creator>
		<pubDate>Wed, 30 Sep 2015 23:29:13 +0000</pubDate>
				<category><![CDATA[barcodes]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[web]]></category>
		<guid isPermaLink="false">https://www.parkscomputing.com/?p=1092</guid>

					<description><![CDATA[I finally got around to making some updates to my Barcode Generator. Try it out and let me know if you have any problems.]]></description>
										<content:encoded><![CDATA[<p>I finally got around to making some updates to my <a href="https://www.parkscomputing.com/webapps/barcode-generator/">Barcode Generator</a>. Try it out and let me know if you have any problems.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.parkscomputing.com/2015/09/updated-barcode-generator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How I Plan Every Minute of My Day to Stay Productive</title>
		<link>https://www.parkscomputing.com/2015/09/how-i-plan-my-day/</link>
					<comments>https://www.parkscomputing.com/2015/09/how-i-plan-my-day/#respond</comments>
		
		<dc:creator><![CDATA[paulmooreparks]]></dc:creator>
		<pubDate>Wed, 09 Sep 2015 06:48:58 +0000</pubDate>
				<category><![CDATA[productivity]]></category>
		<category><![CDATA[project management]]></category>
		<guid isPermaLink="false">https://www.parkscomputing.com/?p=1083</guid>

					<description><![CDATA[Note: I also posted this article on LinkedIn. &#8220;In preparing for battle I have always found that plans are useless, but planning is indispensable.&#8221; — Dwight D. Eisenhower Over the years, I have progressed from being a software developer who focuses on code all day, to a designer who designs and codes, to a technical &#8230;<br><a href="https://www.parkscomputing.com/2015/09/how-i-plan-my-day/" class="more-link pen_button pen_element_default pen_icon_arrow_double">Continue reading <span class="screen-reader-text">How I Plan Every Minute of My Day to Stay Productive</span></a>]]></description>
										<content:encoded><![CDATA[<p><em>Note: I also <a href="https://www.linkedin.com/pulse/article/how-i-plan-every-minute-my-day-stay-productive-paul-parks/">posted this article on LinkedIn</a>.</em></p>
<blockquote><p>&#8220;In preparing for battle I have always found that plans are useless, but planning is indispensable.&#8221; — Dwight D. Eisenhower</p></blockquote>
<p>Over the years, I have progressed from being a software developer who focuses on code all day, to a designer who designs and codes, to a technical lead who communicates a design and technical strategy to a team of developers, to a technical and project lead who leads developers in the implementation of a project while communicating with customers and other stakeholders. At each level the demands on my time have increased, while the expectations of improved productivity and reliable delivery have also increased.</p>
<p>I&#8217;ve played with various ways of planning and scheduling, but the method that has proven to be most effective so far is a variation of  <a href="http://calnewport.com/blog/category/tips-time-management-scheduling-productivity/" target="_blank" rel="noopener">Cal Newport&#8217;s tips for scheduling</a>, particularly what he discusses in the article <a href="http://calnewport.com/blog/2013/12/21/deep-habits-the-importance-of-planning-every-minute-of-your-work-day/" target="_blank" rel="noopener">&#8220;Deep Habits: The Importance of Planning Every Minute of Your Work Day&#8221;</a>. The idea is to lay out a plan for my day in my calendar, at the start of each day before I&#8217;ve jumped into any other activity. The plan isn&#8217;t rigid, but rather a guide for what I tasks need to accomplish and how I would like to get them done.</p>
<p>To show you how this works, I&#8217;ll walk you through a typical working day for me. While the tasks described are entirely fictional, they are still quite representative of what you would find in my real OneNote and Outlook files.</p>
<p>I usually start my working day just before 6:30 AM, after I&#8217;ve made breakfast for the family and I&#8217;ve wandered upstairs to my home office with a large mug of coffee. I&#8217;ll take a few moments to look over my OneNote file, where I keep meticulous notes on everything that happens on a daily basis: what meetings were held, what decisions were made, what questions are open, and what actions need to be taken. For my own actions, I use OneNote&#8217;s CTRL-1 keyboard shortcut to put a check box by each action so that I can easily see what needs to be done. Any actions that aren&#8217;t due on the current day end up at the top of my file, under the heading &#8220;The Future&#8221;, and as I create a new entry in the file for each new day, I&#8217;ll move the items I need to accomplish under that day&#8217;s heading.</p>
<p>For example, by the end of the previous day my general notes file in OneNote might look like the following:</p>
<p><a href="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-01.jpg" target="_blank" rel="noopener"><img decoding="async" loading="lazy" class="aligncenter wp-image-1603" src="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-01.jpg" alt="" width="720" height="491" srcset="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-01.jpg 1024w, https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-01-300x204.jpg 300w, https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-01-768x524.jpg 768w" sizes="(max-width: 720px) 100vw, 720px" /></a></p>
<p>&nbsp;</p>
<p>As you can see, I&#8217;m in the middle of a particularly busy week where a lot of to-do items have piled up. Some are little more than annoying administrative tasks, while others require some deep work and concentration to complete. When I create an entry in OneNote for the new day, I&#8217;ll use the ALT-UpArrow and ALT-DownArrow keyboard shortcuts to move the most important to-do items to the current day, and then I&#8217;ll review notes from the last few days to see if any unchecked or unidentified actions were lurking in those entries. When I finish, the OneNote file might look like the following:</p>
<p><a href="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-02.jpg" target="_blank" rel="noopener"><img decoding="async" loading="lazy" class="aligncenter wp-image-1604" src="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-02.jpg" alt="" width="720" height="491" srcset="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-02.jpg 1024w, https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-02-300x204.jpg 300w, https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-02-768x524.jpg 768w" sizes="(max-width: 720px) 100vw, 720px" /></a></p>
<p>&nbsp;</p>
<p>Now I&#8217;ll open my Outlook calendar and start blocking off time during the day for the various tasks I need to accomplish. Since I work on several concurrent projects, I put a project identification code on each task, and I even color-code the tasks by project so that I can see at a glance where my time is going. There will probably already be some entries for pre-scheduled meetings and conference calls, so I also need to be careful to plan my day around those fixed items.</p>
<p><a href="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-03.jpg" target="_blank" rel="noopener"><img decoding="async" loading="lazy" class="aligncenter wp-image-1605" src="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-03.jpg" alt="" width="720" height="850" srcset="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-03.jpg 925w, https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-03-254x300.jpg 254w, https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-03-867x1024.jpg 867w, https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-03-768x907.jpg 768w" sizes="(max-width: 720px) 100vw, 720px" /></a></p>
<p>&nbsp;</p>
<p>Next, I block off time for the annoying tasks that just need to be cleared out. For me, mornings are the best time to do this because that&#8217;s the noisiest time of my day, and I can move these items around as needed. They usually don&#8217;t require a lot of concentration or other resources, so it&#8217;s no big loss to reschedule them or to be interrupted while doing them. Consequently, you&#8217;ll notice that most of these tasks are shown as free time in Outlook, in case someone needs to schedule me for a meeting during the times that I&#8217;ve blocked off to complete these tasks.</p>
<p>With that done, I start my day. The first half hour or so is usually reserved for dealing with email. Currently, my customers and project managers are in the UK, and my development teams are split between the Philippines and India, so I usually wake up to a bulging inbox in Outlook. I read and respond to what I can, and I flag the items that need to be dealt with later, perhaps creating a calendar entry for them.</p>
<p>One of the emails sitting in my inbox is from the QA lead, saying that she has some questions about the spec and how it relates to her test plan. I had already reserved some time later in the day to drop in and chat with her, so I expand that entry in the calendar to make time for what needs to be discussed.</p>
<p>Next, I have a conference call scheduled with the development team from 7:00 to 8:00. Then, I start to look over a customer requirements document, after which I plan to finish a code review that&#8217;s been assigned to me in <a href="https://www.atlassian.com/software/crucible/overview" target="_blank" rel="noopener">Crucible</a>.</p>
<p>Most of the way through the requirements document, however, I get a call from the programme manager in London asking if I can participate in an urgent discussion about some changes that a customer stakeholder requires in a PowerPoint slide deck that we sent last week. &#8220;No problem,&#8221; I say, and soon I see a meeting request appear in my calendar from 9:00 to 9:30. That&#8217;s when I had planned to knock out the code review, but that&#8217;s okay. I just drag the code review to another part of the day and do some quick shuffling of tasks, taking no more than a minute or two to do so. The review moves down, the time I plan to drop in on the QA lead moves, and some less urgent tasks get pushed to later in the day or maybe even to tomorrow. The large block of time I reserved for the development task, however, stays in the afternoon, since that&#8217;s when my distractions usually diminish and I can concentrate on difficult tasks.</p>
<p>The meeting with the customer ends with an urgent action to update the slide deck and get that back to the customer, so I do a little more shuffling and start that task right away. By the time that task is complete, I&#8217;ve finished the portion of my day that I usually spend at my home office, so I get cleaned up and drive to the real office. That&#8217;s the time I have blocked off from 10:30 to 11:30 as &#8220;Out of office&#8221; so that nobody tries to schedule me for that time.</p>
<p><a href="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-04.jpg" target="_blank" rel="noopener"><img decoding="async" loading="lazy" class="aligncenter wp-image-1606" src="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-04.jpg" alt="" width="720" height="850" srcset="https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-04.jpg 925w, https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-04-254x300.jpg 254w, https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-04-867x1024.jpg 867w, https://www.parkscomputing.com/wp-content/uploads/how-i-plan-every-minute-04-768x907.jpg 768w" sizes="(max-width: 720px) 100vw, 720px" /></a></p>
<p>&nbsp;</p>
<p>Once in the office, I get the code review done, hop onto the intranet travel-booking web site to reserve a hotel for an upcoming trip, and then make a cup of tea and go find the QA lead. It&#8217;s a productive meeting, and some of the outputs dovetail nicely into my next scheduled task to update the dependency table for an upcoming project. Now I&#8217;ve cleared out most of my &#8220;busy&#8221; work, so I make another cup of tea and spend the rest of my afternoon getting lost in code.</p>
<p>My Outlook settings automatically generate a 5-minute reminder for upcoming tasks, so as I near the end of each scheduled task I&#8217;ll get a notification to wrap up what I&#8217;m doing, take a little break, and then dive into the next task. As I start each new task, I know that since I only have a set amount of time in which to complete it I have to stay focused and get the task done in the allotted time, so that I can get through all of what I want to get done for the day.</p>
<p>For ongoing tasks, where I&#8217;m just trying to allocate time to work on them rather than complete them, I fight the urge to work &#8220;just a little longer&#8221; when the reminder pops up, again so that I can keep knocking out those tasks that really do have to get done today. This is another reason I like to schedule ongoing tasks for the end of the day.</p>
<p>I have found that, generally, how productive I am in a given week is dependent on how closely I stick to this method of planning and recording my day. Planning, because it gives me a clear image of what I want to get done and how much time I have to work with. Recording, because I make sure that as I complete tasks I go back and expand or contract the actual time spent so that I can look back through previous days and get an idea of how much time to reserve for new tasks based on how long similar tasks have taken in the past. It&#8217;s also great for when I have to submit my time-tracking reports at the end of the week, since everything I&#8217;ve done is laid out very clearly, along with who gets the bill for that time.</p>
<p>I&#8217;d like to hear how you plan your days, and what little hacks make you more productive.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.parkscomputing.com/2015/09/how-i-plan-my-day/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
