<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Filipe Peliz Pinto Teixeira</title>
    <description>The latest articles on DEV Community by Filipe Peliz Pinto Teixeira (@fppt).</description>
    <link>https://dev.to/fppt</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F28505%2Fa5af641b-532f-4467-b98f-0163bb7deb3d.jpeg</url>
      <title>DEV Community: Filipe Peliz Pinto Teixeira</title>
      <link>https://dev.to/fppt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fppt"/>
    <language>en</language>
    <item>
      <title>Managing Delivery Networks: A Use Case For Graph Databases</title>
      <dc:creator>Filipe Peliz Pinto Teixeira</dc:creator>
      <pubDate>Wed, 30 Oct 2019 13:37:19 +0000</pubDate>
      <link>https://dev.to/fppt/managing-delivery-networks-a-use-case-for-graph-databases-2jb0</link>
      <guid>https://dev.to/fppt/managing-delivery-networks-a-use-case-for-graph-databases-2jb0</guid>
      <description>&lt;p&gt;At takealot.com one of the biggest competitive advantages we have as an e-commerce platform is the maintenance and expansion of our own logistics network.This network allows us to control how and when we deliver to customers and, amongst other aspects, ensures that takealot.com is the leading e-commerce platform in South Africa.&lt;/p&gt;

&lt;p&gt;In this article, I will provide an analysis of the unique problem takealot.com faced in facilitating reliable deliveries to customers and how we use a graph database to deliver a performant and scalable solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  So What's The Problem?
&lt;/h3&gt;

&lt;p&gt;One might ask why takealot.com does not make use of South Africa’s postal service and existing couriers. The answer, quite simply, is lack of &lt;em&gt;reliability&lt;/em&gt;. Local postal services cannot provide accurate delivery dates. This means that using this service as our logistics backbone would not provide exact delivery dates to our customers. Additionally, existing courier companies would charge premiums which would add an additional cost largely incurred by customers. This key factor means that maintaining our own logistics operations remains the best course of action.&lt;/p&gt;

&lt;p&gt;However, when growing a logistics network to fulfil the needs of a growing national e-commerce platform, one can't go from 1 to 11 overnight. As such, we had to ensure integration remained with existing third-party courier companies. &lt;/p&gt;

&lt;p&gt;So the requirements of the system are to establish:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;How to get an order to the customer.&lt;/li&gt;
&lt;li&gt;When will the order get to the customer.&lt;/li&gt;
&lt;li&gt;Wether a third-party courier or our own delivery network will be used to fulfil the delivery.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For the remainder of this article we will focus on point 1 while touching on point 2. If there is interest I will try to expand point 2 in further articles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's Make Ship Happen
&lt;/h3&gt;

&lt;p&gt;A delivery to a customer in the takealot.com world consists of two phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Courier the parcel from a warehouse to the branch closest to the
customer. This can involve bouncing a package across multiple branches.&lt;/li&gt;
&lt;li&gt;Deliver the parcel from the branch to the customer.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In short, takealot.com needs to ensure an order is shipped from a central warehouse or third-party Marketplace seller to the customer in the shortest and most economical way possible.&lt;/p&gt;

&lt;p&gt;This involves computing the &lt;a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm" rel="noopener noreferrer"&gt;shortest path&lt;/a&gt;, a classic computing problem. In principle, we consider branches to be a series of nodes which can be displayed as such:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fx93xme0aldnf0l24i6r8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fx93xme0aldnf0l24i6r8.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you link them all together with edges representing routes and run a graph search algorithm we are delivering and fast celebrating with ice-cold beers and high fives.&lt;/p&gt;

&lt;p&gt;We implemented the above via &lt;a href="https://pgrouting.org/" rel="noopener noreferrer"&gt;pgrouting&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Yen%27s_algorithm" rel="noopener noreferrer"&gt;Yen's Algorithm&lt;/a&gt;. This was the latency with that approach:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fgk1sqg0guyo7v16bdqqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fgk1sqg0guyo7v16bdqqt.png" alt="Getting Routes via Yen's Algorithm on PGRouting"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Within &lt;em&gt;135ms&lt;/em&gt; we will know how to get to the customer. After finding out &lt;em&gt;when&lt;/em&gt; we get to the customer the system response time looks like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Femkud973owkaxx2fgbgz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Femkud973owkaxx2fgbgz.png" alt="Getting Routes &amp;amp; Dates For Deliveries"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After &lt;em&gt;510ms&lt;/em&gt; we will know how to get to you and when. Success! &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Then we needed to scale&lt;/em&gt; and found an issue. The graph representation of the delivery network was just a graph; a bunch of nodes connected by a bunch of edges. This means that the application of delivery constraints such as making sure we don't deliver a fridge on a scooter was done outside of the graph in post. &lt;/p&gt;

&lt;p&gt;As additional routes, couriers and branches were added, performance degraded to the point where we could not expand delivery capabilities without making the customer wait several seconds for a delivery date.&lt;/p&gt;

&lt;p&gt;Eventually, this meant third-party couriers could not be continually integrated; amongst other challenges, affordable rural couriers were now unavailable to the company.&lt;/p&gt;

&lt;h3&gt;
  
  
  Property Graphs To The Rescue
&lt;/h3&gt;

&lt;p&gt;Turns out we didn't need a &lt;em&gt;graph&lt;/em&gt; we needed a &lt;a href="https://markorodriguez.com/2011/02/08/property-graph-algorithms/" rel="noopener noreferrer"&gt;property graph&lt;/a&gt;. In short, a property graph is a graph data structure with the addition of properties (key, value pairs) which sit on the edges and vertices of the graph. The previously discussed graph model went from a bunch of connected nodes to:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fm2s6p7ph19p3imesmwrm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fm2s6p7ph19p3imesmwrm.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;with each edge/vertex having following properties:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4d10ol8gp8zf0tl7cqwi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4d10ol8gp8zf0tl7cqwi.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This meant that we were able to push &lt;em&gt;all&lt;/em&gt; route constraint logic to the graph. In terms of figuring out how to get to customers, no post processing was required. We were able to facilitate this via &lt;a href="https://janusgraph.org/" rel="noopener noreferrer"&gt;JanusGraph&lt;/a&gt; as a data layer with &lt;a href="http://tinkerpop.apache.org/" rel="noopener noreferrer"&gt;TinkerPop &amp;amp; Gremlin&lt;/a&gt; facilitating the query language. This also meant that hundreds of lines of post processing code turned into a simple &lt;a href="https://github.com/mpollmeier/gremlin-scala" rel="noopener noreferrer"&gt;gremlin-scala&lt;/a&gt; query like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="nv"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;V&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="py"&gt;has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Vertex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;LOOKUPID&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lookupIDTo&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;inE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;LegType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;LAST_MILE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Edge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;PHYSMINWEIGHT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;lte&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;physWeight&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Edge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;PHYSMAXWEIGHT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;gte&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;physWeight&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
              &lt;span class="c1"&gt;//More property constraints&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;outV&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Vertex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;HUBACTIVE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;repeat&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;inE&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;LegType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;LINE_HAUL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Edge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;PHYSMINWEIGHT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;lte&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;physWeight&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Edge&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;PHYSMAXWEIGHT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;P&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;gte&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;attributes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;physWeight&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
              &lt;span class="c1"&gt;//More property constraints&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;outV&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
              &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Vertex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;HUBACTIVE&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;simplePath&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
            &lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;until&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;has&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;Keys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Vertex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;LOOKUPID&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lookupIDFrom&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="py"&gt;limit&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="py"&gt;path&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Any gremlin fan reading this will note how we are traversing in reverse. Let's say that edge labels with a better understanding of our &lt;a href="https://en.wikipedia.org/wiki/Degree_distribution" rel="noopener noreferrer"&gt;degree distribution&lt;/a&gt; allowed for further optimisations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The above query not only checks how we can get to customers but also uses the details of the parcels (such as weight) being delivered to more quickly eliminate routes.&lt;/p&gt;

&lt;p&gt;Now, let’s take another look at the latency graph below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4knmcbtaxpza84u0yymc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F4knmcbtaxpza84u0yymc.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A P95 response time of &lt;em&gt;10ms&lt;/em&gt;, an order of magnitude better. In addition to this, as takealot.com added more hubs and couriers there was no performance degradation (or at least there hasn't been yet). This is because our search space remained limited to the number of &lt;code&gt;LINE_HAUL&lt;/code&gt; edges we have and most expansions to the logistical networks occur at the &lt;code&gt;LAST_MILE&lt;/code&gt; edges layer. Another perk of &lt;a href="https://markorodriguez.com/2011/02/08/property-graph-algorithms/" rel="noopener noreferrer"&gt;property graph&lt;/a&gt; is the ability to formally categorise and layer the structure of the graph via labels as well properties. &lt;/p&gt;

&lt;p&gt;This new &lt;a href="https://markorodriguez.com/2011/02/08/property-graph-algorithms/" rel="noopener noreferrer"&gt;property graph&lt;/a&gt; structure also allowed us to represent our temporal constraints in a structured and traversable manner. However, computing when the delivery gets to the customer is still performed outside of the graph. The more natural representation of temporal data (not logic) on the graph allowed us to optimise at that layer as well. In the end the final system response time is:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fexdh2wjxi1u3oia4rqkk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fexdh2wjxi1u3oia4rqkk.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A P95 response time of &lt;em&gt;150ms&lt;/em&gt; is much more acceptable. As I said, if there is interest in this article I may follow up with how the graph allowed us to optimise the delivery date computations as well.&lt;/p&gt;

&lt;p&gt;This new property graph model provides many other non-performance related benefits such as improved observability, easier modifications and many others. &lt;/p&gt;

&lt;h3&gt;
  
  
  So Are We Making Ship Happen?
&lt;/h3&gt;

&lt;p&gt;I would like to think we are. The system has allowed us to more accurately predict deliveries dates - not taking into account potential operational delays such as stock arriving late from suppliers, bad traffic, etc. . . Accounting for potential operational delays on delivery routes could be another challenge for us to try solve next.&lt;/p&gt;

&lt;p&gt;Are &lt;a href="https://markorodriguez.com/2011/02/08/property-graph-algorithms/" rel="noopener noreferrer"&gt;property graphs&lt;/a&gt; a silver bullet to computing problems? No! Definitely not! Just as you would not use a plunger to take out a screw you would not use a graph database to model a shopping cart for example. &lt;/p&gt;

&lt;p&gt;However, this new property graph model has opened up multiple discussions which could lead to more customer facing improvements.&lt;/p&gt;

&lt;p&gt;We are excited to push this tech even further and see what we can do with it: we need to make more ship happen. &lt;/p&gt;

</description>
      <category>development</category>
      <category>graphdb</category>
      <category>gremlin</category>
    </item>
    <item>
      <title>Grakn’s (mostly) Agile Methodology    </title>
      <dc:creator>Filipe Peliz Pinto Teixeira</dc:creator>
      <pubDate>Wed, 02 Aug 2017 14:16:34 +0000</pubDate>
      <link>https://dev.to/fppt/grakns-mostly-agile-methodology</link>
      <guid>https://dev.to/fppt/grakns-mostly-agile-methodology</guid>
      <description>&lt;p&gt;&lt;em&gt;Photo credit: &lt;a href="http://mincarconsulting.com/wp-content/uploads/2015/08/herding-cats3.jpg" rel="noopener noreferrer"&gt;Mincarconsulting.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This article originally appeared on the &lt;a href="https://blog.grakn.ai/grakns-mostly-agile-methodology-ab491fa62ba3" rel="noopener noreferrer"&gt;GRAKN.AI blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Anyone who has ever found themselves monitoring or managing any kind of project may have encountered the term “It’s like herding cats”. These days this refers to the difficulty associated with managing the many interacting components of a project. Originally it was specific to people:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Managing senior programmers is like herding cats.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The difficulty associated with managing software projects and minimising the risks of those projects has spawned off an almost entirely different industry in itself. You will often hear people boast about following some formal workflow process. &lt;a href="https://en.wikipedia.org/wiki/Waterfall_model" rel="noopener noreferrer"&gt;Waterfall&lt;/a&gt;, &lt;a href="http://agilemethodology.org/" rel="noopener noreferrer"&gt;Agile&lt;/a&gt;, &lt;a href="http://scrummethodology.com/" rel="noopener noreferrer"&gt;Scrum&lt;/a&gt;, &lt;a href="https://www.versionone.com/what-is-kanban/" rel="noopener noreferrer"&gt;Kanban&lt;/a&gt;, the list goes on... Some actually get quite passionate about these approaches. I have even heard of people &lt;strong&gt;not&lt;/strong&gt; in software engineering following these formal processes. Personally, I am of the thought that you should find something that works for the team you have, stick with it when it works, and tweak it when it doesn’t work.&lt;/p&gt;

&lt;p&gt;So this is a tale and a retrospective look at how we at Grakn Labs found our “something that seems to work for us. This tale may aid you in finding your something.&lt;/p&gt;

&lt;p&gt;We found ourselves in an interesting position in comparison to most software teams. We are not all software engineers. Some of us fall more in the data scientist side, some in the rapid prototype side, and some in the marketing side. Regardless, when you have a &lt;strong&gt;small mixed team&lt;/strong&gt; that have to reach objectives quickly, it’s important to get everyone working in the same manner. So, in our case, our cats are on fire and each cat is trying to put out the fire with different materials. Finally, you, who are watching this, are also on fire.&lt;/p&gt;

&lt;h1&gt;
  
  
  Graknâ€Š–â€ŠDay 0
&lt;/h1&gt;

&lt;p&gt;It’s year one of Grakn, we have vague requirements, a rough design document, and zero lines of code to work with. We also have a new and relatively young team. From the management perspective you should &lt;strong&gt;quickly&lt;/strong&gt; get everyone on the same platform and process. With this being a new team our CEO had time to investigate and introduce our new platform, &lt;a href="http://targetprocess.com/" rel="noopener noreferrer"&gt;TargetProcess&lt;/a&gt;. Think &lt;a href="https://www.atlassian.com/software/jira" rel="noopener noreferrer"&gt;Jira&lt;/a&gt;, but less bloated and more focussed.&lt;/p&gt;

&lt;p&gt;The tool is only the start and should be used to facilitate the needs of the team. At this stage we started going with a &lt;a href="https://en.wikipedia.org/wiki/Waterfall_model" rel="noopener noreferrer"&gt;Waterfall&lt;/a&gt;-like model. Basically all work has to go through the following pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Requirements Gatheringâ€Š&lt;/strong&gt;–â€ŠSimply list the high level features which need to be delivered by the software. Anything goes here, so list whatever you think adds value to your project, as long as it’s high level. Its important to encourage this attitude as it allows everyone in your team to contribute in some way or another to the direction of the project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Requirements Discussion&lt;/strong&gt;â€Š–â€ŠAt this stage you will be accepting and rejecting requirements based on: (1) does the requirement fit within the vision of the product? and (2) is it feasible to do, regardless of timeline? During this stage, avoid discussing design. The objective is to create your feature set and prioritise those features. Your must haves for your minimum viable product.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design Time&lt;/strong&gt;â€Š–â€ŠPick your highest priority requirements and start designing and outlining a rough implementation. Be sure to document any decisions and assumptions. You don’t need to go through &lt;strong&gt;all&lt;/strong&gt; the requirements. Just enough keep everyone busy for a some time. When time allows, you can do the same for the lower priority requirements. Not planning all the requirements is important as things may change before you finally get around to implementing them and with a young team on a new project you will need flexibility.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1791%2F1%2AQ_sou0ogLGa0HlhB5gnHyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F1791%2F1%2AQ_sou0ogLGa0HlhB5gnHyg.png" alt="The Requirements Board We Use For a subset of the project"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The Requirements Board We Use For a subset of the project&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This basically takes care of managing which features get into the product. If you notice the &lt;strong&gt;new&lt;/strong&gt; column looking empty, time do to step 1. If you notice the &lt;strong&gt;accepted&lt;/strong&gt; column looking thin, time for step 2. Finally, if the &lt;strong&gt;in progress&lt;/strong&gt; column is looking thin, time for step 3.&lt;/p&gt;

&lt;p&gt;Next up, is task planning and task execution, and this is where we set our first cats on fire.&lt;/p&gt;

&lt;h1&gt;
  
  
  Running Sprints
&lt;/h1&gt;

&lt;p&gt;Now that you know what needs to get done you need to make sure progress can be monitored and communicated in a non intrusive manner. Enter the &lt;a href="https://www.scruminc.com/scrum-board/" rel="noopener noreferrer"&gt;Scrum Board&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F896%2F1%2AXBdwV8EzHgvVyF7ak8--lw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F896%2F1%2AXBdwV8EzHgvVyF7ak8--lw.png" alt="Our Weekly Sprint Board on TargetProcess"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Our Weekly Sprint Board on &lt;a href="http://targetprocess.com/" rel="noopener noreferrer"&gt;TargetProcess&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Borrowing a page from &lt;a href="http://scrummethodology.com/" rel="noopener noreferrer"&gt;Scrum&lt;/a&gt; methodology we run weekly sprints. At the end of each week we group up and fill our todos for the following week. This is basically the process of taking accepted and designed requirements and breaking them down into executable tasks. Doing this serves two purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Planning the tasks you going to execute in advance minimises “dead time”, i.e. time spent waiting for others to do something you need or time spent looking for your next actionable task when you not sure what to do next.&lt;/li&gt;
&lt;li&gt;By planning in smaller groups we more effectively communicate how we going to impact each other. This minimises surprises throughout the week. For example, if you going to be refactoring some API calls your colleagues should know about these in advance before they wonder where their API has gone.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;a href="https://www.scruminc.com/scrum-board/" rel="noopener noreferrer"&gt;Scrum Board&lt;/a&gt; allows each developer to be aware of everyone’s status on each task without having to poke anyone. A digital board also makes this easier to work with, as changing the status of a task is as simple as dragging a card to the next column.&lt;/p&gt;

&lt;h1&gt;
  
  
  KISSâ€Š–â€ŠKeep It Simple Stupid
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;KISSâ€Š&lt;/strong&gt;–â€Š&lt;em&gt;This phrase is often used when designing software and I believe it should be applied towards managing workflows as well.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is where things started to go wrong. A new team, a new workflow, and vague requirements will results in some failures. We had plenty of these during the early days of Grakn. From not properly defining requirements, skipping the requirements pipeline all together, to just failing to plan, we experienced all of these in our mad rush to our fist PoC, &lt;a href="http://moogi.co/" rel="noopener noreferrer"&gt;Moogi&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Some may argue that these failures are a result of not strictly sticking to established and proven process. In other words, if you going to &lt;a href="http://scrummethodology.com/" rel="noopener noreferrer"&gt;Scrum&lt;/a&gt;, you &lt;a href="http://scrummethodology.com/" rel="noopener noreferrer"&gt;Scrum&lt;/a&gt; 100%, if you going to &lt;a href="https://www.versionone.com/what-is-kanban/" rel="noopener noreferrer"&gt;Kanban&lt;/a&gt;, you go with that 100% without deviation. This is what we tried. This is where we failed. We found that sticking to a specific process was never flexible enough. When you have 6 months to get to a PoC you can’t spend much time on your workflow. So this is where we started to deviate from the proven processes which resulted in things getting better. . . until they got bad again.&lt;/p&gt;

&lt;p&gt;These processes are proven and established for a reason and too much deviation from them results in failed planning and planning to fail. So at this stage we learnt our lessons and went with a different approach. We treated these processes as guidelines and picked those which worked, while abandoning those which failed.&lt;/p&gt;

&lt;h1&gt;
  
  
  KISSâ€Š–â€ŠEstimating Effort
&lt;/h1&gt;

&lt;p&gt;One of the most common principles of &lt;a href="http://scrummethodology.com/" rel="noopener noreferrer"&gt;Scrum&lt;/a&gt; is in estimating effort associated with tasks. Many insist that you should &lt;strong&gt;not&lt;/strong&gt; use hours when estimating task difficulty. You should use &lt;a href="https://agilefaq.wordpress.com/2007/11/13/what-is-a-story-point/" rel="noopener noreferrer"&gt;story points&lt;/a&gt;, or hot dog sizes, or precipitation levels, or some other layer of abstraction.&lt;/p&gt;

&lt;p&gt;One of the reasonings behind this is that engineers do not like associating hours with tasks. However, in most cases (not all) these abstracted points get converted into hours anyway. So this layer of abstraction exists to protect our feelings at the cost of giving us the opportunity at getting better at estimating the time it takes to execute tasks. I know this is a controversial stand point but here me out, knowing how long it will take you to do something is a valuable skill for anyone to posses. A skill which is more difficult to develop when you think in terms of hot dogs and not time. So &lt;strong&gt;KISS&lt;/strong&gt;â€Š–â€Šgo back to hours, yes, you will get it wrong often but, as time goes on, you will get increasingly accurate. Of course if the point abstraction works for your team then stick with it, but in our smaller team where everyone is responsible for individual components, time based estimations work better for us.&lt;/p&gt;

&lt;p&gt;When you start using hours for task estimation &lt;strong&gt;do not&lt;/strong&gt; use it to keep time sheets on you people. If you do, you are going to encourage people to pad out the hours, which defeats the purpose of this exercise. &lt;strong&gt;KISS&lt;/strong&gt;â€Š–â€Šworkflow management is not the same as keeping time sheets.&lt;/p&gt;

&lt;h1&gt;
  
  
  KISSâ€Š–â€ŠCommunication
&lt;/h1&gt;

&lt;p&gt;Another common aspect of &lt;a href="http://scrummethodology.com/" rel="noopener noreferrer"&gt;Scrum&lt;/a&gt; is the &lt;a href="https://martinfowler.com/articles/itsNotJustStandingUp.html" rel="noopener noreferrer"&gt;daily standup&lt;/a&gt;. The principle is simple, every morning everyone stands up and gives a brief talk about what they did the day before, and what they going to do today. This has the common pitfall of running over the allotted time.&lt;/p&gt;

&lt;p&gt;Daily Standups are supposed to be brief 10 minute intros to the day. However, more often that not there is run over because as developers we are enthusiastic people and will talk any implementation detail into the ground if given the chance. Tabs vs spaces anyone? This is such a common problem that you can find &lt;a href="https://www.scrumalliance.org/community/articles/2014/july/7-mistakes-during-the-daily-stand-up-meeting" rel="noopener noreferrer"&gt;articles&lt;/a&gt; suggesting ways to deal with it. Some people use stop watches, talking sticks (you can only talk if you have the stick), druidic rituals, and many other workarounds. &lt;strong&gt;KISSâ€Š&lt;/strong&gt;–â€ŠIf it doesn’t work for your team, get rid of it.&lt;/p&gt;

&lt;p&gt;We replaced the daily standup with a &lt;strong&gt;daily email&lt;/strong&gt; update everyone sends at the end of the work day. This email simply states what they did, issues they encountered, and what they planning for the next day. If conversation needs to continue, it can do so on the email thread without dragging in people who do not need to be involved. In addition to this we have a weekly standup at the start of every week to say what our objective is for the coming week. This is high level enough that dev talk rarely happens and if we do run over it only happens once a week so we don’t feel the need to introduce controlling measures such as the previously mentioned stopwatches and druids.&lt;/p&gt;

&lt;h1&gt;
  
  
  Practice Makes Perfect
&lt;/h1&gt;

&lt;p&gt;Handling incorrect task estimations needs to be done carefully. It is easy to accidentally create an environment of rewarding overestimating and punishing underestimating. The objective is to reward accurate task estimations and assist with understanding why certain tasks were misestimated. This is regardless whether they were executed 2 times faster or slower than expected.&lt;/p&gt;

&lt;p&gt;You may ask why are accurate estimations so important? Isn’t it a good thing to have people finishing work ahead of plan. Yes of course! However, wouldn’t it be even &lt;strong&gt;better&lt;/strong&gt; if you knew they were going to finish ahead of time? Furthermore, there are troubles that can occur when constantly under or over estimating:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Overestimating&lt;/strong&gt; can lead to people getting to the middle of their week and not be sure what to do next. Senior staff with a good initiative and intuition may easily jump on another task, but some (if not most) people are reluctant to do so. So it’s best to avoid this&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Underestimating&lt;/strong&gt; means that you risk blocking other developers or missing deadlines. It also means you can’t accurately plan around someone.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One general guidelines which has helped us in the past is that any task over 8 hours should be broken down further. Luckily &lt;a href="http://targetprocess.com/" rel="noopener noreferrer"&gt;TargetProcess&lt;/a&gt; lets us do this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F716%2F1%2AxhcLDEanmsAR02YZNoA3ow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F716%2F1%2AxhcLDEanmsAR02YZNoA3ow.png" alt="A more granular breakdown of tasks"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A more granular breakdown of tasks&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Graknâ€Š–â€ŠPresent Day
&lt;/h1&gt;

&lt;p&gt;This roughly covers how we do business and how we work at Grakn Labs. It’s not perfect but it’s gotten us to where we are today. We are still tweaking here and there but the core principles have been maintained since we started our journey.&lt;/p&gt;

&lt;p&gt;There are still many challenges which we are facing with regards to this workflow. The research side of our work still doesn’t perfectly match this workflow. I have heard of research teams who have incorporated Agile principles into their work and I would love to know peoples thought’s on how to do it. Similarly, there is still the vagueness of non requirement driven and non technical tasks. For example, I am writing this blog piece which takes time, how does this sort of work get factored in? Should it get factored in? I have been told that these are common problems amongst small teams of varying composition and background. I would love to hear your thoughts on how your teams have tackled these issues.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this high level review of how we went from a group of cats on fire running in random directions to cats on fire running in the same direction. Maybe one day we will no longer be on fire.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thanks to Thanh for converting this article to Markdown&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Please let us know your thoughts by leaving us a comment below, joining our &lt;a href="https://grakn.ai/slack.html" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; community or pinging us on &lt;a href="https://twitter.com/GraknLabs" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;! And if you liked this post, please do hit recommend.    &lt;/p&gt;

</description>
      <category>development</category>
      <category>agile</category>
      <category>scrum</category>
    </item>
  </channel>
</rss>
