<?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>Forem: David Israel</title>
    <description>The latest articles on Forem by David Israel (@uclusion).</description>
    <link>https://forem.com/uclusion</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%2F386861%2F637662b6-5427-4881-9d8a-f9dab4bad49a.png</url>
      <title>Forem: David Israel</title>
      <link>https://forem.com/uclusion</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/uclusion"/>
    <language>en</language>
    <item>
      <title>Multiple tabs in your app</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Sun, 01 Nov 2020 01:57:47 +0000</pubDate>
      <link>https://forem.com/uclusionhq/multiple-tabs-in-your-app-133b</link>
      <guid>https://forem.com/uclusionhq/multiple-tabs-in-your-app-133b</guid>
      <description>&lt;p&gt;Update 2024 use &lt;a href="https://www.npmjs.com/package/tab-election"&gt;tab-election&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;We had some problems with multiple tabs that are pretty common:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing to storage could collide or not get picked up&lt;/li&gt;
&lt;li&gt;Logout in one tab would not be noticed in the other&lt;/li&gt;
&lt;li&gt;Sync with the backend would be done independently by all&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Being &lt;a href="https://www.uclusion.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=multitab"&gt;Uclusion&lt;/a&gt; we of course used a Uclusion Dialog to decide and the options were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/broadcast-channel"&gt;broadcast-channel&lt;/a&gt; the NPM package&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API"&gt;Broadcast channel API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://felixgerschau.com/how-to-communicate-with-service-workers/#:~:text=Service%20Workers%20can%20intercept%20requests,when%20all%20tabs%20are%20closed"&gt;Service worker communication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pretty easy decision because in addition to using broadcast channel API when available the NPM package supported leader selection. That allowed us to set up a React context to let us know anywhere in the code whether our tab was leader or not - see code &lt;a href="https://github.com/Uclusion/uclusion_web_ui/blob/a013f9327700f2d67d56df2d9154575b18cddde2/src/contexts/LeaderContext/LeaderContext.js"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We could also send messages to the other tabs telling them to refresh from IndexedDB &lt;a href="https://github.com/Uclusion/uclusion_web_ui/blob/0523b6fd43d8a696082b2ac1530c4081a3594f4b/src/contexts/CommentsContext/commentsContextReducer.js"&gt;like so&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const myChannel = new BroadcastChannel(COMMENTS_CHANNEL);
      return myChannel.postMessage('comments').then(() =&amp;gt; myChannel.close())
        .then(() =&amp;gt; console.info('Update comment context sent.'));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the basic idea we followed was the leader syncs from the backend and stores in an IndexedDB namespace and all other tabs store their local edits in a differently named IndexedDB namespace. Its very unlikely more than one tab is doing local edits at a time and even if somehow they were the sync from the network is the eventual master.&lt;/p&gt;

&lt;p&gt;Also very simple &lt;a href="https://github.com/Uclusion/uclusion_web_ui/blob/fdab31beb38bac3c1cc581a9c38fe06798dfe422/src/pages/Authentication/SignOut.js"&gt;logout&lt;/a&gt; broadcasts a message which is listened for by the other tabs &lt;a href="https://github.com/Uclusion/uclusion_web_ui/blob/b73290bcaf7ad8be153ff8dc31f253378e30a21f/src/containers/Header/index.js"&gt;here&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [logoutChannel, setLogoutChannel] = useState(undefined);

  useEffect(() =&amp;gt; {
    console.info('Setting up logout channel');
    const myLogoutChannel = new BroadcastChannel('logout');
    myLogoutChannel.onmessage = () =&amp;gt; {
      console.info('Logging out from message');
      onSignOut().then(() =&amp;gt; console.info('Done logging out'));
    }
    setLogoutChannel(myLogoutChannel);
    return () =&amp;gt; {};
  }, []);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>architecture</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>Uclusion React code now public</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Sat, 12 Sep 2020 16:21:51 +0000</pubDate>
      <link>https://forem.com/uclusionhq/uclusion-react-code-now-public-3a42</link>
      <guid>https://forem.com/uclusionhq/uclusion-react-code-now-public-3a42</guid>
      <description>&lt;p&gt;In order to help with the learning curve in React, Uclusion &lt;a href="https://github.com/Uclusion/uclusion_web_ui"&gt;uclusion_web_ui&lt;/a&gt; is now public with a Readme to many articles on Dev.To explaining its code.&lt;/p&gt;

&lt;p&gt;I've been searching for a while now and am unable to find anything like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Public UI for a large recently launched React application that you can log in for free and use&lt;/li&gt;
&lt;li&gt;Explained point by point with blogs and we are happy to add more if you request&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://github.com/mattermost/mattermost-webapp"&gt;Mattermost&lt;/a&gt; was the closest I was able to find and until their cloud beta finishes you have to setup a server to run them. With a Github or Google identity you are one click away from running Uclusion (and with any email several clicks) - no credit card required.&lt;/p&gt;

&lt;p&gt;If you are new to React or even front end development in general then this repo and accompanying blogs are the resource I wish I had a couple of years ago. At the time we used Tarik Huber's excellent &lt;a href="https://github.com/TarikHuber/react-most-wanted"&gt;React Most Wanted&lt;/a&gt; which I also recommend but its no substitute for access to documented, easy to run, production level code.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>news</category>
    </item>
    <item>
      <title>Responding to Mr. Hastings  statements about WFH</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Wed, 09 Sep 2020 18:57:37 +0000</pubDate>
      <link>https://forem.com/uclusionhq/responding-to-mr-hastings-statements-about-wfh-269f</link>
      <guid>https://forem.com/uclusionhq/responding-to-mr-hastings-statements-about-wfh-269f</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hTJNLMZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/59ydloijfzsystx4pae0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hTJNLMZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/59ydloijfzsystx4pae0.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine a world like ours suffering a pandemic but there are no streaming services. The movie theaters shut down and people are forced to watch entertainment from the internet in any way they can cobble together.&lt;/p&gt;

&lt;p&gt;Now along comes someone and says watching from home is "&lt;a href="https://archive.is/6iK6Z"&gt;a pure negative&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;Mr. Hastings says, "Debating ideas is harder now." just as in that alternate no streaming services world someone might say, "full immersion in the entertainment is harder now."&lt;/p&gt;

&lt;p&gt;Of course without streaming services one would have no concept of binge watching and so watching from home would have less upside. Just as in a world where working from home tools like &lt;a href="https://www.uclusion.com"&gt;Uclusion&lt;/a&gt; are unknown it might seem that asynchronous collaboration is very difficult.&lt;/p&gt;

&lt;p&gt;Early on in any technological change skeptics can poke fun. The real surprise is a visionary like Hastings having so little vision on this subject:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If I had to guess, the five-day workweek will become four days in the office while one day is virtual from home. I’d bet that’s where a lot of companies end up.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why not four days virtual from home and one day in the office? If WFH is such a negative why would people want the one day from home? America is very early on in this experiment and already working remotely is working much, much better than predicted. As new technology built for asynchronous collaboration becomes more wide spread the case for a high percentage of time in the office will only decrease.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>remote</category>
      <category>leadership</category>
    </item>
    <item>
      <title>How Uclusion Makes Life Easier for the Team Lead</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Fri, 17 Jul 2020 00:32:41 +0000</pubDate>
      <link>https://forem.com/uclusionhq/how-uclusion-makes-life-easier-for-the-team-lead-25f4</link>
      <guid>https://forem.com/uclusionhq/how-uclusion-makes-life-easier-for-the-team-lead-25f4</guid>
      <description>&lt;p&gt;As a point of departure let’s use Lane Wagner’s observations on four problems faced by current common process:&lt;br&gt;
&lt;a href="https://hackernoon.com/leave-scrum-to-rugby-4-major-issues-with-using-scrum-gp2x3uyi?source=rss"&gt;&lt;strong&gt;Leave Scrum To Rugby - 4 Major Issues With Using Scrum | Hacker Noon&lt;/strong&gt;&lt;br&gt;
*Bitcoinist, libertarian, atheist, cryptography fan, and founder of http://qvault.io Scrum is a buzzword, the virtue…*hackernoon.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem #1 — Scrum Is Vague
&lt;/h2&gt;

&lt;p&gt;Here’s how &lt;a href="https://www.uclusion.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=devteamlead"&gt;Uclusion&lt;/a&gt;’s built in workflow and rules make the state of development crystal clear:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0sVqTjRA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2562/1%2Aql4deunjN3OZ9TTK7les8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0sVqTjRA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2562/1%2Aql4deunjN3OZ9TTK7les8g.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At a glance, Dene Jille’s story in Proposed is not approved yet (red text), her story In Progress is on track, her story in Review has unresolved comments (red text), she is Blocked on “Map software” story and Requires Input on “Naming and domain” story.&lt;/p&gt;

&lt;p&gt;This is all backed by Uclusion enforcing only one story In Progress at a time and opening a blocking type comment automatically moving the story to Blocked. Also, Opening a Dialog on a story automatically moves it to Requires Input, and if a story is past its estimated completion date then Dene has to enter a progress report or the whole card shows yellow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem #2 — The “Sprint”
&lt;/h2&gt;

&lt;p&gt;Sprints don’t enable agile software delivery — they crush agile altogether unless you live in some dinosaur world where collaboration can wait to happen once every two weeks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x42jlAwq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2472/1%2AVGlzmmGHywUg8tpbbR69iw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x42jlAwq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2472/1%2AVGlzmmGHywUg8tpbbR69iw.png" alt="Uclusion Workspace with a new edit showing a highlighted diff"&gt;&lt;/a&gt;&lt;em&gt;Uclusion Workspace with a new edit showing a highlighted diff&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Uclusion works a different way.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Don’t maintain a backlog of fully flushed out stories that may or may not be ever implemented. Instead keep your requirements in a wiki like area in the Workspace. When the requirements are changed everyone will be notified and see a diff.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A developer or team lead will write up a story from the list of requirements and assign it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The story will be in Proposed and one or more members of the team can approve it&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uALKaDEb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2516/1%2AQ3DMhrRuYv4-iB6FPKtpVA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uALKaDEb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2516/1%2AQ3DMhrRuYv4-iB6FPKtpVA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you really want every single team member to estimate and approve the story then there is a Workspace setting for the number of approvals required — change it to the size of your team. The important thing is that the approval, implement and review cycle in Uclusion is truly continuous — not on arbitrary Sprint boundaries.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem #3 — The Scrum Master
&lt;/h2&gt;

&lt;p&gt;Effectively Uclusion has automated some of what was perceived as a Scrum master’s job.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--huwwkKeF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A_zd6xsXR4jvu3mq5miaT6w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--huwwkKeF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A_zd6xsXR4jvu3mq5miaT6w.png" alt="Uclusion notifies everyone so a Scrum master does not have to"&gt;&lt;/a&gt;&lt;em&gt;Uclusion notifies everyone so a Scrum master does not have to&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;However fully agile software delivery has a lot better things for a process person to do. With the team at full speed and potentially changing direction more often the work shifts to helping get everyone on the same page. Here is where Uclusion’s structured communication shines:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wLm-NRUx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4000/0%2AZLFcSj0Zr3nayYs2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wLm-NRUx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4000/0%2AZLFcSj0Zr3nayYs2.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Opening a TODO on a story prevents it from changing stage until the TODO is resolved.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Aa1_cZLc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2526/1%2AhRCqfADHQbf4y0E4SVrKIw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Aa1_cZLc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2526/1%2AhRCqfADHQbf4y0E4SVrKIw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Options for doing a story get their approval right inside the story. Now when the team lead or process czar wants to keep things moving he can see exactly what the issues are and, if necessary, call meetings that have an agenda that makes sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem #4 — Estimates
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;In Scrum&lt;/strong&gt; &lt;strong&gt;you don’t even write down people’s individual opinions.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Much of the Scrum ceremonies are data for the sake of data instead of being actionable. If your burn down chart looks bad or Sprint estimates are wrong what are you going to do about it? Most likely have a retrospective meeting where nothing is resolved either. Instead of a traditional retrospective Uclusion recommends &lt;a href="https://medium.com/uclusion/how-teams-work-with-uclusion-d675bdfc4fca"&gt;opening a Dialog&lt;/a&gt; and doing something with about it now — not 2 weeks later.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--reB43igU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2458/0%2A2VhiXEKWFMs1PVMK.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--reB43igU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2458/0%2A2VhiXEKWFMs1PVMK.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Its just easier
&lt;/h2&gt;

&lt;p&gt;If you are a team lead insist on a process and supporting collaboration tool that matches the way software is built in 2020. We think Uclusion is that tool and would love to talk about it — &lt;a href="https://calendly.com/uclusion/30min"&gt;https://calendly.com/uclusion/30min&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>agile</category>
    </item>
    <item>
      <title>Getting the highest ROI out of Contractors</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Tue, 14 Jul 2020 21:38:57 +0000</pubDate>
      <link>https://forem.com/uclusionhq/getting-the-highest-roi-out-of-contractors-5f3c</link>
      <guid>https://forem.com/uclusionhq/getting-the-highest-roi-out-of-contractors-5f3c</guid>
      <description>&lt;p&gt;&lt;a href="https://www.uclusion.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=devcontractor"&gt;Uclusion&lt;/a&gt;, works a lot with contractors. If you’ve ever done so yourself, you understand that the single biggest problem is making sure that the contractor is constantly doing useful work.&lt;/p&gt;

&lt;p&gt;We believe that the features we describe below are the &lt;em&gt;minimum requirements&lt;/em&gt; for any product which is going to help you get good ROI from your contractors.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Contractor “Swim Lanes” (personalized Kanban boards), are right on your home page.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ORpnTQpP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4598/1%2A6rNCB3KQzD5_LyvZmdxAsQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ORpnTQpP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4598/1%2A6rNCB3KQzD5_LyvZmdxAsQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Approval for a story requires value to be assigned to a story.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ujxmvw5i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4506/1%2AyZJ_OHWkojsz-mkugi0-cA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ujxmvw5i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4506/1%2AyZJ_OHWkojsz-mkugi0-cA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;If the story is taking more time than estimated we will demand a progress report from the contractor and mark the story as in danger.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ihLMm_Zg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4604/1%2AglQZ1cmWUZJ_307jMgZ52A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ihLMm_Zg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4604/1%2AglQZ1cmWUZJ_307jMgZ52A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;When your contractor raises a blocking issue on a story, you will be immediately notified, and will see it in the swim lanes.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--82vgeZtD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4730/1%2AAy46dxoXtMKZhvpiU6HG3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--82vgeZtD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4730/1%2AAy46dxoXtMKZhvpiU6HG3g.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;You can provide, TODOs and the contractor can’t move the story forward until they do what you tell them.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L81VA8wG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4486/1%2AR2Uq_cNYd3nqznSFP0JwPA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L81VA8wG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/4486/1%2AR2Uq_cNYd3nqznSFP0JwPA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;It’s clearly visible when a story needs your input.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sqa_-VTp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2512/1%2AJkv0eH_-3MkaCggY5N0oYw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sqa_-VTp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2512/1%2AJkv0eH_-3MkaCggY5N0oYw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Communication resides inside the story, not outside of it.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7k3a9IjN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2536/1%2A9sucgym1XQC8xzZkPogXiQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7k3a9IjN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2536/1%2A9sucgym1XQC8xzZkPogXiQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;You can easily communicate with images and files, not just text.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hz1WNN6a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2464/1%2AJiDhwpQA-Fu0I_GEro9qTw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hz1WNN6a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2464/1%2AJiDhwpQA-Fu0I_GEro9qTw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  It &lt;em&gt;is&lt;/em&gt; possible to effectively manage contractors without spending inordinate amounts of time or effort. However to do so you need a tool like Uclusion, or you’re going to see significantly lower ROI than you could be.
&lt;/h2&gt;

</description>
      <category>productivity</category>
      <category>management</category>
    </item>
    <item>
      <title>Is Testim worth using for automated testing?</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Fri, 10 Jul 2020 19:50:37 +0000</pubDate>
      <link>https://forem.com/uclusionhq/is-testim-worth-using-for-automated-testing-3cad</link>
      <guid>https://forem.com/uclusionhq/is-testim-worth-using-for-automated-testing-3cad</guid>
      <description>&lt;p&gt;For the past couple of weeks, I have been using Testim.io as a tool to create tests for the company &lt;a href="https://www.uclusion.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=devtestim"&gt;Uclusion&lt;/a&gt;’s user interface, so it’s safe to say I have a pretty good impression on the site’s capabilities. In short, it’s a mixed bag. The amount of struggle you’ll have in Testim entirely depends on what you’re testing. Testim excels when you bug-test simple things, like the Google Calculator: the test making process and run-through are notably smooth . But when you try to use it for full-blown websites, like the Uclusion.com site I’m working on now, …not so much. Here is a list of its strengths and weaknesses, so you can decide whether Testim is the one for you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9fgw0ayV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Ad56uTZoVnTE07T9YFFV8EA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9fgw0ayV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Ad56uTZoVnTE07T9YFFV8EA.png" alt="“Educate” on top, support on bottom."&gt;&lt;/a&gt;&lt;em&gt;“Educate” on top, support on bottom.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Great customer service.&lt;/strong&gt; If you have a question or concern, on the upper right, they have an “educate” button that answers a variety from frequently asked questions, from basic to expert. If you can’t find what you’re looking for in there, you can contact their support team, who respond in a couple of minutes. They are a really nice group of people who try to answer anything problems you have.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easy to use.&lt;/strong&gt; Pictures 2 and 3 on the bottom left is a test I made for Uclusion, where it tests its Google sign up option. As you can see, it allows groups, which are very useful for reusing steps, making the test creating process significantly faster. Once you have created the test, the run through is very straight forward, telling you exactly where it messes up (if there is an error that is). Testim is very comparable to coding. It will do exactly the instructions you give it. The instruction making process is very simple: all you have to do is perform an action, and Testim will record it and replicate it as an instruction. Just remember whatever you do when recording, you’re doing in an actual browser.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CxRkEE8H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3192/1%2Ac-HpYIZcXWBadG5lfBJcVQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CxRkEE8H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3192/1%2Ac-HpYIZcXWBadG5lfBJcVQ.png" alt="Picture 2 (An array of subsequent groups)"&gt;&lt;/a&gt;&lt;em&gt;Picture 2 (An array of subsequent groups)&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Weakness:&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_NnQ3u9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3220/1%2AA1GEY6qV6BMCwPduMh-1sw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_NnQ3u9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3220/1%2AA1GEY6qV6BMCwPduMh-1sw.png" alt="Picture 3 (The steps inside a group)"&gt;&lt;/a&gt;&lt;em&gt;Picture 3 (The steps inside a group)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Major lack of flexibility.&lt;/strong&gt; All of Testim’s weaknesses stem from this, so instead of having a long list of each individual weakness, I’ll try to summarize my problems so far. When I said the instruction making process is simple, I didn’t necessarily say it was good, or flexible. If you intend to use it as a legitimate website testing tool, this is where you’ll run into problems. You are extremely limited in what actions you can perform. For example, Testim doesn’t have a function where you can navigate through Google accounts without programming. It will also be unable to catalog links. If you copy a generated link, Testim will generate a step where it continually navigates to that specific link you clicked, rather then the general “copy and paste generated link” step you probably intended. In short, if you try anything that is the slightest abnormal Testim will either be unable to create that action for you, or be inconsistent in the test running process.&lt;/p&gt;

</description>
      <category>testing</category>
    </item>
    <item>
      <title>How Teams Work with Uclusion</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Tue, 07 Jul 2020 21:28:23 +0000</pubDate>
      <link>https://forem.com/uclusionhq/how-teams-work-with-uclusion-530o</link>
      <guid>https://forem.com/uclusionhq/how-teams-work-with-uclusion-530o</guid>
      <description>&lt;p&gt;We’ve all seen that email is too silo’ed; important discussions get trapped and never see the light of day. However group chat has gone too far in the other direction:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Put the message in a #channel&lt;br&gt;
Even if a Slack message is directed to one person, it should be posted in the appropriate channel and not via DM. Most of our channels correspond to a project, so you never know when another team member might need that information in the future. Following this rule has transformed Slack into a valuable archive that’s simple to search.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’m not going explain why that’s madness — by now everyone has experienced that kind of garden hose of notifications and information and already knows all too well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.uclusion.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=devteam"&gt;Uclusion&lt;/a&gt; recommends a different approach to sharing information with those that are not directly involved in your project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Put read only links to Uclusion stories into your code&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Put read only links to Uclusion Workspaces into a &lt;em&gt;Team Workspace&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To create a team Workspace&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MYSCtp4b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ABTmqjuDXnXoLsbUNKlhgkg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MYSCtp4b--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ABTmqjuDXnXoLsbUNKlhgkg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;choose the first option above and name the Workspace with your team designation. Now invite everyone on your team to the Workspace.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sF4_6d9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2436/1%2AgHZRbLhupzHxU3Sa4aIS6Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sF4_6d9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2436/1%2AgHZRbLhupzHxU3Sa4aIS6Q.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Members of your team probably already have different projects they are working on in &lt;a href="https://production.uclusion.com/?utm_source=medium&amp;amp;utm_medium=blog&amp;amp;utm_campaign=team#signUp"&gt;Uclusion&lt;/a&gt; Workspaces. For instance “V3 API”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TDxZhGl3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2438/1%2Afuhl6UZRNrOtCg2DSUZ3rg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TDxZhGl3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2438/1%2Afuhl6UZRNrOtCg2DSUZ3rg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You’ll want to choose “Share a read only link” as you see above and then paste that link into the description of your team Workspace (the link will automatically have the name “V3 API” applied to it).&lt;/p&gt;

&lt;p&gt;After everyone on your team has pasted in the Workspaces they are involved in you can share a read only link to this team Workspace for all to know what your team is doing. And since everyone on your team is a collaborator in the team Workspace they will be notified of all changes.&lt;/p&gt;

&lt;p&gt;But that’s not all, in the past when you wanted to change your team process perhaps you had a retrospective meeting or a long email chain. If that is working for you then continue on, otherwise choose “Add Dialog”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n0xNSncP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aq-xO1VwoFVv_wYjkgoBtgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n0xNSncP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aq-xO1VwoFVv_wYjkgoBtgg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and state the problem and possible solutions there:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_hnQ7Ful--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2458/1%2AxW5VEfmQJputMv1FsUn1LQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_hnQ7Ful--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2458/1%2AxW5VEfmQJputMv1FsUn1LQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally team level discussion can use the team Workspace’s structured communication options&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JbfwWg9l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2496/1%2A2PgiezDMN-qvhrJetocRBA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JbfwWg9l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2496/1%2A2PgiezDMN-qvhrJetocRBA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>agile</category>
    </item>
    <item>
      <title>How Product Managers Work with Uclusion</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Tue, 07 Jul 2020 18:49:38 +0000</pubDate>
      <link>https://forem.com/uclusionhq/how-product-managers-work-with-uclusion-3hp4</link>
      <guid>https://forem.com/uclusionhq/how-product-managers-work-with-uclusion-3hp4</guid>
      <description>&lt;p&gt;Sometimes the terms collaboration, brainstorming and empowerment get mixed up and since &lt;a href="https://www.uclusion.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=devpm"&gt;Uclusion&lt;/a&gt; is a great tool for all of them it can be confusing. Collaboration is “the action of working with someone to produce or create something.” Even if a PM provides all details its still collaboration and its still hard. Explaining in English precisely enough that computer code can be written makes PM / engineering communication a real challenge.&lt;/p&gt;

&lt;p&gt;On top of which customers can be indecipherable, priorities change and technical realities intervene. That’s why a Uclusion Workspace is a great place to collaborate on requirements&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you change requirements everyone will be notified and automatically see a diff&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ku6JxIfw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A152zPR1PzHHQvom5bkT9ZA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ku6JxIfw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A152zPR1PzHHQvom5bkT9ZA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s a lot easier than entering a separate backlog item for every single requirement and much easier to maintain.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You receive notifications and see highlighting for the structured comments entered about the requirements and comment can be resolved when addressed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZcSrabp8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2530/1%2A33sPzKm0Y-WDT7_l43tSeg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZcSrabp8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2530/1%2A33sPzKm0Y-WDT7_l43tSeg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the requirements are understood engineers can start creating stories based on those requirements right in the same Workspace.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When someone needs help on how a story will be implemented you will be notified and it shows in a separate section of the &lt;a href="https://medium.com/uclusion/an-opinionated-review-of-asynchronous-team-collaboration-tools-for-2020-2104ef1897d3"&gt;Uclusion swim lanes&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0qoOg9n8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AxR_KwXtieqsMEpS9DXCNJQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0qoOg9n8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AxR_KwXtieqsMEpS9DXCNJQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The options you need to weigh in as the PM are discussed and approved right inside the story&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8NRwKs7d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2500/1%2AeoKibLmFCc8NqQ9ZA-rDxA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8NRwKs7d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2500/1%2AeoKibLmFCc8NqQ9ZA-rDxA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Instead of a long ambiguous email thread or group chat everyone knows exactly what was decided and how.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you need a rough idea of when the requirements in the Workspace will be complete ask the engineering team to maintain the Workspace date of completion field. That displays right alongside the requirements you have input and you will be notified if it is changed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And if you need to go back to customers for clarification don’t start one of those long ambiguous email threads with them either. Use a Uclusion Dialog instead.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>agile</category>
    </item>
    <item>
      <title>Integration Tests, Promises and Websockets</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Sat, 27 Jun 2020 17:01:49 +0000</pubDate>
      <link>https://forem.com/uclusionhq/integration-tests-promises-and-websockets-2h30</link>
      <guid>https://forem.com/uclusionhq/integration-tests-promises-and-websockets-2h30</guid>
      <description>&lt;p&gt;&lt;a href="https://www.uclusion.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=devwebsockets"&gt;Uclusion&lt;/a&gt; is powered by an eventually consistent Rest API and uses WebSockets to inform the client when data changes server side. This means that any integration test that depends on writes happening in a sequence must integrate web sockets into it’s control flow.&lt;/p&gt;

&lt;p&gt;More specifically, the integration test must integrate web sockets in a way that allows for messages to arrive in any order, and must fuse the WebSocket notification with the standard Promise based control flow that our SDK presents.&lt;/p&gt;

&lt;p&gt;So how do we do this? With a WebSocket “runner”:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import _ from 'lodash';
var W3CWebSocket = require('websocket').w3cwebsocket;

/**
 * Class which fires and manages a websocket connection to the server. Copied from and derived from the uclusion web ui code
 */
class WebSocketRunner {
    constructor(config) {
        this.wsUrl = config.wsUrl;
        this.reconnectInterval = config.reconnectInterval;
        this.subscribeQueue = [];
        this.messageHanders = [];
    }

    getMessageHandler() {
        const handler = (event) =&amp;gt; {
            //console.log(event);
            const payload = JSON.parse(event.data);
            //we're going to filter the messagehandlers at each run
            //and if they return true assume they want to go away
            this.messageHanders = this.messageHanders.filter(messageHandler =&amp;gt; !messageHandler(payload));
        };
        return handler.bind(this);
    }

    /**
     * Subscribes the given user id to the subscriptions described in the subscriptions object
     * subscriptions is an object of a form similar to
     * @param idToken the identity token to subscribe too
     */
    subscribe(idToken) {
        const action = { action: 'subscribe', identity : idToken };
        // push the action onto the subscribe queue so if we reconnect we'll track it
        this.subscribeQueue.push(action);
        // if socket is open, just go ahead and send it
        if (this.socket.readyState === this.socket.OPEN) {
            const actionString = JSON.stringify(action);
            this.socket.send(actionString);
        }
        // compact the queue to remove duplicates
        const compacted = _.uniqWith(this.subscribeQueue, _.isEqual);
        this.subscribeQueue = compacted;
    }

    onOpenFactory() {
        // we have to assign queue this to prevent the handler's
        // this from being retargeted to the websocket
        const queue = this.subscribeQueue;
        //console.debug('Subcribing to:', queue);
        const factory = (event) =&amp;gt; {
          //  console.debug('Here in open factory with queue:', JSON.stringify(queue));
          //  console.debug('My socket is:', this.socket);
            queue.forEach(action =&amp;gt; {
                const actionString = JSON.stringify(action);
                //console.debug('Sending to my socket:', actionString);
                this.socket.send(actionString);
            });
            // we're not emptying the queue because we might need it on reconnect
        };
        return factory.bind(this);
    }

    onCloseFactory() {
        const runner = this;
        const connectFunc = function (event) {
            //console.debug('Web socket closed. Reopening in:', runner.reconnectInterval);
            setTimeout(runner.connect.bind(runner), runner.reconnectInterval);
        };
        return connectFunc.bind(this);
    }

    // dead stupid version without good error handling, we'll improve later,
    connect() {
        this.socket = new W3CWebSocket(this.wsUrl);
        this.socket.onopen = this.onOpenFactory();
        this.socket.onmessage = this.getMessageHandler();
        // make us retry
        this.socket.onclose = this.onCloseFactory();
    }

    /** Waits for a received message matching the signature passed in
     *
     * @param signature an object of key/value pairs we'll wait for
     * @return A promise that resolves if the message is received within timeout milliseconds,
     * otherwise rejects
     */
    waitForReceivedMessage(signature){
        return this.waitForReceivedMessages([signature]).then((responses) =&amp;gt; responses[0]);
    }

    /** Waits for a received messages matching the signature passed in
     *
     * @param signatures an array of object of key/value pairs we'll wait for
     * @return A promise that resolves if the message is received within timeout milliseconds,
     * otherwise rejects
     */
    waitForReceivedMessages(signatures){
        console.log("Waiting on message signatures:");
        console.log(signatures);

        const promises = signatures.map(signature =&amp;gt; {
            return new Promise((resolve, reject) =&amp;gt; {
                //     const timeoutHandler = setTimeout(() =&amp;gt; { reject(signature) }, timeout);
                this.messageHanders.push((payload) =&amp;gt; {
                    console.log("Received payload for matching:");
                    console.log(payload);
                    let stillMatching = true;
                    console.log(IT"Testing message against signature:");
                    console.log(signature);
                    for(const key of Object.keys(signature)){
                        stillMatching &amp;amp;= (payload[key] === signature[key] || isSubsetEquivalent(payload[key], signature[key]));
                    }
                    if (stillMatching) {
                        console.log("Found match");
                        //            clearTimeout(timeoutHandler);
                        resolve(payload);
                        return true;
                    }
                    return false;
                });
            });
        });
        return Promise.all(promises);
    }

    terminate(){
        // kill the reconnect handler and close the socket
        this.socket.onclose = (event) =&amp;gt; {};
        this.socket.close();
    }
}

function isSubsetEquivalent(payload, signature) {
    if ((!payload &amp;amp;&amp;amp; signature) || (!signature &amp;amp;&amp;amp; payload)) {
        return false
    }
    for(const key of Object.keys(signature)){
        if (payload[key] !== signature[key]) {
            return false;
        }
    }
    return true;
}

export { WebSocketRunner };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In general, the WebSocket runner above presents a function waitForReceivedMessages that allows the caller to register a signature and returns a promise that will &lt;em&gt;resolve&lt;/em&gt; when a message comes in over the wire that matches the signature. A message is considered to match, if all fields in the signature match the corresponding fields in the message. Note, however, that a message may have &lt;em&gt;more&lt;/em&gt; fields than the signature, which allows us to only give signatures for the things we consider important in the message.&lt;/p&gt;

&lt;p&gt;Usage of the runner proceeds as follows:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;....
}).then((messages) =&amp;gt; {
    const userPoked = messages.find(obj =&amp;gt; {
        return obj.type_object_id === 'USER_POKED_' + adminId;
    });
    assert(userPoked.text === 'Please add the thing.', 'Wrong poke text');
    return userClient.users.removeNotification(adminId, 'USER_POKED', createdMarketId);
}).then(() =&amp;gt; {
    return userConfiguration.webSocketRunner.waitForReceivedMessage({event_type: 'notification', object_id: userExternalId});
}).then(() =&amp;gt; {
....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Your situation may require two-way communication via the WebSocket. In that case I would model the message transmission from client to server as a promise, which will allow you to serialize your communication sequences much like we do with our Rest API.&lt;/p&gt;

&lt;p&gt;That’s about it, and I hope this helps you along your testing journey.&lt;/p&gt;

</description>
      <category>node</category>
      <category>testing</category>
    </item>
    <item>
      <title>Designing SaaS Rest APIs for web clients</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Tue, 23 Jun 2020 21:54:14 +0000</pubDate>
      <link>https://forem.com/uclusionhq/designing-saas-rest-apis-for-web-clients-3086</link>
      <guid>https://forem.com/uclusionhq/designing-saas-rest-apis-for-web-clients-3086</guid>
      <description>&lt;p&gt;For a typical browser IndexedDB storage gives you access to as much as half the free disk space. Once you convince yourself to use Rest, having that much storage makes your basic flow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Have an API that returns all changed items for a client.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have APIs that return the items for anything that changed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any create or update API will need to return the back end stored object so that the front end can update its IndexedDB cache.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In general do not expose individual item read APIs or APIs that filter, sort or search — do all of that on the web client.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In graphical terms 1 and 2 look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RVrcvidZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A9Xy2i3yHDO9WyEB4GMrcVA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RVrcvidZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A9Xy2i3yHDO9WyEB4GMrcVA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So far very simple but 3 is where we fall down the rabbit hole. If any single one of your APIs is eventually consistent then answering “Client up to date?” is hard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.uclusion.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=devapi"&gt;Uclusion&lt;/a&gt; uses DynamoDB and asynchronous workflows built on DynamoDB streams so of course there is eventually consistent everywhere. Even with a SQL DB you could be reading from a slave or multi-master database where replication lag will be eventually consistent. If you rely on a read immediately following a write returning the data you just wrote then the front end client is dictating back end implementation.&lt;/p&gt;

&lt;p&gt;If because of client space or compute limitations filter, sort and search capabilities must have APIs then run them outside your main transactional database. Otherwise long running queries against the same database requiring lightning fast create and updates is a use case mismatch. So these kinds of querying APIs require eventual consistency as traffic and volume of data scales.&lt;/p&gt;

&lt;p&gt;With eventual consistency a call to refresh the client with the latest data can overwrite newer data that it already has from create and update operations. So a user might see his newly created object disappear for a while unless you are careful.&lt;/p&gt;

&lt;p&gt;Traditional CRUD where a page loads from the back end dynamically or hoping to get by with an all synchronous API are strategies that user performance expectations and SaaS traffic loads have obsoleted. Our strategy for handling syncing eventually consistent objects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;All objects are versioned and these versions are used for signatures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When the back end sends the object signatures it records an ID in a look up table for what was sent to the client.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the client is successful in retrieving the object signatures it uses the signature ID in subsequent calls to inform the back end what object versions it has.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>architecture</category>
    </item>
    <item>
      <title>Notes on S3 backed File Downloads</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Fri, 19 Jun 2020 21:09:41 +0000</pubDate>
      <link>https://forem.com/uclusionhq/notes-on-s3-backed-file-downloads-42i3</link>
      <guid>https://forem.com/uclusionhq/notes-on-s3-backed-file-downloads-42i3</guid>
      <description>&lt;p&gt;&lt;a href="https://www.uclusion.com/?utm_source=devto&amp;amp;utm_medium=blog&amp;amp;utm_campaign=devfiledownload"&gt;Uclusion&lt;/a&gt; recently introduced arbitrary file uploads to our Workspaces or Stories (we previously allowed only images), and there are a few implementation notes I’d like to record for posterity.&lt;/p&gt;

&lt;p&gt;Firstly, browsers do not always provide a content type when uploading a file. If your backend demands content types the code something like the below is needed when asking for a presigned post&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export function uploadFileToS3 (marketId, file) {
  const clientPromise = _.isEmpty(marketId) ? getAccountClient() : getMarketClient(marketId);
  const { type, size, name } = file;
  // if we don't have a content type, use generic octet stream
  const usedType = _.isEmpty(type)? 'application/octet-stream' : type;
  return client.getFileUploadData(usedType, size, name))
    .then((data) =&amp;gt; {
      const { metadata, presigned_post } = data;
      const { url, fields } = presigned_post;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/Uclusion/uclusion_web_ui/blob/master/src/api/files.js"&gt;See production file with this code&lt;/a&gt;.&lt;br&gt;
Second, unless your served JS or HTML is coming from the same domain as your CDN, browsers will happily ignore the &lt;a href="https://www.w3schools.com/TAGS/att_a_download.asp"&gt;download&lt;/a&gt; attribute of S3 links. They will either open it in a new tab with their viewer, or, for security reasons, use the S3 bucket’s file’s name. This means that if you machine generate paths such as &lt;a href="https://dev.imagecdn.uclusion.com/8432f156-f452-4031-8e7d-728deb25f7cd/35fed849-1b69-4f05-9cea-99f57d5f71e9"&gt;https://dev.imagecdn.uclusion.com/8432f156-f452-4031-8e7d-728deb25f7cd/35fed849-1b69-4f05-9cea-99f57d5f71e9&lt;/a&gt; the user will end up with a file of &lt;a href="https://dev.imagecdn.uclusion.com/8432f156-f452-4031-8e7d-728deb25f7cd/35fed849-1b69-4f05-9cea-99f57d5f71e9"&gt;35fed849–1b69–4f05–9cea-99f57d5f71e9&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To avoid this, set your content distribution on your presigned post. This won’t effect the downloaded path, but is a method of telling the browser what you want the downloaded filename to be. Here’s code that does that, and also attempts to set the extension on the path appropriately:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def post_validation_function(event, data, context, validation_context):
    content_length = data['content_length']
    original_name = data.get('original_name', None)
    content_type = data['content_type']
    file_path = str(uuid.uuid4())
    # See if they provided the original name,
    # and if so use it, and try to put a good extension on
    fields = {"Content-Type": content_type}
    if original_name is not None:
        fields["Content-Disposition"] = 'attachment; filename="' + original_name + '"'
    extension = guess_file_extension(content_type)
    if extension is not None:
        file_path = file_path + extension

    used_id = validation_context['market_id'] if validation_context['market_id'] is not None else validation_context['account_id']
    path = used_id + '/' + file_path
    return create_post(path, fields, content_type, content_length, bucket)


def create_post(path, fields, content_type, content_length,  bucket):
    expiration = 60  60  24  # Upload must occur within 24 hours
    conditions = [
        ['content-length-range', content_length, content_length],
        {'Content-Type': fields['Content-Type']},
        {'Content-Disposition': fields['Content-Disposition']}
    ]
    post = s3_client.generate_presigned_post(bucket,
                                             path,
                                             Fields=fields,
                                             Conditions=conditions,
                                             ExpiresIn=expiration)
    return {
        'metadata': {
            'path': path,
            'content_length': content_length,
            'content_type': content_type
        },
        'presigned_post': post
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Notice that I set the constraints to include all Fields. If you don’t do that your users will get Access Denied whenever they try to upload.&lt;/p&gt;

&lt;p&gt;If you don’t mind the users getting generated names, then I would at least attempt to set the file extensions properly. The code above invokes the following function to do so, and extension setting is one of the reasons why we demand content-type to be passed in when doing a presigned post.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import mimetypes

# Constants to give the file upload some additional information on extensions, especially on MS mimetypes
#
MS_TYPES = {
    'application/msword': '.doc',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document': '.docx',
    'application/mspowerpoint': '.ppt',
    'application/vnd.openxmlformats-officedocument.presentationml.presentation': '.pptx',
    'application/vnd.openxmlformats-officedocument.presentationml.template': '.potx',
    'application/msexcel': '.xls',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': '.xlsx',
    'application/vnd.openxmlformats-officedocument.spreadsheetml.template': '.xltx',
    'application/msproject': '.mpp',
}


def guess_file_extension(mime_type):
    lowercase = mime_type.lower()
    system = mimetypes.guess_extension(lowercase)
    if system is not None:
        return system
    # the system doesn't know, try our MS map
    return MS_TYPES.get(lowercase, None)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>aws</category>
    </item>
    <item>
      <title>An Opinionated Review of Asynchronous Team Collaboration Tools for 2020</title>
      <dc:creator>David Israel</dc:creator>
      <pubDate>Tue, 16 Jun 2020 22:37:06 +0000</pubDate>
      <link>https://forem.com/uclusionhq/an-opinionated-review-of-asynchronous-team-collaboration-tools-for-2020-9p9</link>
      <guid>https://forem.com/uclusionhq/an-opinionated-review-of-asynchronous-team-collaboration-tools-for-2020-9p9</guid>
      <description>&lt;p&gt;The opinionated part is that this review assumes the main purpose of team collaboration software is to serve the communications needs of the team using it. If you are more in the market for a tool that organizes across projects and teams, focuses on reporting productivity or tracks hours billed then this review will not be as useful. You have to have a main purpose in mind when you choose your team’s tools because software that does it all would be too complex to do any of it well.&lt;/p&gt;

&lt;p&gt;Here we’re also going to assume that your video conferencing and direct messaging needs are out of scope. I don’t think the addition of synchronous communication will make a big difference in your choice of asynchronous tools. Most likely the best in class asynchronous team collaboration tool wins regardless of whether or not it has integrated video conferencing and synchronous messaging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uclusion
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where do your requirements go?
&lt;/h3&gt;

&lt;p&gt;In a workspace’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w9jfVGZM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2572/1%2ADhqIMgFNvbuLbmcAu80phg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w9jfVGZM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2572/1%2ADhqIMgFNvbuLbmcAu80phg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Somewhat like Wiki when the description changes everyone will be notified and see a diff.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where do your stories go?
&lt;/h3&gt;

&lt;p&gt;In swimlanes showing what each person in a workspace is up to. Note that you can only have one story in progress per Workspace and so you always know what is actually being worked on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X_pEWyI---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2514/1%2A5tPCn0vnyvlDtqfmnsY-bg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X_pEWyI---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2514/1%2A5tPCn0vnyvlDtqfmnsY-bg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Where does your communication about requirements and stories go?
&lt;/h3&gt;

&lt;p&gt;Structured, resolvable comments in a workspace or story. If you open a blocking comment it blocks, a TODO must be closed before changing stage, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PJboDbyp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2520/1%2AZ4dHSYOrnduEyzPlzKbxTA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PJboDbyp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2520/1%2AZ4dHSYOrnduEyzPlzKbxTA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also reach a decision about requirements or implementation of a story in a dialog:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E2NYYKeB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2498/1%2AiEVuT4BBOgDyvlMFpZZdGQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E2NYYKeB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2498/1%2AiEVuT4BBOgDyvlMFpZZdGQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally you can kick of a new project or direction by launching an initiative which has up down voting with certainty and reasons:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Fn2hgL5Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2504/1%2AhHPqrD1mCeytD96GCWnXXQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Fn2hgL5Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2504/1%2AhHPqrD1mCeytD96GCWnXXQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you know what everyone has done, will do now and will do next?
&lt;/h3&gt;

&lt;p&gt;The swimlanes shown above already display at a glance what everyone is up to but in addition you are prompted to vote certainty, days estimate and reason on the assignment of a story right inside the tool without having to have additional meetings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trello
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where do your requirements go?
&lt;/h3&gt;

&lt;p&gt;In cards on a Kanban board. According to Trello it would look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Bg86aBb_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2798/1%2ASyivUYnBLEAvsTst1hSrQA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Bg86aBb_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2798/1%2ASyivUYnBLEAvsTst1hSrQA.png" alt="From [https://trello.com/en-US/teams/engineering](https://trello.com/en-US/teams/engineering)"&gt;&lt;/a&gt;&lt;em&gt;From &lt;a href="https://trello.com/en-US/teams/engineering"&gt;https://trello.com/en-US/teams/engineering&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Where every requirement, no matter how small, gets its own card in an ever growing backlog.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where do your stories go?
&lt;/h3&gt;

&lt;p&gt;Same place.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where does your communication about requirements and stories go?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://help.trello.com/article/765-commenting-on-cards"&gt;Inside a card&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eVDO8Cil--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ANMyFtwJI2tJ6MjfJuq6SEA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eVDO8Cil--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ANMyFtwJI2tJ6MjfJuq6SEA.png" alt="Seriously?"&gt;&lt;/a&gt;&lt;em&gt;Seriously?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you know what everyone has done, will do now and will do next?
&lt;/h3&gt;

&lt;p&gt;Trello &lt;a href="https://blog.trello.com/trello-power-ups-for-remote-work"&gt;recommends&lt;/a&gt; the &lt;a href="https://trello.com/power-ups/5d5b3b96fe9c9f88bc7bd311"&gt;daily updates power up&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7x7_bXsL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AFyTOE3jH4Y_gao-z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7x7_bXsL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AFyTOE3jH4Y_gao-z.png" alt="I’m not making this up"&gt;&lt;/a&gt;&lt;em&gt;I’m not making this up&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Trello + Slack
&lt;/h2&gt;

&lt;p&gt;Like the Trello solution except now some of your messaging will no longer be co-located with the requirement or story it is about and instead scroll up the screen hoping to be noticed before it disappears.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trello + Slack + Google Docs
&lt;/h2&gt;

&lt;p&gt;We asked someone what they liked about this solution and they said, “Everything integrates well with each other.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure DevOps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where do your requirements go?
&lt;/h3&gt;

&lt;p&gt;Kind of laborious but you could put the requirements in an Epic and then link Issues to the Epic:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7iHKX-L2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2008/1%2A0-lnbA8fL29giiQJnLh2Mg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7iHKX-L2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2008/1%2A0-lnbA8fL29giiQJnLh2Mg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Where do your stories go?
&lt;/h3&gt;

&lt;p&gt;Following the above idea (Azure DevOps is non-opinionated software) they go in issues and issues have their own Kanban display like above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where does your communication about requirements and stories go?
&lt;/h3&gt;

&lt;p&gt;Rudimentary commenting inside the cards like Trello.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you know what everyone has done, will do now and will do next?
&lt;/h3&gt;

&lt;p&gt;Filter the Kanban board by assigned. You can add columns to the Kanban board and you can also add what is called swimlanes to the columns (like a subcolumn). However this approach is unlikely to tell you much because Azure DevOps encourages backlogs. So its a bit like looking at someone’s email Inbox to figure out what they are doing.&lt;/p&gt;

&lt;p&gt;Essentially Azure DevOps, Jira, Linear and others are designed for issue tracking - smaller, potentially customer driven, problems that are less about approval and design and more about cranking out on a schedule. Using an issue tracker is a good idea for anything that does not require much collaboration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asana
&lt;/h2&gt;

&lt;p&gt;Same as Trello in use of a Kanban board but comments inside a card look like this&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ep0dt9kZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AqEbK06tqXEoNAu1jiYbLjg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ep0dt9kZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AqEbK06tqXEoNAu1jiYbLjg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and if you want to know what people are up to you apparently &lt;a href="https://asana.com/templates/for/marketing/agile-daily-standup"&gt;create a whole different Kanban board&lt;/a&gt; and search inside each card one by one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monday.com
&lt;/h2&gt;

&lt;p&gt;Less of a collaboration tool and more of a pre built spreadsheet:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HoxdMbG---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3518/1%2As21SreBZWuNrASUw6pjU5g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HoxdMbG---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3518/1%2As21SreBZWuNrASUw6pjU5g.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Clubhouse
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iHRwRL9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2224/1%2Az2mKmLRmEskbIjgNS9dEMg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iHRwRL9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2224/1%2Az2mKmLRmEskbIjgNS9dEMg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Less of a collaboration tool and more like a database barfed on you. Do your requirements go in an Epic or a Project? Or maybe you use a Workflow?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HnU4ekPh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A5zR1qyfwGsL8CJvV1xy6CA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HnU4ekPh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A5zR1qyfwGsL8CJvV1xy6CA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Supposedly there are swim lanes like Uclusion has but after 30 minutes of really trying I was unable to get them to show. The way to compete with Jira is not by being more complex.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zepel
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Where do your requirements go?
&lt;/h3&gt;

&lt;p&gt;In their own list:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OH_MLGkh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AiJcjOkg-OqzWfgymMmhTgA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OH_MLGkh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AiJcjOkg-OqzWfgymMmhTgA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Where do your stories go?
&lt;/h3&gt;

&lt;p&gt;On a Kanban board which is a different view of the requirements list:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WFL_Ko2r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2806/1%2AvkIfF3A4c01ld1BBip6ZCw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WFL_Ko2r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2806/1%2AvkIfF3A4c01ld1BBip6ZCw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Where does your communication about requirements and stories go?
&lt;/h3&gt;

&lt;p&gt;A requirement and the story to do a requirement share a card so you can comment inside of it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5xuYx0iQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3280/1%2AQTnUGRTnH3Pzz_C5RZ4Lgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5xuYx0iQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3280/1%2AQTnUGRTnH3Pzz_C5RZ4Lgg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How do you know what everyone has done, will do now and will do next?
&lt;/h3&gt;

&lt;p&gt;I wasn’t able to find any way to do this. You can generate a burn down / up report&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rhMUKGQB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2780/1%2AU__8jyaMUACMN3Fhe3a96A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rhMUKGQB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2780/1%2AU__8jyaMUACMN3Fhe3a96A.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;but going back to our opinionated purpose how is this report actionable for the team doing the work? It doesn’t say who is blocked on what or give any indication of progress reports etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Favro
&lt;/h2&gt;

&lt;p&gt;Again the opinionated issue comes up — are we optimizing for ease of development or ease of reporting? Or put another way is it more important that stories get done or that they get done on a certain timeline?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ljtsrAUf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2528/1%2ADXwXtNKdRZbR5srTzCS74w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ljtsrAUf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2528/1%2ADXwXtNKdRZbR5srTzCS74w.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There could well be situations where the timeline is the more important factor. For instance suppose this is a situation where zero creativity is required and success is solely dependent on speed of doing a multitude of straight forward tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Microsoft Teams
&lt;/h2&gt;

&lt;p&gt;According to Microsoft &lt;a href="https://support.microsoft.com/en-ie/office/add-a-kanban-board-to-teams-3cf84256-c2b8-4108-83fa-f4e93d1ffa57"&gt;support&lt;/a&gt; you can add a Kanban board by&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3pibC1fW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AlnRofH8ybWeMJ0zxV9Ogew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3pibC1fW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AlnRofH8ybWeMJ0zxV9Ogew.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Teams literally does everything — chat, boards, wiki, conferencing, screen sharing, you name it. Reviewing it as a solution is like reviewing a laptop as a team collaboration tool; a team that collaborates is likely to have laptops and they also may be using Microsoft for something.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notion
&lt;/h2&gt;

&lt;p&gt;Similar to Teams but even more so Notion is more like a high level programming language for collaboration applications. Excellent if you want something specific that you are willing to build yourself or you want to share finished content that you worked on by yourself.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>agile</category>
    </item>
  </channel>
</rss>
