<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by John Kyeremeh on Medium]]></title>
        <description><![CDATA[Stories by John Kyeremeh on Medium]]></description>
        <link>https://medium.com/@John_Kyeremeh?source=rss-8b6384e87432------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*f--5ZkgxtA9f4tuKcraVBA.jpeg</url>
            <title>Stories by John Kyeremeh on Medium</title>
            <link>https://medium.com/@John_Kyeremeh?source=rss-8b6384e87432------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 06 May 2026 15:40:52 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@John_Kyeremeh/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Introduction to Object Relationships in Basic Ruby]]></title>
            <link>https://medium.com/@John_Kyeremeh/introduction-to-object-relationship-in-basic-ruby-74a67f28a040?source=rss-8b6384e87432------2</link>
            <guid isPermaLink="false">https://medium.com/p/74a67f28a040</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[object-oriented]]></category>
            <category><![CDATA[object-relationships]]></category>
            <category><![CDATA[flatiron-school]]></category>
            <category><![CDATA[ruby]]></category>
            <dc:creator><![CDATA[John Kyeremeh]]></dc:creator>
            <pubDate>Fri, 17 Dec 2021 14:20:33 GMT</pubDate>
            <atom:updated>2021-12-17T14:22:24.416Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NCKDn8IeYrdWsQuKzYWTbw.png" /></figure><p>When you are first learning about Object Relationships, it can be difficult to understand what type of relationship should exist between objects and how each line of code and variable, works together to create that relationship in the program.</p><p>I’ll walk you through a step-by-step example of how relationships operate abstractly and how each part of code works to create this relationship into the code we’re developing. I decided to use the world of Pokémon to illustrate object relationships in Ruby, but the major idea can be understood in other languages as well.</p><p><strong>Object relationship</strong> is a concept used to describe how different classes that create objects can interact together with other objects that we’ve created. As in real-life, how objects relate to each other varies depending on the relationship each object has with each other. As a programmer, we control how we build these relationships, which we will call <strong>the domain</strong> <strong>model</strong>. There are several basic ways in which these models relate to one another — I’m going to dive into the <strong>belongs to</strong> and the <strong>has-many</strong> relationships.</p><p>When we think about the world of Pokémon we have a <strong>Trainer</strong> who can be Ash, Brock, or Gary, or any other Pokémon trainer. The individual trainer, let’s say Ash in this example, has many Pokémon: Pikachu, Charizard, Bulbasaur, and many others. Each of these individual Pokémon has its moves, for example, Pikachu’s moves may include Thunder, Thunderbolt, &amp; Quick Attack.</p><p>I’ve chosen to focus our domain model around the popular Ash Ketchum as my example, and right now Ash has the following three Pokémon: Pikachu, Charizard, and Bulbasaur. I’ll also be using the word instance of a class and an object to mean the same thing as they can often be used interchangeably.</p><p>Ash, is an individual object of our Trainer Class, and the Ash object has its own unique set of attributes specific to that class. What do I mean by object? Think of the Trainer Class as a blueprint that allows you to create unique instances(or copies) of the Trainer class which we can call objects, so Ash is an instance of the Trainer class. Each instance of a Class has attributes that make them unique, for example, what attributes do all trainers have (other than Pokémon)? Some common attributes would be a name, possible nickname, number of pokeballs, trainer level, personality type, items, and amount of money in the trainer’s pocket to name a few.</p><p>For simplicity, I’ll focus on a few Trainer attributes for our Ash object, which remember is one instance(or object) of a Trainer with unique properties and attributes.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/90ce9a988160c44172a0f7c6f711d9a9/href">https://medium.com/media/90ce9a988160c44172a0f7c6f711d9a9/href</a></iframe><p>Now let’s create the trainer Ash object from the Trainer Class in an IRB like this:</p><figure><img alt="Ash object with attributes" src="https://cdn-images-1.medium.com/max/890/1*vlBHspDS7xd6p7aVpbfFNA.png" /></figure><p>From the above, we can return Ash’s name to us like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/559/0*rWlwb4pNZTebgQzi" /></figure><p>And we can also return the Ash object’s level like this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/565/0*7msuDYKZe9S7BQAU" /></figure><p>As far as modeling our Ash object that was created from the Trainer class to the real world, this isn’t very realistic. A Trainer has much more attributes than just name and their level. One most important attribute that is missing to be a Pokémon trainer is the trainer’s Pokémon. As we can see our program has no knowledge of who our Ash objects pokemon are or even the method to call the Pokémon.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/885/1*26TtkWikdlp4GN83zxgQ8A.png" /></figure><p>In the world of Pokémon, a Pokémon <strong>belong to</strong> a Trainer and a Trainer <strong>has many</strong> Pokémon. How can we model this Pokémon belonging to a Trainer relationship with our code? Let’s give a pokemon attribute to an individual trainer.</p><p><strong>The “Belongs To” Relationship</strong></p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/54255284cb55d48ec7e54de1703a9458/href">https://medium.com/media/54255284cb55d48ec7e54de1703a9458/href</a></iframe><p>Now that we have a setter and getter for a Trainer’s pokemon attribute, let’s review the data in IRB or Pry again:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/583/0*yfbnhZgdtxfjeGVA" /></figure><p>Let’s say we want to know the Pokemon’s name.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/566/0*h-c5t__9PsLqr8-A" /></figure><p>Looks like the “string” that we assigned to this Ash object pokémon attribute is doesn’t have access to the name method.</p><p>Instead of setting the Ash’s pokemon attribute into a string, we can set it to something more useful like a complex object. We can set it equal to Pokémon object. So instead of the pokemon=() method being equal to a string, let’s create a Pokemon class and assign an individual pokemon object to the Ash instance pokemon attributes.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0aa9c07377992ef749e8f1887df1d31e/href">https://medium.com/media/0aa9c07377992ef749e8f1887df1d31e/href</a></iframe><figure><img alt="" src="https://cdn-images-1.medium.com/max/493/1*RXMp3a0s1ge-mnI1Koqurw.png" /></figure><p>Just like we were able to set the pokemon attribute equal to the string ‘Pikachu” we can set the attribute equal to an instance of the Pokemon class stored in the pikachu variable.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/522/1*DoDxJjd384_5WImiem3PTQ.png" /></figure><p>Now we can ask for the type.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/586/0*qrRCf2Vp-BQioZ5u" /></figure><p>Now the relationship between Pokemon and Trainer is almost complete. We’ve established the “<strong>belongs to’</strong> relationship. A pokemon has one trainer (in our domain model) so we say a Pokemon <strong>belongs to </strong>Trainer. We established the relationship by giving the Trainer object a setter and getter for Pokemon.</p><p>If we look at the Pokémon flowchart we can see that there are a total of three instances of Pokémon that belong to Ash object. They are connected horizontally because all the elements in the class will have the same attribute types, but the values or specifics of those attributes will be changed depending on the pokemon.</p><p><strong>The “Has-Many” Relationship</strong></p><p>To build the “has-many” functionality in our trainer class and allow it to have many Pokémon, we have to adjust the class a bit.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4b084f3bb4f51c866591df0580ead503/href">https://medium.com/media/4b084f3bb4f51c866591df0580ead503/href</a></iframe><p>We’ve started to build functionality into our Trainer classes to allow it to communicate with the other classes and get many pokemon. How? Look at @pokemons = [] in the initialize method. What is that doing? Every time a new Trainer class is initialized (let’s say our Ash object) the pokemon attribute is an array that is a place to hold many pokemon objects. Think of this as the place that houses where all Ash’s pokémon are. The object part is most important — it’s not just holding a string of a pokemon it’s holding pokemon objects.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a94c302f09d5697d90c25df8c6d24aa8/href">https://medium.com/media/a94c302f09d5697d90c25df8c6d24aa8/href</a></iframe><p>Take a look at the above code, and you can see that we added a trainer attribute to the Pokemon class, which in turn is setter and getter. But it hasn’t been included in the initialize method. Why would we do that? The answer is who chooses when a Pokémon is added? Is it the Pokémon or the Trainer? The Trainer, of course.</p><p>How do we show that with code? We can go to the Trainer class and add a method to do that.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/39216ebb0fea670112365bc277277d66/href">https://medium.com/media/39216ebb0fea670112365bc277277d66/href</a></iframe><p>Let’s focus on the add_pokemon method.</p><p>So what is the pokemon argument here? It’s the pokemon object created from Pokemon class. We created this method that takes in an argument of pokemon so the trainer can decide when they add a Pokémon object to their @pokemons array. In the world of Pokémon, it would be when they catch a Pokémon.</p><p>Okay, we can look at the next line we have</p><p><strong>@pokemons &lt;&lt; pokemon</strong></p><p>As discussed pokemon represents the pokemon object and @pokemon is an array that we decided to store all the pokemon objects. How do the pokemon objects know which player they have a relationship with? Through the next line.</p><p>We have…</p><p><strong>pokemon.trainer = self</strong></p><p><strong>Let’s break this down</strong></p><p>pokémon is the argument we passed with a pokémon object.</p><p>pokémon.trainer is using the trainer =() method setter and getter to assign a value to self.</p><p><strong>What is self?</strong></p><p>Self is the object receiving the method call. If the method is an instance method, self is always the instance that we are working with right now. If the method is a class method, self is going to be the class that the method is acting on.</p><p>Taking this information of what self is back to our example.</p><p><strong>pokemon.trainer = self</strong></p><p>The first question is, where are we? We are in the Trainer class, and we are reading a method we built that is an instance method. We don’t want this method to work for the Trainer class overall, because we want to make sure the particular trainer has access to their pokemon. Furthermore, we are trying to add the pokemon to the object of Trainer called Ash. Therefore, self refers to the Ash object.</p><p>We can take a look at the code tested in a terminal line to see it in action of how the relationship works.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*bfT6MHsDt--AQhJO" /></figure><p>In line 1, we are creating a Trainer objected and assigned it to the Ash variable. This Ash object has the name attribute “Ash” and the trainer level attribute at” 10”.</p><p>In line 2, we are creating a Pokemon object and assigning it to the pikachu variable. This pikachu variable holds the pikachu object, which has the name attribute “Pikachu” and the type attribute “Electric”.</p><p>In line 3, we’re calling the method <strong>add_pokemon. </strong>We are calling <strong>add_pokemon </strong>on a particular instance of a Trainer which is Ash and passing the pikachu object as our argument.</p><p>In line 4, we are checking if it worked, and we can see that the Ash variable with contains Ash object has a pokemon object inside the array which is the pikachu object;</p><p>In lines 5–8, we decided to create two new pokemon objects and named them “charizard” and “bulbasaur” each with their own attributes. In lines 7 and 8 we decided to add each of the objects into the add_pokemon method, and it was successful.</p><p>In lines 9, 10, we can see that Ash has three different pokemon objects in the pokemon attribute which is an array, and in line 10 we can see go deeper to just see the attribute data.</p><h3>What next?</h3><p>Okay, great, looks like the method works! Remember a Pokémon <strong>belong to</strong> a Trainer and a Trainer <strong>has many</strong> Pokémon this relationship was demonstrated. Hope this article helped build your understanding of has-many and belongs-to relationships between two objects in Ruby. Ideally, in the Pokemon world their would more relationships with other Classes in order to truly capture the world of Pokemon.</p><p>If you’d like to see a Pokemon CLI Adventure Game that uses these fundamentals, head here to check out the <a href="https://github.com/EveOfMaly/pokemon_adventure/tree/master">repository</a>. Some key features include the following:</p><ul><li>Ability to catch pokemon and add them to your pokemon list</li><li>Ability to see a list of caught pokemon</li><li>Display Bag</li><li>See current amount of pokedollars</li><li>Shop — V1 — plan to add fully functioning shop to future versions</li><li>Log Out — keeps your save file</li><li>Start Battle — V1 — — plan to add fully functioning battle system to future versions.</li></ul><h3>Don’t forget to give a 👏 if you enjoyed the read!</h3><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=74a67f28a040" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building Obie.ai for Stride]]></title>
            <link>https://medium.com/tasytt-inc/building-obie-ai-for-stride-3f63da002e53?source=rss-8b6384e87432------2</link>
            <guid isPermaLink="false">https://medium.com/p/3f63da002e53</guid>
            <category><![CDATA[collaboration]]></category>
            <category><![CDATA[developer]]></category>
            <category><![CDATA[enterprise-chatbot]]></category>
            <category><![CDATA[atlassian]]></category>
            <category><![CDATA[productivity]]></category>
            <dc:creator><![CDATA[John Kyeremeh]]></dc:creator>
            <pubDate>Tue, 27 Feb 2018 21:47:21 GMT</pubDate>
            <atom:updated>2018-02-27T21:47:21.091Z</atom:updated>
            <content:encoded><![CDATA[<p>How we connect knowledge to your fingertips in Stride</p><h3>How we connect knowledge to your fingertips in Stride</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ireTPmcesD2z_DWeaXsT2A.jpeg" /></figure><p>Whether you work in a small team or a larger enterprise juggling and finding the right internal knowledge when you need it is no easy task. And for teams that rely heavily on messaging (which most organizations do), it’s especially easy to allow conversational knowledge to not be turned into institutional knowledge. These days it’s all too common to have business units put into isolated groups that rarely talk, share information, or collaborate. When specific knowledge does need to be found it’s hard to search for the information, know if the information is up-to-date, or worse there can be too much information to sort through. Information just lives in too many places. We created a bot in Stride to tackle this.</p><p>If you are thinking of bringing your bot from another platform to Stride, here are some lessons we learned launching our app and how we solved key problems. We’ll cover why we chose to use particular commands, give an architectural overview of the application, and walk through considerations we took when building <a href="http://obie.ai/">Obie</a> for Stride.</p><h3>First, some context</h3><p>Messaging does a great job of keeping communication in one place. It makes for a great archive of information. We all know how to search; it’s pretty simple. You type in what you are looking to find. The problem? Getting information from the deepest archives is a challenge.</p><p>For example, looking for a file you accessed a few weeks ago (noise) while only remembering the topic, a few queries, and a bit of context on the content (signal) but not the file name can be a frustrating experience. You have a good idea of what to look for, but there are a lot of places the file can exist and lots of files with similar topics, queries, and context. How can we impact the signal, and reduce the noise?</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qAXdOJS7rpLsoVwSxgkCqg.png" /></figure><p>At <a href="http://www.obie.com/">Obie.ai</a>, we tackle this signal and noise issue using messaging, behaviour-based machine learning, and natural language processing to help teams share and access knowledge organization-wide: the bigger the company, the harder the challenge exists of accessing and sharing knowledge. With every search, teams can be more focused and informed with fewer interruptions. Our goal is to ensure employees can get access to relevant knowledge at their fingertips. Whether you have an intranet, Google Drive, GitHub, Confluence, or other Atlassian tools like Trello, knowledge is dispersed and siloed across the organization, making some information inaccessible. Finding information should be an easy process. A defined single source of truth to search for knowledge streamlines the search process for both the employees and organizations looking to make information easier to find so that you can get more done.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*KYthC7UGpgQzGTOz4nM-Sw.png" /><figcaption>Obie in Stride fetching a resource</figcaption></figure><p>We were lucky to have heard from many teams, developers and product managers who use a wide range of productivity, developer, and project management tools about common pitfalls: finding information across sources within an organization can create a virtual firehose of information. People didn’t want more knowledge sources. We needed to figure out how to continually reduce the noise so that people can find what is relevant, quickly.</p><p>Our journey building bots on messaging platforms began in 2016. As a team who has been tackling knowledge management for some time now, we feel that messaging has afforded us unique opportunities that we’ve never been able to tackle.</p><p>While building Obie from a prototype to a fully functioning Stride app, we learned some tips and tricks that might be useful for those bot developers hoping to transition their bot to Stride or those looking to build something new. Here are a few takeaways from our efforts to create a valuable experience:</p><h3><strong>1. If you’re building a bot for the first time, try not to bite off too much</strong></h3><p>After being in the bot ecosystem for some time now, we found that the most useful bots typically provide easy ways to get information or collect information using the conversational interface and other interfaces available to them.</p><p>We knew that we had to build a quick prototype with Obie’s knowledge retrieval functionality front and center. The prototype of our Stride app was going to be very simple, but still valuable.</p><p>In addition to the send/receive messaging endpoints, it involved leveraging the following Stride APIs:</p><blockquote><strong><em>User Details:</em> </strong><em>Returns useful information about a given user like their real name, email, and photo.</em></blockquote><h4><strong><em>Usage Example</em></strong></h4><pre>getUser: (cloudId, userId, cb) =&gt; {<br>     auth.getToken((token) =&gt; {<br>         request({<br>         url:       `https://api.atlassian.com/scim/site/${cloudId}/Users/${userId}`,<br>         method: &#39;GET&#39;<br>         headers: {<br>            &#39;Authorization&#39;: &#39;Bearer &#39; + token<br>         }<br>      }, (err, httpRsp, body) =&gt; {<br>         if (cb) {<br>           cb(JSON.parse(body));<br>         }<br>       })<br>    });<br>}</pre><blockquote><strong><em>Conversation rosters: </em></strong><em>Returns a list of user Ids for users in the given conversation.</em></blockquote><h4><strong>Usage Example</strong></h4><pre>getConversationRoster:(cloudId, conversationId, cb) =&gt;{<br>          auth.getToken((token) =&gt; {<br>                  request({<br>                          url:<br>`https://api.atlassian.com/site/${cloudId}/conversation/${conversationId}/roster`,<br>                          method: ‘GET’,<br>                          headers: {<br>                              ‘Authorization’: ‘Bearer ‘ + token<br>                         }<br>                  }, (err, httpRsp, body) =&gt; {<br>                           if (cb) {<br>                                   cb(JSON.parse(body));<br>                            }<br>                 });<br>           });</pre><pre>}</pre><p>We developed the Alpha in about a week at StrideCon. StrideCon is more or less a hackathon week at Mountain Winery in Saratoga, CA, attended by Stride developers and designers. This experience was a unique and timely opportunity that gave us the resources to move quickly. We had entertained talks internally about working within new APIs and we were interested in understanding what it was like to work within the Stride API. This opportunity helped us understand what it would take to bring Obie from other messaging apps into Stride.We tested it and demoed Obie at StrideCom.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6YucsDoeLR4IbksmJc_cSQ.png" /><figcaption>View from StrideCon in Mountain Winery Saratoga, CA</figcaption></figure><p>With the help of the Atlassian designers and developers we created a solid proof of concept that helped skyrocket our understanding of the Stride ecosystem. After this experience, we decided to focus on how we were going to translate more of our core product experience into Stride past the Alpha.</p><h3>2. Communicate early to your users what your bot does</h3><p>There should be some information that explains the value of your bot (what it can do) communicated early. You’re going to get users installing just to play around, so it’s a good idea to demonstrate or talk about the value very early on. This is especially important if you want users to invest the time in going through a lengthy onboarding process.</p><p>We focused heavily on educating users through an onboarding process where we could be as specific as possible so new users understand what the bot can or can’t do. After a design review with the Atlassian team, we made several iterations to the onboarding to ensure we communicated our value proposition much earlier than we initially intended.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*B8LD2Ph-fzYO49Bj-JQ5cw.png" /></figure><h3>3. Make the first impression count</h3><p>We rely heavily on messaging to introduce users to what Obie can do and we get a sense of users sentiment and first impression — when they are happy and when they are frustrated — using <a href="https://www.dashbot.io/">Dashbot</a>, a bot analytics platform that enables developers to measure user engagement, and <a href="https://amplitude.com/">Amplitude</a>, which allows us to track the web experience of the user experience in addition to the bot experience. We focus extensively on user experience — we measure every click, question, and user reply to make sure the experience with Obie is better than nudging, asking a peer, or going into the knowledge sources directly.</p><p>A neat endpoint we use unique to Stride is the built-in configuration status for apps. We make it mandatory for users to complete onboarding/configuration before using Obie. While Obie is awaiting configuration, there is a status indicator beside his app icon in the side toolbar so that the installer is aware that configuration is required before proceeding to use the app fully.</p><p>To do this, we use:</p><blockquote><strong><em>Conversation Configuration State: </em></strong><em>Updates a given conversation’s configuration state, where configured is either “true” or “false”.</em></blockquote><h4><strong>Usage Example</strong></h4><pre>updateConversationConfig: (cloudId, conversationId, status, cb) =&gt; {<br>          auth.getToken((token) =&gt; {<br>          request({url: ‘https://api.atlassian.com/app/module/chat/conversation/chat:configuration/obie-config/state&#39;,<br>          method: ‘POST’,<br>          headers: {<br>               ‘Authorization’: ‘Bearer ‘ + token,<br>               ‘Content-Type’: ‘application/json’<br>           },<br>           json: {<br>                 configured: status,<br>                 context: {<br>                          cloudId: cloudId,<br>                          conversationId: conversationId<br>                  }<br>             }<br>           }, (err, httpRsp, body) =&gt; {if (cb) {<br>                  cb();}<br>            })<br>            });<br>}</pre><p>This configuration status is important for us since in order to have a good experience, users must first configure Obie within their environment. We’ve found that onboarding with Obie is crucial for success; by guiding the user through connecting an integration and performing their first search, they get the feel of how Obie works. Once the user has completed onboarding we unlock Obie for regular use.</p><h3>4. <strong>Sidebars and Cards: Take advantage of new design challenges for unique opportunities</strong></h3><p>It’s important to think of the type of information you are sending to Stride. Stride has a numerous amount of opportunities to allow developers to display information within its environment. We came up with a unique way to interact with Obie because of what Stride offered.</p><h4><strong>Stride Sidebar &amp; Cards</strong></h4><p><a href="https://developer.atlassian.com/cloud/stride/learning/glances-sidebars/">Stride Sidebars</a> provide a free for all in terms of design and development. Apps can display custom HTML hosted by your app in the right sidebar, like a list of meetings, relevant documents, or open tasks, to displaying contextual information relevant to the conversation.</p><p>We found it useful to display documents related to the search for our particular use case. One thing we took into consideration while embracing the freedom HTML provides was to ensure there is a consistent user experience with Obie and Stride. It’s difficult to create a consistent user experience without guidelines so we used Stride <a href="https://atlassian.design/">design guidelines</a> to create the consistent user experience the user audience would understand.</p><p>We found it beneficial to leverage <a href="https://developer.atlassian.com/cloud/stride/learning/sending-cards/">Stride App Cards</a>. App cards offer information at-a-glance and leverage a wide range of design options. When a user asks Obie a question, instead of showing a list of results within the conversation window, we leveraged the metadata and put this information into an App Card . This user experience ended up being quite favorable even though it wasn’t an experience we were used to. The Sidebar allowed us to avoid making the conversation too crowded by displaying only the top result in the conversation window, and then the rest of the results in the Sidebar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Yg-CTPiR-4812EWUunmitQ.png" /></figure><p><strong>Related Guides</strong></p><ul><li><a href="https://developer.atlassian.com/cloud/stride/learning/glances-sidebars/"><strong>Glances and sidebars</strong></a></li><li><a href="https://developer.atlassian.com/cloud/stride/learning/adding-sidebars"><strong>Adding sidebars</strong></a></li><li><a href="https://developer.atlassian.com/cloud/stride/learning/sidebar-style-guide"><strong>Sidebar style guide</strong></a></li><li><a href="https://developer.atlassian.com/cloud/stride/learning/sending-cards/"><strong>Sending cards</strong></a></li><li><a href="https://developer.atlassian.com/cloud/stride/apis/document/nodes/applicationCard/"><strong>Node — Application cards</strong></a></li><li><a href="https://developer.atlassian.com/cloud/stride/learning/sidebar-style-guide"><strong>Sidebar style guide</strong></a></li></ul><h3>Takeaways</h3><p>Obie integrated into Stride turns Stride into an intelligent source of truth, where you can keep your knowledge up-to-date and access knowledge wherever it lives. In Stride, you can surface relevant information and see how up-to-date information is. Through our focus on listening to our users, relentlessly pursuing a favorable user experience, and making data-driven decisions, we’ve learned that each encounter with a bot builds trust and your goal as you develop your bot is to build a trusted coworker.</p><p>We’ve only scratched the surface of the <a href="https://developer.atlassian.com/cloud/stride/rest/">Stride API</a>, but hopefully you’re now sufficiently excited to build something awesome! Even if your mission and product aren’t tied to the things we aim to solve, hopefully our learnings from this process will help inform your decisions about specific aspects of your bot and save you time as you build it in Stride. We’d really love to see how you use it, and if you do create a great bot in Stride (or move your bot over to Stride), don’t forget to let us know on <a href="https://twitter.com/AskObie">Twitter</a>. If you have any specific questions about the journey feel free to reach out and we’ll be sure to help!</p><p><em>Written by John Kyeremeh, Head of Growth, &amp; edited by the Obie.ai team.</em></p><h3>Think other people would benefit from this article? Click the clap to help them find it ❤</h3><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3f63da002e53" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tasytt-inc/building-obie-ai-for-stride-3f63da002e53">Building Obie.ai for Stride</a> was originally published in <a href="https://medium.com/tasytt-inc">Obie.ai</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Revenue is Optional: The Benefits of Making Your Middle Sales Reps More Productive]]></title>
            <link>https://medium.com/tasytt-inc/revenue-is-optional-the-benefits-of-making-your-middle-sales-reps-more-productive-5b28076c792b?source=rss-8b6384e87432------2</link>
            <guid isPermaLink="false">https://medium.com/p/5b28076c792b</guid>
            <category><![CDATA[business]]></category>
            <category><![CDATA[productivity]]></category>
            <category><![CDATA[chatbots]]></category>
            <category><![CDATA[entrepreneurship]]></category>
            <category><![CDATA[sales]]></category>
            <dc:creator><![CDATA[John Kyeremeh]]></dc:creator>
            <pubDate>Mon, 13 Mar 2017 16:31:47 GMT</pubDate>
            <atom:updated>2017-03-16T20:53:39.534Z</atom:updated>
            <content:encoded><![CDATA[<p><strong>What makes an “A” rep different than a “B” rep and how do we ensure everyone has the resources to contribute consistently and efficiently to the team?</strong></p><p>The reasons sales teams fail at meeting their quota are all influenced by productivity — this article provides you with insights on how sales reps learn and retain information with the goal of understanding what a 10% increase in productivity has on a sales team.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/940/1*2ZRenm1Krhzp2EIXxSDLdg.png" /></figure><h3>Designed To Learn As Fast As Possible</h3><p>The other day I came across a post by Tim Gruffub, the author of the popular blog <a href="https://25iq.com/2017/02/10/a-dozen-lessons-on-growth/">25iq.com</a>, on a dozen lessons on growth. He made a lot of great points, but I couldn’t help but identify strongly with one passage in particular:</p><blockquote>“If you can run more experiments than the next guy, if you can be hungry for growth, if you can fight and die for every extra user and you stay up late at night to get those extra users, to run those experiments, to get the data, and <strong>do it over and over and over again, you will grow faster.</strong>” — Alex Schultz.</blockquote><p>I bolded the words, “<strong>do it over and over and over again, you will grow faster</strong>”, for a reason. This resonated with me deeply, I immediately wrote in my notebook in red “<strong><em>Coffee is for closers.”</em></strong></p><p>The quote from the movie Glengarry Glen Ross with Alec Baldwin is perhaps the most referenced sales movie in the last few years. It’s easy to get swept up in the narrative of clear winners and losers when it comes to sales <strong>but what if the coffee was available for the whole team?</strong> Companies that focus on improving sales productivity as a team while enhancing individual performance and learnings will dominate the battle for business.</p><p>I think this summarizes things so well. It might sound crazy because I’ve never met a sales team that says they don’t want all their sales reps to hit quota. Yet, many teams don’t do the things required to get the whole team to succeed. It reminds me a lot of a basketball team where as a team you want everyone to be at their best; you want everyone to play at 100% despite physical pain or fatigue. Each player has the desire, and everyone is equally prepared, but like in today’s basketball teams, usually only one person in the team carries the team and is willing to do the hard work — the results show.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ao9mJg7ZOjM8QWJi0zgE2g.jpeg" /><figcaption>Usually only one person in the team carries the team and is willing to do the hard work</figcaption></figure><p><strong>Despite the intention, by not focusing on the team, the pipeline and revenue is impacted.</strong> Sales people who regularly kill their quota have done the work; they are so good despite changes in the market or competition — they understand what works and what doesn’t. Indeed, at times the numbers are so much in their favour that the company — and even the rest of the team in general — may not fully understand what behaviors are making this impact. They are the winners, and between them and the rest of the sales team, the question of how you help other reps learn to perform similarly to these Top Performers remains.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/547/1*FQ1jfkQbJcaPNB0YeRS-aQ.png" /><figcaption>What are your Top Performing reps doing differently than the rest?</figcaption></figure><p><strong>Let’s get very basic for a second: sales reps learn and retain information differently.</strong> What makes an “A” rep different than a “B” rep and how do we ensure everyone has the resources to win? A way to measure this is by productivity. A good productivity increase is one that generates a lot of business, allowing a team that is currently moving at 50 MPH to move further towards its potential of 100 MPH. Of course, any increase in team productivity would also mean individuals are performing better. Moreover, it’s important to dive deeper into how sales reps learn and access information by focusing on sales behaviors.</p><h3>Dials. Emails. Demos. Repeat.</h3><p>For years buyers relied on sales people to communicate with them using three activities to stay informed</p><blockquote>1) Dialing the phone</blockquote><blockquote>2) Having meeting/demonstrations</blockquote><blockquote>3) Sending Emails</blockquote><p><strong>While these activities are still highly effective means to communicate with potential customers in the B2B space, it’s important to understand that like any channel of distribution, channel saturation eventually happens, and the impact of these three activities has dropped today as the buyer’s journey changed.</strong> Looking at the buyer’s journey in more detail, CEB found out that <a href="https://www.cebglobal.com/marketing-communications/digital-evolution.html">57%</a> of the buyer’s journey is complete before the buyer talks to a sales rep. This statistic tells sales teams that they must ensure that the customer understands how a solution will help them do their job better with insights that go beyond product knowledge.</p><h3>Add Value And Provide Deep Insights</h3><p>Think of how many sales emails you get daily from sales professionals with similar messaging, not to mention the closing email, ‘right person’ email, ‘animal’ chasing you email, and ‘break-up’ email. <strong>Which of these emails, calls, or presentations did you <em>actually</em> take the time to listen to and what about them made you respond?</strong> If your sales team is not maximizing value for the buyers, according to SAVA, <a href="https://www.slideshare.net/SAVO_Group/techniques-of-social-selling-just-do-it-sales-for-life">74%</a> of potential customers will choose the one that is first to add value. Consumers measure value added by evaluating the reps:</p><ul><li><strong>Market Knowledge </strong>— Problem the customer is looking to find a solution for.</li><li><strong>Product Knowledge </strong>— How your solution solves the customer’s problem.</li><li><strong>Sales Knowledge</strong> — How you present a solution to the problem.</li></ul><p>Indeed, when considering how sales reps learn it’s important to ensure the rep can develop the skills to convey these three types of knowledge.</p><h3>Focus On Using Your Time Wisely</h3><p>Sales reps usually work in teams with a leaderboard approach to motivate and amplify winning behavior where there is a clear 1st, 2nd, 3rd, and the rest.</p><p><strong><em>Here are two hypothetical 60-person sales teams.</em></strong></p><p><strong>Company A</strong></p><ul><li><em>Has periodic monthly boot camps (5 new reps onboarded monthly). Onboarding takes about 5–7 weeks. During this time, reps are strictly doing onboarding on the product, competitors, and company culture. The Sales Manager has said that the current onboarding process is not scalable to promote consistent and efficient reps. The organization wants to promote ongoing engagement and professional development to ensure reps stay consistent as reps who were top performers in the past are no longer top performers.</em></li></ul><h4>Company B</h4><ul><li><em>Is currently hiring an additional 15 reps who will focus on new business. The organization as a whole has a built-in LMS with existing content and a new sales training program. The Sales Manager has no current way to ensure the development of existing reps while also promoting the development of the 15 new reps.</em></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/588/1*vSeeM8T6WS8JKRfuYrbnTQ.png" /><figcaption>Comparison of top, average, and low performers</figcaption></figure><p><strong>The data sets contain not only average revenue, but also achieved revenue for a 60 person sales team each with a $2M quota.</strong> It’s common for most sales organizations to perform with averages representing the 20/60/20 rule. What this means is that the top 20% will be the top performers that often meet or exceed quota, the middle average represents the 60% percent that is often on or usually just short of meeting quota, and the bottom 20% are typically far below quota.</p><p>Let’s say Company A and B each had goals this quarter to contribute the most to revenue.<strong> The question most managers would ask is, “Where should I spend my time to make my job easier?</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*85DmYsFV9nzAirKqGGyOyg.png" /><figcaption>Improving the performance of the middle delivers 95.65% more revenue than top performers performance</figcaption></figure><p><strong>We can answer this by considering the above example. </strong>A performance improvement of 5% by the average-middle performers can be close to double that compared to the same increase for top performers. Equally important, even a 10 % increase in low performers productivity doesn’t even come close to the business impact of improving the middle performers’ productivity by 5%.</p><p><strong>In other words, improving the middle contributes to 95.65% more revenue. </strong>This significance is compelling, even with ten sales reps, let alone 10,000 sales reps; managers should focus on delivering solutions to enhance the middle productivity. The deeper you dive into the data, the more you realize that improving the middle drives the most impact on productivity.</p><p><strong>What’s the best way to do so?</strong> Looking at the two companies in more detail, it’s clear having the right knowledge is an important goal for both. Each month Company A spends a significant portion of a new reps time (5–7 weeks) on activities designed solely around knowledge delivery. Company B has the LMS and training tools ready for the 15 new sales to understand in terms of knowledge delivery. What this digestion typically looks like is a rep is coached on great storytelling, effectively handling questions, competitor information, and managing the sales process efficiently and consistently. The LMS houses all these resources and the hope is that the reps regularly use the system. <strong>What’s interesting to know is according to </strong><a href="https://www.hr.com/en/topleaders/all_articles/why-learning-retention-is-key-to-employee-training_ip1gcieq.html"><strong>HR.com</strong></a><strong> 70% of employee training is forgotten within five days.</strong> This means that teams must ensure that their sales reps can apply what they learn. It’s still necessary to coach at this knowledge introduction stage, but one key thing to keep in mind is that research has suggested that individuals <strong>learn 70% of their knowledge from on-the-job- experience, 20% from interacting with others, and 10% from studying and reading.</strong></p><p><strong>Company A and B have both invested heavily in sales enablement tools that hold knowledge.</strong> However, they will be better off if they can shift focus beyond learning delivery (Bootcamp experience/LMS knowledge) and instead improve how sales reps access the right pieces of knowledge to on the job quickly. <a href="https://www.nap.edu/read/9853/chapter/5">The National Academies Press</a> has shown that a key difference between an expert and and a novice is the experiences on which the expert has to draw on.</p><p><strong>Senior sales reps win because they remember thousands of situations and plays more quickly and strategically because of their experience.</strong> New reps rely more on abstract rules— what to say to objections when the customer has a rebuttal, how to close the sale, etc. Both companies would benefit from finding a solution that reinforces moving the ‘abstract’ knowledge to strategic knowledge in a way that gathers knowledge without disrupting their workflow.</p><p><strong>When your sales enablement strategy lacks the ability to maximize learning while on the job deals are lost.</strong> Sales teams should invest their time in solutions that promote this active learning process. How do your reps handle questions that they don’t know how to answer quickly? It shouldn’t involve shoulder tapping a peer. Having the resource or answer when you need it quickly is necessary for deals.</p><p><strong>There’s good news and bad news.</strong> The bad news is that according to a study done by the<a href="https://www.salesforce.com/blog/2015/09/how-to-get-sales-to-use-your-marketing-content.html"> CMO Council</a>, sales reps waste over 40% of their time every day trying to find the resources and content needed to do their job. It’s also <a href="http://www.eyesonsales.com/content/article/to_increase_sales_productivity_in_2016_focus_on_time_effectiveness/">common</a> sales knowledge that every 5% increase in selling time can amount to a 20% increase in revenue. Having a mechanism in place where your reps can proactively find the right content for each selling situation is important. When this mechanism works quickly, a rep is able to have answers to a question or find the right resource almost instantaneous they are more productive and learn on the floor. Now imagine if this process was automated within Slack, where the team lives daily, directly into reps workflows, so they don’t have to waste 40% of their time every day looking for the right resource. <strong>Sales Managers can expect to recognize their investment in new hires sooner, making it easier to focus efforts on coaching the middle performers.</strong></p><h4><a href="http://bit.ly/obiedotai"><strong>Click here to learn how Obie helps you access the knowledge and assets you need to make faster decisions, without leaving Slack. So you can actually get things done.</strong></a></h4><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5b28076c792b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tasytt-inc/revenue-is-optional-the-benefits-of-making-your-middle-sales-reps-more-productive-5b28076c792b">Revenue is Optional: The Benefits of Making Your Middle Sales Reps More Productive</a> was originally published in <a href="https://medium.com/tasytt-inc">Obie.ai</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>