<?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 Rick Mak on Medium]]></title>
        <description><![CDATA[Stories by Rick Mak on Medium]]></description>
        <link>https://medium.com/@rickmak?source=rss-907d507d902c------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*ReiKiJGhyLOOwHoDwtIEPQ.jpeg</url>
            <title>Stories by Rick Mak on Medium</title>
            <link>https://medium.com/@rickmak?source=rss-907d507d902c------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 13:58:45 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@rickmak/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[Naming 101]]></title>
            <link>https://medium.com/oursky-team/naming-101-4b0b498f5161?source=rss-907d507d902c------2</link>
            <guid isPermaLink="false">https://medium.com/p/4b0b498f5161</guid>
            <category><![CDATA[naming]]></category>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[startup]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Rick Mak]]></dc:creator>
            <pubDate>Wed, 25 Apr 2018 08:14:12 GMT</pubDate>
            <atom:updated>2018-04-25T08:14:12.996Z</atom:updated>
            <content:encoded><![CDATA[<h4>The most obvious rules. Duh.</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*C4bjhstC_3Fka9QzLB7Zbw.jpeg" /></figure><blockquote>There are only two hard things in Computer Science: cache invalidation and naming things.</blockquote><blockquote>— Phil Karlton</blockquote><p>On any given day, you will probably find my colleagues and me in the office, deep in discussion on how to best name for a certain method or variable. Maybe around evening, we’ll finally agree to disagree and just make a judgement call because, hey, we still need to ship our code by tomorrow.<br> <br>Finding a good name isn’t a trade off between project management deadlines and programmers’ preferences. Naming isn’t just about technical conventions. Naming serves the practical purpose of handing over maintainable high level code to other development teams (i.e. for our clients) and quality APIs for our <a href="https://skygear.io/">open-source serverless platform</a>. A decade ago, before technical advances like WiFi, mobile, and cloud computing, our serverless platform was only a dream. But some things don’t change after a decade — things like how you choose a good name. So I’m just rehashing what we developers have known since Java, C, or even BASIC.</p><h3>Symbols vs Names</h3><p>Naming things in computer science is about giving a name to a concept. The concept can be common software design pattern like Singleton and Factory, or it can be a custom logic that we write code for. By giving a name to a concept, we make the concept concrete by defining the assumptions, the behavior, and the responsibility of the concept. A concept with a name is contained and no longer (as) vague.</p><p>Well, in theory, names aren’t needed — <a href="https://temochka.com/blog/posts/2017/06/28/the-language-of-programming.html">a symbol can also denote a concept</a>. For example, in mathematics “+” (plus) or “=” (equal) are so well understood that giving them other names would just complicate things. If you love expressing things in symbols, maybe it’s time to get a pure maths degree. Programming is more than mathematics. <em>How are we going to </em><a href="http://wiki.c2.com/?BrainfuckLanguage"><em>program using only symbols</em></a><em> without looking up a textbook of documentation?</em></p><blockquote>In programming, rolling your eyes is better than scratching your head.</blockquote><p>That’s why naming is important: it helps to communicate a concept to another person (which can also mean your future self). When writing code, we want to focus on the logic without constantly breaking up our train of thought by looking up the documentation. During discussion with other developers, for example team members who rotate into a project, we want to refer to concepts without explaining its behavior all over again.</p><p>Therefore, a good name is a name that helps us communicate effectively.</p><ul><li>Obvious — the concept is apparent just by reading the name</li><li>Unambiguous — the name is only associated with one concept, or that it is obvious the name is associated with a particular concept</li><li>Accurate — the name is correct in describing the concept</li><li>Consistent — the name follows certain convention or uses the same vocabulary to describe similar concepts</li></ul><h3>Follow Conventions</h3><p>Let’s say we have a function called getAccessToken() . What could it do? Almost anything, like...<br> <br> ... returning an access token<br> <br> ... fetching the access token from underlying storage to get access token<br> <br> ... check with the server if the access token is still valid, and log the user out if the session timed out<br> <br> ... <a href="https://blogs.msdn.microsoft.com/oldnewthing/20140627-00">result in time travel</a><br> <br>How do we know? The documentation should cover the implementation of the function, but it is not a good idea to constantly rely on documentation to deliver the meaning of the concept. It is one thing for a concept to be difficult to remember if we were to use a symbol, but it is very bad if the name doesn’t accurately convey the meaning of the function.<br> <br>Convention is important here. Convention tells you what the get, or lack of get, actually means. If this function is part of a Java program, get tells you this function is a getter and should have no side effect. This convention is prevalent even outside Java. <a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Conventions/Conventions.html#//apple_ref/doc/uid/TP40011210-CH10-SW8">Convention in some languages</a> discourage the use of get in name, but a function can still be considered a getter and should have no side effect.</p><p>Being consistent means that if you use the name get in your function, you should implement the function with no side effect, which is what most developers expect when they call your function. They also expect your function to return quickly because they expect the function to simply return an internal state.</p><h3>Don’t Use the Same Name</h3><p>A good name isn’t good if it only factors in one or two principles in naming. For example, when we designed our data model for <a href="https://github.com/SkygearIO/chat">our serverless Chat SDK</a>, we called our model for storing information related to a conversation…obviously, Conversation. Conversation is a good name, because it is obvious that this model encapsulated information about a conversation. Since this is most commonly used as a noun, there isn&#39;t much room for mistaking a thing for an action.</p><p>But as we were writing the code for our API, we needed to name another model that stores <em>user-specific</em> information of a conversation. It would be used, for example, to show a message unread count to the user for each conversation they’re a participant in. In database schema design parlance, this model is an associative entity storing the relationship between user and conversation, with association relation attribute like unread count. The convention is to name this model UserConversation (or user_conversation as a table name).<br> <br>Independently, both Conversation and UserConversation are good names. However when both models are exposed in the API of the Chat SDK, two good names equals one bad combination. Our most frequently asked question by Chat SDK users was: What is the difference between a Conversation and a UserConversation?</p><h3>Sometimes You Need to Break Grammar Rules</h3><p>Conventions often say our name should be grammatically correct, but we sometimes need to break the grammatical rules in order to make our code readable and obvious.</p><pre>var somethings []Something // somethings? this word doesn&#39;t exist!</pre><p>No one knows what “Something” is, but one thing is painfully obvious: “somethings” is a collection of values with the type “Something”.<br> <br>Code should be obvious, even if we need to break some grammar rules to get there. If the grammar rules get in the way when we try to make something as readable as possible, we will always strive for obviousness rather than correct grammar rules.<br> <br>We can also call the variable “arrayOfSomething”, but this will not be as readable as simply “somethings”. I am not saying that “arrayOfSomething” is bad naming. It is a good choice to make the type of the collection obvious.<br> <br>“Settings” is another example we encountered in one of our client projects. In English, we always use the word “Settings” to refer to configurations while the word “Setting” refers to a situation or circumstance. However, in programming convention, we add “-s” or “-es” to represent multiple items of something. If we call a unit of configuration as “Settings”, how should we call an array of such “Settings”? “Settingss” is just too odd and will not pass our pull request review.<br> <br> That’s why we code like this:</p><pre>type Server struct {<br>    Settings []Setting // an array of Setting<br>}</pre><p>That’s all I can think of for now. Give me a drink, and my memory will come back with more examples.<em> </em>In fact, some of our best exchanges and breakthrough ideas have come from ad hoc tasting sessions at our DIY whiskey corner.</p><blockquote><em>The great thing about having fresh graduates working with developers who have 10+ years of experience is that we are constantly reminded about how readable our code is.</em></blockquote><p>I’d also like to thank my Skygear.io colleague, <a href="https://medium.com/u/cdd8a0d1e292">cheungpat</a>, for his input and helping me edit this piece.</p><p><em>Building an app? Our free </em><a href="https://oursky.com/products/"><em>developer tools</em></a><em> and </em><a href="http://skygear.io/"><em>open source backend</em></a><em> will make your job easier.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=4b0b498f5161" width="1" height="1" alt=""><hr><p><a href="https://medium.com/oursky-team/naming-101-4b0b498f5161">Naming 101</a> was originally published in <a href="https://medium.com/oursky-team">Oursky Team</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to handle unknowns and make assumptions when designing a cloud database]]></title>
            <link>https://medium.com/free-code-camp/how-to-handle-unknowns-and-make-assumptions-when-designing-a-cloud-database-df002068a83b?source=rss-907d507d902c------2</link>
            <guid isPermaLink="false">https://medium.com/p/df002068a83b</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[cloud-computing]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[database]]></category>
            <category><![CDATA[tech]]></category>
            <dc:creator><![CDATA[Rick Mak]]></dc:creator>
            <pubDate>Thu, 21 Sep 2017 16:21:47 GMT</pubDate>
            <atom:updated>2017-09-21T16:21:47.547Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YbuEATHnaNlM4yPP5qYZzg.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/search/photos/public?photo=if2coegqwZU">Chance Anderson</a> via Unsplash</figcaption></figure><h3>Scenario: Shoebox or social app?</h3><p>Say you’re a developer who wants to build a note taking app. Let’s look at one feature detail with huge implications on your back-end. To write a note, your app will need to be able to save the data.</p><p>Saving a record to a database is straight forward. The key questions are:</p><ul><li>Who will need to access that record?</li><li>Will it only be your user, or will your user share it with others?</li><li>Will your product be shoe-box app or a social app?</li></ul><p>If you intend for the notes to be private to the author, you may conclude that you are making a shoe-box app. This means all data goes to a private DB (database).</p><p>If you intend for your app to share notes with others, you may conclude it should be a public DB.</p><p>But will you know which it is before you start?</p><p>And what will you do if you need to change your product as you go? Public DB and private DB isn’t the first thing most developers think about when they’re building an app. We encountered these question when we were building our back-end product for our developers, <a href="https://skygear.io/">Skygear</a>.</p><p>Because of our experience in building apps for clients, we<strong> assumed </strong>there was a right choice of database. And that our user would know how to choose.</p><p>How do you build a back-end for developers who aren’t sure of their products needs yet?<br> Or for those who want to keep their options open in the future?</p><p>As the tech lead in the project, I’d like to share with you our decision making process from 2 years ago. I hope it helps future development teams approach unknowns and assumptions.</p><h3>Why did we start thinking about private vs public DBs?</h3><p>Many apps require a back-end to store and query user data. The back-end is a lot of hard work to build and, let’s face it — not so enjoyable to create. <a href="https://skygear.io/">Skygear</a> is our open-source serverless back-end. It helps address common development features for mobile and web apps.</p><p>The feature I’ll talk about is our Cloud DB, where you store and query user data. When we started to design Cloud DB, we asked ourselves how different apps store and query user data.</p><p>We looked at our company’s mobile apps <a href="https://oursky.com/works/">portfolio</a> for inspiration. Our company does everything from consumer apps to e-commerce apps. So we grouped them into “shoe-box” and “social” apps.</p><p>Shoe-box apps store personal data that the user wants to keep private. For example, our side project <a href="https://itunes.apple.com/app/spentable-track-your-daily-expense-and-savings/id500630565?mt=8">Spentable</a> helps a user track of their daily spending. Data stored in the app is meant to be private, in a shoe-box.</p><p>But, there is stuff that we want to share publicly or with friends. That also means the user needs to be in control of who can read their data. These two kinds of apps present a challenge in how we designed Skygear’s Cloud DB. We wanted to make storing data in Cloud DB as easy as possible. For shoe-box apps, all the developers need is a database where each user can only see the data that they are putting in. Yet, in social apps, developers need features such as ACL (access control). How can we make things simple for developers of both kinds of apps?</p><h3>Having our cake and eating it too</h3><p>We decided to solve this problem by introducing the concept of multiple databases in the <a href="https://docs.skygear.io/guides/cloud-db/basics/ios/">Cloud DB</a>: private DB and public DB. Each user has a private DB to put data in, and that data is only available to the same user. The app also has one public DB that is shared among all users.</p><p>A shoe-box app developer is able to focus on saving and fetching the data without worrying about permissions because data in the private DB is always private.</p><p>But, private DB does not work at all for social apps. Developers for social apps should put data in the public DB because data in social apps are meant to be shared.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/859/1*0HS1xeqA7s-UU79TGYrhEw.png" /></figure><p>Before we added support for <a href="https://docs.skygear.io/guides/cloud-db/acl/ios/">ACL</a>, this simple distinction for public and private data served us(and our users very well. Everything in private DB is truly private while everything is public DB is truly public.</p><p>“Everything is public” is not good enough. Most social apps have use cases that data is only shared among a group of friends.</p><p>ACL is another difficult and interesting topic that should be it’s own article.</p><h3>We couldn’t have the best of both databases</h3><p>Separating the DB into private and public ones was a good idea. We thought they supported the use case for majority of apps.</p><p>But early adopters found our private and public options confusing.</p><p>Our early users gave us invaluable feedback. We also paid attention to the support questions we received. This is what we learned from developer feedback when they used our Cloud DB:</p><ol><li>It’s not obvious to developers what they’re building at first<br>While it may be obvious which kind of app developer made by looking at the product retroactively, it is not obvious from the get-go. Forcing the developer to decide whether they are making a shoe-box or social app at the beginning is difficult, if not impossible.</li><li>Developers just want to get started quickly<br>We want the developers to learn the basics as quickly as possible. Having to learn one more concept to choose which DB to use before they can actually save and retrieve data is too much to ask for new users.</li><li>The decision for public or private DB, once made, isn’t easy to reverse<br>Suppose that a developer started with a shoe-box app idea and they put everything in the private DB. Later they may realize that they should make the app a social one instead. It is not easy to migrate data once they are put into a particular DB.</li><li>Permissions are usually an after thought<br>Data security a priority in our company. But data security is not the first thing that comes to the mind of a developer. Especially when they’re just doing a proof-of-concept prototype. They want to focus on the functionality first, and take care of the security later on.</li></ol><h3>Our takeaways</h3><p>We are always thinking about how we could make our products better. We could do better in terms of software architecture, user documentation and ease-of-use. We sometimes brainstorm what we would do if we could rewind the clock two years to start over. But here is what we would tell our former selves:</p><ol><li>If developers are already familiar with an existing concept, adopt it<br>Most developers are familiar with the concept of a database. It is a container of some sort where developers can save content. They can also retrieve data and support the CRUD (Create, Read, Update, and Delete ) property. <br>Because developers are already familiar with the concept of a database, they would find a single database on Cloud DB straight-forward to use.</li><li>Introduce new concepts when developers are prepared for them<br>This idea is actually an other way of saying that we should make the learning curve as easy as possible. Skygear was a prototype in its own way. We just launched V<a href="https://skygear.io/">1.0</a>!.<br>You never want to make life for your early adopters difficult. Having to learn everything before developers can do anything does not work well from a product perspective. Until developers need to think about data permission, they should not need to know about the difference between a private DB and public DB. We should let our users get started with the common concepts first to familiarize themselves with a new platform.<br>Only after they’re comfortable should we introduce new concepts to provide more options. In this case, there’s no harm for a developer to discover they need ACL so the new concept is a natural next step after they have learned how to use Cloud DB.</li></ol><h3>What we learned</h3><p>When we began working on Skygear two years ago, we wanted to build a kick-ass product with 2–4 of our senior developers. We had ready testers from our own in-house developers, who gave lots of critical feedback. We thought we were using our experience in web and mobile app development to make better decisions on how to design tools for other developers.</p><p>But our experience also created assumptions about what to expect our users to know before using our product.</p><p>The good thing about getting user feedback on Cloud DB as we went was that we learned that our assumptions were incorrect. Our most valuable lesson was the humbling reminder of a basic startup principle. No matter our experience, we often don’t know exactly what we’re building.</p><p>Of course, that doesn’t stop us from trying to build that philosopher’s stone to make lives easier for our fellow developers anyway. As my co-founder, Ben, said one of his most productive days was when he tossed 1000 lines of code away.</p><p>I would like to credit my colleague <a href="https://medium.com/u/cdd8a0d1e292">cheungpat</a> who worked on the Cloud DB with me and helped write this piece.</p><p>My team would love to hear your critical feedback for <a href="https://skygear.io/">Skygear</a>. Also check out our <a href="https://docs.skygear.io/">documentation</a> and <a href="https://github.com/SkygearIO/features">GitHub repos</a> to see how we discuss Skygear features.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=df002068a83b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/free-code-camp/how-to-handle-unknowns-and-make-assumptions-when-designing-a-cloud-database-df002068a83b">How to handle unknowns and make assumptions when designing a cloud database</a> was originally published in <a href="https://medium.com/free-code-camp">We’ve moved to freeCodeCamp.org/news</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Want to make the deployment process less scary? Build ChatOps in Slack.]]></title>
            <link>https://medium.com/free-code-camp/want-to-make-the-deployment-process-less-scary-build-chatops-in-slack-b2accc72e2a9?source=rss-907d507d902c------2</link>
            <guid isPermaLink="false">https://medium.com/p/b2accc72e2a9</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[chatbots]]></category>
            <category><![CDATA[tech]]></category>
            <category><![CDATA[startup]]></category>
            <dc:creator><![CDATA[Rick Mak]]></dc:creator>
            <pubDate>Tue, 12 Sep 2017 05:06:44 GMT</pubDate>
            <atom:updated>2017-09-12T05:07:06.504Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*C-h4AY4jHHPv9AEyND0JWQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@jamomca">Jamison McAndie</a> via Unsplash</figcaption></figure><p>In a company that makes mobile and web products, developers shouldn’t be the only ones who can launch the latest version of an app. You need proper testing beyond getting colleagues to give ad hoc feedback by clicking through the app.<br> <br>At <a href="http://www.oursky.com/">Oursky</a>, our QA built an <a href="https://medium.freecodecamp.org/4-steps-to-build-an-automated-testing-pipeline-with-gitlab-ci-24ccab95535e">automatic testing pipeline</a>. But testing needs to be coordinated and the report needs to go to the relevant people. The QA team needs to know when to test the latest version of the app. The PM needs to check the latest progress. And the designer needs to support and fine-tune the details. While building command line tools is the obvious go-to for developers, we wanted to find a tool that everyone in the company uses. <br> <br><strong>We created our deployment ChatOp on </strong><a href="https://slack.com/"><strong>Slack</strong></a><strong>. Read on to see how you can do it with your chat service. You can automate your deployment, which saves everyone time and reduces coordination errors </strong>(<a href="https://campfirenow.com/">Campfire</a>, <a href="https://www.hipchat.com/">Hipchat</a>, and <a href="https://www.flowdock.com/">Flowdock</a> are also supported). We’ve been using ChatOps in 15+ simultaneous projects within our team.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WuZO04C1uFLulI0ZGm_a3Q.png" /><figcaption>Screenshot of our Slack bots, Chima and Faseng (the names of our resident office cats)</figcaption></figure><p><a href="https://speakerdeck.com/jnewland/chatops-at-github">ChatOps</a> is a great way to make the deployment procedure less complex, less black-boxed, and less scary. <br> <br>I adapted GitHub’s use of ChatOps for our deployment with Slack. GitHub’s open source chatbot (<a href="https://github.com/hubotio/hubot"><em>Hubot</em></a>) does automating deployment, graphing, monitoring, provisioning, tweeting, and many other things. GitHub even created MySQL database back-up jobs so they can do important operations without leaving the chatroom with a set of instructions.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/695/1*fVmXBn-azKd53zoYvKXqoQ.png" /></figure><h3>The big picture of ChatOps deployment</h3><p>ChatOps simplifies deployment with automation: it removes manual coordination errors, and allows everyone in a project to jump in. It also encourages open communication so team members don’t have to interrupt each other for updates or documentation. They can access information whenever they need it.</p><p>So how does it work and how do you set it up?</p><p>This graph shows how deployment interactions would work via <a href="http://www.github.com/">Github</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/649/1*Vu_VmB_cJ0qFIUvYQm2OjA.png" /><figcaption><em>Reference: </em><a href="https://developer.github.com/v3/repos/deployments/"><em>https://developer.github.com/v3/repos/deployments/</em></a></figcaption></figure><p>Our company implemented a similar version using open <a href="https://slack.com/">Slack</a> channels for all our operations. Each project has its own channel. We introduced two Slack botsk, <strong>Chima</strong> and <strong>Faseng</strong>, to assist the deployment process. (<a href="https://www.facebook.com/chima.fasang/">Chima and Faseng</a> are the names of our resident office cats.)<br> <br><strong> The core idea is summarized in this sentence:</strong></p><blockquote><em>Tell </em><strong><em>Chima</em></strong><em>(CEO), to make </em><strong><em>Faseng</em></strong><em>(CTO) deploy.</em></blockquote><figure><img alt="" src="https://cdn-images-1.medium.com/max/648/1*YVd18Txn2-SRXJi8K-UHlg.png" /></figure><h3>Roles of the bots: Creating &amp; executing</h3><p>For each project, we set up respective deployment jobs with Faseng. It’s not only easily to deploy, but deployment notifications make the progress and status of the project clear.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/676/1*r6WJVHOT6BxeCn5hvLFdBg.png" /><figcaption>Screenshot of Chima and Faseng (our Slack bots)</figcaption></figure><h3>Creating the deployment job (chat command bot)</h3><p>Chima is a <a href="https://github.com/github/hubot">github/hubot</a> which helps to understand our commands from Slack. For example chima deploy is a deployment command.<br> <br> We have to configure these settings for each project:</p><ul><li>Specify a deployment provider such as <a href="http://www.fabfile.org/">Fabric</a>, <a href="http://capistranorb.com/">Capistrano</a>, <a href="https://www.heroku.com/">Heroku</a>, or any Ruby Rescue task</li><li>Whether to support auto_merge for the target branch for deployment</li><li>The repository name of the project</li><li>Available environments of the deployment</li><li>Only channel members in the allowed_rooms list can create the deployment</li></ul><p>We put this configuration in the <strong>app.json </strong>file. Below is an example of how you can configure for project-x:</p><pre>{<br>  &quot;project-x&quot;: {<br>    &quot;provider&quot;: &quot;fabric&quot;,<br>    &quot;auto_merge&quot;: false,<br>    &quot;repository&quot;: &quot;oursky/project-x&quot;,<br>    &quot;environments&quot;: [&quot;live&quot;, &quot;edge&quot;],<br>    &quot;allowed_rooms&quot;: [&quot;deployment&quot;]<br>  }<br>}</pre><h3>Executing the deployment job (deployment bot)</h3><p>Faseng is an <a href="https://github.com/atmos/heaven">atmos/heaven</a> program. When it receives GitHub webhooks, it will run deployment jobs as background tasks with Resque. There are several supported ways to create deployment jobs, such as:</p><ul><li><a href="http://www.fabfile.org/">Fabric</a></li><li><a href="http://capistranorb.com/">Capistrano</a></li><li><a href="https://www.heroku.com/">Heroku</a></li><li>Any Ruby rescue task</li><li><a href="https://www.lita.io/">Lita</a>: Written in Ruby</li><li><a href="http://errbot.net/">Err</a>: Written in Python</li></ul><p>Deployment task creation and completion will send out notifications into the integrated chat services. <a href="https://campfirenow.com/">Campfire</a>, <a href="https://www.hipchat.com/">Hipchat</a>, <a href="https://slack.com/">SlackHQ</a>, and <a href="https://www.flowdock.com/">Flowdock</a> can receive deployment status event notifications.</p><h3>Use cases in our company</h3><h4>1. Developers use it to deploy to the staging environment</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/676/1*lWEwt5cgW5zqHtkA8tRyag.png" /></figure><p>Although we planned to use ChatOps to ease the difficulties for non-developers, it also benefits me as a developer. <br> <br>For example, when I want to deploy trellhub/edge to pandawork, I can just type chima deploy trelhub/edge to pandawork and then brew some coffee while I wait.<br> <br>To deploy using a chat command, I have to set up the environment settings at Chima. To make sure the deployment is authorized, I have also provided Faseng the access to the pandawork server.</p><h4>2. QA can also deploy the latest version to the edge</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/676/1*e-mIkpu3XnMVlUq7DIfr-w.png" /></figure><p>After each milestone, the QA team is responsible for performing functional tests, usability tests, and performance tests for the pre-deliverable software. <br> <br> In this example, our QA engineer, <a href="https://medium.com/u/57d6cffeab2a">Joyz</a>, wants to ensure that the latest version of modmod-web is ready on the edge environment before she runs the tests. She can trigger the deployment and receive notifications as well.</p><h4>3. Checking up the current jobs</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/676/1*9124MZa1SPe2RZCX36tO8Q.png" /></figure><p>To see the current building jobs, <strong>everyone</strong> who is relevant to the project can talk to Chima and check on the Travis building progress.<br> <br>This one-time initial ChatOps setup has helped our team manage our projects in the following ways:</p><ul><li>Enables less technical members on the team to contribute to the development process.</li><li>Notifications are pushed to the relevant project channel, which means that every relevant team member receives and can access status updates.</li></ul><p>We are working towards doing more via ChatOps , such as backing up servers and <a href="https://medium.freecodecamp.org/4-steps-to-build-an-automated-testing-pipeline-with-gitlab-ci-24ccab95535e">performing automated tests</a>. Look out for future updates or share your tips with us! We’d love to hear from you.</p><h3>Further reading</h3><h4>About continuous integration</h4><ul><li><a href="http://www.objc.io/issue-6/travis-ci.html">Issue 6: Build Tools · Issue Travis CI for iOS</a></li></ul><h4>About deployment</h4><ul><li><a href="https://developer.github.com/v3/repos/deployments/">Github Developer — Deployments</a></li><li><a href="https://github.com/capistrano/capistrano">Remote multi-server automation tool — Capistrano</a></li><li><a href="http://www.fabfile.org/">Python tool for streamlining deployment- Fabric</a></li></ul><p>Footnote: Now, we’ve moved to GitHub trigger deploy.</p><p>Building an app? Our free <a href="https://oursky.com/products/">developer tools</a> and <a href="http://skygear.io/">open source backend</a> will make your job easier.</p><p>Liked what you read? Give me some claps so more people see this article! Thanks!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b2accc72e2a9" width="1" height="1" alt=""><hr><p><a href="https://medium.com/free-code-camp/want-to-make-the-deployment-process-less-scary-build-chatops-in-slack-b2accc72e2a9">Want to make the deployment process less scary? Build ChatOps in Slack.</a> was originally published in <a href="https://medium.com/free-code-camp">We’ve moved to freeCodeCamp.org/news</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to use transfer learning to create an image classifications engine]]></title>
            <link>https://medium.com/oursky-team/using-tensorflow-and-support-vector-machine-to-create-an-image-classifications-engine-7ee51b5617d5?source=rss-907d507d902c------2</link>
            <guid isPermaLink="false">https://medium.com/p/7ee51b5617d5</guid>
            <category><![CDATA[tensorflow]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[image-recognition]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Rick Mak]]></dc:creator>
            <pubDate>Fri, 21 Oct 2016 00:03:49 GMT</pubDate>
            <atom:updated>2017-08-16T11:02:25.936Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*32h8ts3A-7XNr6A4Js87ng.jpeg" /><figcaption>Image by Tony Webster via <a href="https://unsplash.com/collections/211345/cyberpunk?photo=F9o7u-CnDJk">Unsplash</a></figcaption></figure><p>In this post, we are documenting how we used Google’s <a href="https://www.tensorflow.org/">TensorFlow</a> to build this image recognition engine. We’ve used <a href="https://github.com/tensorflow/models/tree/master/inception">Inception</a> to process the images and then train an <a href="https://en.wikipedia.org/wiki/Support_vector_machine">support vector machine (SVM) classifier</a> to recognise the object, in other words, transfer learning. Our aim is to build a system that helps a user with a zip puller to find a matching puller in the database. This piece will also cover how the Inception network sees the input images and assess how well the extracted features can be classified.</p><h3>Our puller project with TensorFlow</h3><p>Recently, Oursky got a mini zip puller recognition project. One of our teams had to build a system for users to match an image of puller with most similar puller inside the database. The sample size for the trial is small (12 pullers), which has implications discussed below as we share our experience on trying out Google’s TensorFlow.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eRAHu29vK4P8dVy5VxCxOQ.jpeg" /><figcaption>Images showing 12 different pullers</figcaption></figure><p>Our first test was to compare the <a href="https://en.wikipedia.org/wiki/Histogram_of_oriented_gradients">histogram of oriented gradients (HOG)</a> feature computed on the input image and all the puller model images rendered from their computer-aided design (CAD) models. This solution works but the matching performance is poor if the input image background has a strong texture.</p><p>We also tested an alternative solution to address the problems with the textured background. We then built a relatively shallow convolutional neural networks (CNN) with 2 convolutional layers and two fully connected layer <a href="#aedf">[1]</a> for classifying the puller image. However, since our data set is too small (around 200 puller images for each type) and lacks variety, the classification performance is poor. It is basically not different from making random guesses.</p><p>Training a CNN from scratch with a small data set is indeed a bad idea. The common approach for using CNN to do classification on a small data set is not to train your own network, but to use a pre-trained network to extract features from the input image and train a classifier based on those features. This technique is called transfer learning. TensorFlow has a <a href="https://www.tensorflow.org/versions/r0.9/how_tos/image_retraining/index.html#bottlenecks">tutorial</a> on how to do transfer learning on the Inception model; Kernix also has a <a href="http://www.kernix.com/blog/image-classification-with-a-pre-trained-deep-neural-network_p11">nice blog post</a> talking about transfer learning and our work is largely based on that.</p><h3>Brief overview on classification</h3><p>In a classification task, we first need to gather a set of training examples. Each training example is a pair of input features and labels. We would like to use these training examples to train a classifier, and hope that the trained classifier can tell us a correct label when we feed it an unseen input feature.</p><p>There are lots of learning algorithms for classification, for example SVM, random forest, and neural network. How well a learning algorithm can perform is highly related to the input feature. Input feature is a representation that captures the essence of the object under classification.</p><p>For example, in image recognition, the raw pixel values could be an input feature. However, using raw pixel values as input feature, the feature dimension is usually too big or too generic for a classifier to work well. In this case, we can either use a more complex classifier such as deep neural network, or use some domain knowledge to brainstorm a better input feature.<a href="#8a86">[2]</a></p><p>For our puller classification task, we will use SVM for classification, and use a pre-trained deep CNN from TensorFlow called Inception to extract a 2048-d feature from each input image.</p><h3>Bottlenecks features of deep CNN</h3><p>The common structure of a CNN for image classification has two main parts: 1) a long chain of convolutional layers, and 2) a few (or even one) layers of the fully connected neural network. The long convolutional layer chain is indeed for feature learning. The learned feature will be feed into the fully connected layer for classification.</p><p>The feature that feeds into the last classification layer is also called the bottleneck feature. The following image shows the structure of TensorFlow’s Inception network we are going to use. We have indicated the part of the network that we are getting the output from as our input feature.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*1XfV5hNxuZH-Fo4dmVVHNA.png" /><figcaption>TensorFlow Inception Model that indicating the bottlenecks feature</figcaption></figure><h3>How Inception sees a puller</h3><p>Training a CNN means it learns a bunch of <a href="https://en.wikipedia.org/wiki/Kernel_(image_processing">image filters (kernels)</a>.</p><p>For example, if the input of the convolutional layer is an image with 3 channels, the kernel size for this layer is 3×3 and there will be an independent set of three 3×3 kernels for each output channel. Each kernel in a set will convolve with the corresponding channel of the input and produces three convolved images. The sum of those convolved images will form a channel of the output.</p><p>The illustration below is a convolution step.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/458/1*Jlajp-esbbf3K9PinY_b-g.png" /><figcaption>Illustration of convolution</figcaption></figure><p>As the output of each convolutional layer <a href="#cc5b">[3]</a> is a multi-channel image, we could also view them as multiple gray-scale images.”. By plotting those grayscale images out, we can understand how the Inception network sees an image. The following images are extracted at different stages of the convolutional layer chain The points are illustrated as A,B,C and D in the Inception Model figure.</p><p>This is an input image.</p><h4>All the 32 149×149 images at stage A:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BLIYWeWd9bALFNqb1Xz5Ow.png" /><figcaption>Inception Output image at Stage A</figcaption></figure><h4>All the 32 147×147 images at stage B:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I4vW1O9xgUV4KBmyXiiDSA.png" /><figcaption>Inception Output image at Stage B</figcaption></figure><h4>All the 288 35×35 images at stage C:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*204ZY_KVimJxridB_0GCtQ.png" /><figcaption>Inception Output image at stage C</figcaption></figure><h4>All the 768 17×17 images at stage D:</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ilT-_iH5NEnRuKg3i8Uc_g.png" /><figcaption>Inception Output image at stage D</figcaption></figure><p>Here we can see the images become more and more abstract going down the convolutional layer chain. We could also spot that some of the image are highlighting the puller, and some of them are highlighting the background.</p><h3>Why is the bottleneck feature good?</h3><p>The bottleneck feature of Inception network is a 2048-d vector. The following is a figure showing the bottleneck feature of the previous input image in bar chart form.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UjqqfUHNf9r2b8e4gRtILA.png" /><figcaption>Bottleneck feature in bar chart form</figcaption></figure><p>For the bottleneck feature to be a good feature for classification, we would like the features representing the same type of puller to be close (think of the feature as a point in 2048-d space) to each other, while features representing different types of puller should be far apart. In other words, we would like to see features in a data set clustering themselves according to their types.</p><p>It is hard to see this kind of clustering happened on 2048-d feature data sets. However, we can do a dimensionality reduction<a href="#9388">[4]</a> on the bottleneck feature and transform them to a 2-d feature which is easy to visualize. The following image is the scatter plot of the transformed feature in our puller data set<a href="#fce7">[5]</a> . Different puller type are illustrated by different colors.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/972/1*7dX1iOgLpHlq100-HyxVew.png" /><figcaption>Scatter plot of transformed feature of the puller dataset</figcaption></figure><p>As we can see, the same color points are mostly clustered together. It has a high chance that we could use the bottleneck feature to train a classifier with high accuracy.</p><h3>Code for extracting inception bottleneck feature</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/ce16f5ba36786d1455b8467cfd9ef083/href">https://medium.com/media/ce16f5ba36786d1455b8467cfd9ef083/href</a></iframe><p>The inception v3 model can be downloaded <a href="https://storage.googleapis.com/download.tensorflow.org/models/inception_dec_2015.zip">here</a>.</p><h3>Training a SVM classifier</h3><p>SVM is a linear binary classifier.</p><p>The goal of the SVM is to find a hyper-plane that separates the training data correctly in two half-spaces while maximising the margin between those two classes.</p><p>Although SVM is a linear classifier, which could only deal with linear separable data sets, we can apply a <a href="https://en.wikipedia.org/wiki/Kernel_method">kernel trick</a> to make it work for non-linear separable case.</p><p>A commonly used kernel besides linear is the <a href="https://en.wikipedia.org/wiki/Radial_basis_function_kernel">radial basis function kernel (RBF kernel)</a>.</p><p>The hyper-parameters for SVM includes the type of kernel and the regularization parameter *C*. If using the RBF kernel, there is an additional parameter *γ* for selecting which radial basic function to use.</p><p>Usually the bottleneck feature from a deep CNN is linear separable. However, we will consider the RBF kernel as well.</p><p>We used simple grid search for selecting the hyper-parameter. In other words, we tried out all the hyper-parameter combination in the range we have specified, and evaluated the trained classifier performance using <a href="https://en.wikipedia.org/wiki/Cross-validation_(statistics)">cross validation</a>.</p><p>The rule of thumb for trying out the *C* and *γ* parameter is trying them with different order of magnitude.</p><p>We used 10-fold cross validation.</p><p>SVM is a binary classifier. However, we could use the <a href="https://en.wikipedia.org/wiki/Multiclass_classification#One-vs.-rest">one-vs-all</a> or <a href="https://en.wikipedia.org/wiki/Multiclass_classification#One-vs.-one">one-vs-one</a> approach to make it a multi-class classifier.</p><p>It seems a lot of stuff to do for training a SVM classifier, indeed it is just a few function calls when using machine learning software package like <a href="http://scikit-learn.org/">scikit-learn</a>.</p><h3>Code for the training the SVM classifier</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c04d18a65101b58e7e601f3e016bd028/href">https://medium.com/media/c04d18a65101b58e7e601f3e016bd028/href</a></iframe><h3>SVM training result</h3><p>The following is the training result we get, which got a perfect result! Though this might deal to overfitting…</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/917c6bb0e0a8edb8b63dd837cd92ef76/href">https://medium.com/media/917c6bb0e0a8edb8b63dd837cd92ef76/href</a></iframe><p>We’ve used it to built an mobile app and a web front-end for the puller classifier for field testings.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*k6CAnK_YRT-RdVSS_A4EoQ.jpeg" /><figcaption>Puller Matcher screenshot</figcaption></figure><p>Since the classifier can work with unseen samples, it seems that the over-fitting issue is not so serious.</p><h3>Conclusion</h3><p>A pre-trained deep CNN, Inception network in particular, could be used as a feature extractor for general image classification tasks.</p><p>The bottleneck feature of the Inception network should a good feature for classification. We have extracted the bottleneck feature from our data set and did a dimensionality reduction for visualization. The result shows a nice clustering of the sample according to their class.</p><p>The SVM classifier training on the bottleneck feature has a perfect result, and the classifier seems to work on the unseen sample.</p><h3>Footnotes</h3><p>1: <a href="#30d5">^</a> The model is based on one of the TensorFlow <a href="https://www.tensorflow.org/versions/r0.10/tutorials/deep_cnn/index.html">Tutorial</a> on <a href="https://www.cs.toronto.edu/~kriz/cifar.html">CIFAR-10</a> classification, with some twist to deal with larger image size.</p><p>2: <a href="#437f">^</a> Sometimes, it will be the other way round, the dimension input feature is too small, we need to do some transformation on the input feature to expand its dimension. The process of picking a good feature to learn is called <a href="https://en.wikipedia.org/wiki/Feature_engineering">feature engineering</a>. It is a difficult task. One of the reasons why deep learning is so popular is because we can feed in raw and generic input to the network, and it can automatically learn some good feature during the training. However, the trade-off will be a huge training data set and long training time.</p><p>3: <a href="#7f55">^</a> Noticed that one convolutional layer is not just having one convolution operation, it could also have multiple convolution operations, pooling operations, or other operations.</p><p>4: <a href="#ca82">^</a> The algorithm for dimensionality reduction we use is <a href="https://en.wikipedia.org/wiki/T-distributed_stochastic_neighbor_embedding">t-SNE</a>.</p><p>5: <a href="#ca82">^</a> We didn’t use the full data set for the classification, instead we remove images has low variety from the data set, this result in a data set of around 400 images.</p><blockquote>If you find this post interesting, please click that heart below so other people can see too!</blockquote><blockquote>Building an app? Our free <a href="https://oursky.com/products/">developer tools</a> and <a href="http://skygear.io/">open source backend</a> will make your job easier.</blockquote><p><em>Originally published at </em><a href="https://code.oursky.com/tensorflow-svm-image-classifications-engine/"><em>code.oursky.com</em></a><em> on October 21, 2016.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7ee51b5617d5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/oursky-team/using-tensorflow-and-support-vector-machine-to-create-an-image-classifications-engine-7ee51b5617d5">How to use transfer learning to create an image classifications engine</a> was originally published in <a href="https://medium.com/oursky-team">Oursky Team</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>