<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: James Hrisho</title>
    <description>The latest articles on Forem by James Hrisho (@securingsincity).</description>
    <link>https://forem.com/securingsincity</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F267008%2F41087331-30b5-4814-b85c-81c13da3d107.jpeg</url>
      <title>Forem: James Hrisho</title>
      <link>https://forem.com/securingsincity</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/securingsincity"/>
    <language>en</language>
    <item>
      <title>Why did I start a feature flagging startup? </title>
      <dc:creator>James Hrisho</dc:creator>
      <pubDate>Thu, 28 Jan 2021 03:31:06 +0000</pubDate>
      <link>https://forem.com/securingsincity/why-did-i-start-a-feature-flagging-startup-1fik</link>
      <guid>https://forem.com/securingsincity/why-did-i-start-a-feature-flagging-startup-1fik</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EJmcR1Zo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/aoe9ernm0y9pse5l54nv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EJmcR1Zo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/aoe9ernm0y9pse5l54nv.png" alt="Sample code for a Molasses Client"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When the pipe bursts
&lt;/h2&gt;

&lt;p&gt;7am every Wednesday, it was time to release the code. I'd take a weeks worth of code that I knew nothing about, by 2 dozen people, and ship it to production. We tested the code in isolation. We tested it together in our lower environments.  But even then when it was up on production who knew what was going to happen. Even if the release itself went well, there was always a chance that a feature was not ready for users. Finding that out at the last minute could push a release to a later day. This would delay other important releases that teams worked hard on. &lt;/p&gt;

&lt;p&gt;By batching up releases, we thought we were doing everyone a favor.  Customer success only has to learn about the release once a week! One person can own the release process and be an authority on it! We can test everything together all at once, and know for sure that it will work!. We were so wrong. &lt;/p&gt;

&lt;p&gt;By batching up releases, we introduced a ton of risk. The release became an all or nothing affair. If any feature in a release wasn't ready for customers, everything we had already communicated to customers was at risk. We would mitigate that risk by creating new problems. Rushing through something or introducing new issues. &lt;/p&gt;

&lt;p&gt;The person (me) who was doing the deployment had no context for what exactly I was deploying. Sure the steps we could document the steps and what was in the release. But if something went wrong,, all I knew I could do was stop the whole train. If anything broke, it was impossible to figure out what may have caused it. Even if you are an expert of a system, a week's worth of work by 20+ people is impossible to isolate defects. &lt;/p&gt;

&lt;p&gt;After a few too many stressful releases, we decided one of the best investments we could make quickly was feature flags. With feature flags, you separate the release of code to customers from the deployment to production. Code for a new feature can live in a production environment for any duration of time without disruption to your customer. When the feature is ready, any team member can turn it on. If there is an issue for any reason, Anyone can shut the feature off, limiting impact. &lt;/p&gt;

&lt;p&gt;We saw improvements to our process right away.  We stopped batching deployments, instead we would deploy to production regularly. Each change getting sent to production was easy to discern, it could be as small as a couple lines of code. If there was an issue it would be easy to track and identify. &lt;/p&gt;

&lt;p&gt;When a feature was  ready for customers, anyone on our team, especially our product owners, could turn it on. We even went further. To deliver value cusotmers sooner, we could build smaller features and only release it to users who had no known edge cases.  Once we had more time to identify how to approach the edge cases those customers would receive the updates. Teams became more confident, less stressed, and could get feedback on their work in a much shorter timeframe. &lt;/p&gt;

&lt;p&gt;This was a transformative experience for me. I've been preaching the gospel ever since. I knew I could help get teams to work faster by enabling feature flags for more teams. &lt;/p&gt;

&lt;p&gt;That's why I built Molasses. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Great Molasses Flood 
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GXsT9zDJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ethy6ngta9qxnhqujlvm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GXsT9zDJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ethy6ngta9qxnhqujlvm.png" alt="The Molasses dashboard of feature flags"&gt;&lt;/a&gt;&lt;br&gt;
I started building in June. I focused on the problems I saw with the current tools. I surveyed those who had used feature flagging and A/B testing services in the past to get their opinion. What I found was that while there are great solutions here and there, but there was space for improvement. &lt;/p&gt;

&lt;p&gt;Despite being a developer focused tool,  so many feature flag services are developer hostile. They can be slow, and make blocking remote calls. They are naive in their ability to target users, sometimes only by IP address or one parameter.  They had no way to audit changes. They lacked integrations with platforms for planning, chatops or observability.   Teams are slow to remove feature flags, accumulating technical debt. The gaps in these feature flag systems are  filled with custom software. Taking away from expensive developer and operations resources. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.molasses.app/"&gt;Molasses&lt;/a&gt; allows teams to get up and running with feature flags right away. It supports many different languages and frameworks.&lt;br&gt;&lt;br&gt;
Molasses' clients are fast, non-blocking, and the service pushes updates to the client instantly, no waiting.  You can roll out features to specific users and target specific groups. Molasses lets teams focus on the features they are building, not building feature flag technology. &lt;/p&gt;

&lt;p&gt;Molasses unlocks A/B testing. We can examine the effectiveness  of a change right away. Want to start rolling out a feature to a set of alpha or beta users? No problem! Molasses will let you adjust who receives a feature over time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WFeyY6ag--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ianmbvfjydff72uo816l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WFeyY6ag--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ianmbvfjydff72uo816l.png" alt="A github PR opened by Molasses to clean up code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Molasses isn't the only tool in your toolchain. It integrates with the systems you already use, like Datadog or Slack. You can use those updates to know if a recent change is causing issues. When your feature is finally rolled out, Molasses has the code clean itself up. It opens a PR in your Github repo removing any stale code. &lt;/p&gt;

&lt;p&gt;I'm proud of what I've built so far. I'm excited to watch teams speed up with Molasses.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.molasses.app"&gt;Molasses&lt;/a&gt; is a feature flag and A/B testing service.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Molasses is Live on Product Hunt!</title>
      <dc:creator>James Hrisho</dc:creator>
      <pubDate>Fri, 27 Nov 2020 11:17:13 +0000</pubDate>
      <link>https://forem.com/securingsincity/molasses-is-live-on-product-hunt-2641</link>
      <guid>https://forem.com/securingsincity/molasses-is-live-on-product-hunt-2641</guid>
      <description>&lt;p&gt;&lt;a href="https://www.producthunt.com/posts/molasses-feature-flags-as-a-service"&gt;Molasses is launching on Product Hunt Today!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;208 times more often.&lt;/p&gt;

&lt;p&gt;According to the latest State of the DevOps report, high performing teams deploy code 208 times more often than a low performing team. While actually having fewer bugs. More deployments?! Less bugs?! &lt;/p&gt;

&lt;p&gt;When I read that I was shook. So I decided to help teams faster and ship code with fewer bugs by launching Molasses! &lt;/p&gt;

&lt;p&gt;Molasses is a feature flag platform. Feature flags are a technique that allows you to turn on or off features without having to deploy new code, allowing you to release code more often. Molasses supports many different languages and frameworks - React, React Native, TypeScript, JS, Node, Go, Python, and Ruby. &lt;/p&gt;

&lt;p&gt;Once you use tools like this you realize how important it is to have powerful tooling around it. So I also included audit logging and an integration with Slack.&lt;/p&gt;

&lt;p&gt;I'm excited for folks to try Molasses. If you are looking to give it a test run, let me know and I can help you get started right away. Check out our &lt;a href="https://molasses.app/"&gt;website&lt;/a&gt;, our &lt;a href="https://github.com/molassesapp/"&gt;github&lt;/a&gt; and of course our &lt;a href="https://www.producthunt.com/posts/molasses-feature-flags-as-a-service"&gt;Product Hunt Page!&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>producthunt</category>
      <category>showdev</category>
      <category>node</category>
    </item>
    <item>
      <title>Making Laundry Less Terrible with Machine Learning</title>
      <dc:creator>James Hrisho</dc:creator>
      <pubDate>Sat, 24 Oct 2020 01:43:37 +0000</pubDate>
      <link>https://forem.com/securingsincity/making-laundry-less-terrible-with-machine-learning-3ih6</link>
      <guid>https://forem.com/securingsincity/making-laundry-less-terrible-with-machine-learning-3ih6</guid>
      <description>&lt;p&gt;Since my son was born, I've been doing a lot of laundry. An infant's laundry needs are small (well the clothes are) but frequent so to be efficient you might as well do the whole family's the laundry.  When you do enough laundry, you'll notice those little tags. Each garment has a set of shapes -  triangles, circles, squares, and other shapes - that intend to describe how to care for it. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2m5anpdb8kn2522a1jaq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F2m5anpdb8kn2522a1jaq.jpg" alt="Laundry care tags - Wash at 60 degrees Celsius, Do not bleach"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well last year, I got obsessed and started to learn how to interpret each one. It's not complicated but it is not obvious either. So I set out to make it easier on myself and others. It's easy enough to create a pocket guide for laundry tags. But, I thought it would be neat to be able to take a picture of the care tag and present which tag it matched. This seemed like an opportunity to play around with machine learning and computer vision tools as well. &lt;/p&gt;

&lt;p&gt;Each time I did laundry I would take photos of the tags. I would then organize them based on which type of care tag it was (Wash at 30 degrees Celsius vs Non-Chlorine Bleach). Using &lt;a href="https://firebase.google.com/docs/ml/automl-image-labeling" rel="noopener noreferrer"&gt;Firebase's Automl Vision Edge&lt;/a&gt;, I could then create a machine learning model. &lt;br&gt;
Vision edge generates a TFlite model to use to classify an image. To use the model, I then created an Android app and an iOS app to consume results from the camera. &lt;/p&gt;

&lt;p&gt;Here's what the Kotlin code looks like to process an image&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onImageSaved&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;uri&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUri&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// loads the machine learning model&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;localModel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FirebaseAutoMLLocalModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAssetFilePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"manifest.json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FirebaseVisionOnDeviceAutoMLImageLabelerOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;localModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setConfidenceThreshold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;// Sets the appropriate confidence threshold&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="c1"&gt;// loads the labeler&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;labeler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FirebaseVision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;getOnDeviceAutoMLImageLabeler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FirebaseVisionImage&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// loads the image as a firebase vision image&lt;/span&gt;
            &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FirebaseVisionImage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fromFilePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;applicationContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;labeler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;processImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addOnSuccessListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;
                        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;confidence&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confidence&lt;/span&gt;
                        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"RECOGNITION"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="c1"&gt;// do a thing with the confidence and label&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addOnFailureListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
                    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;IOException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;printStackTrace&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code in Swift is very similar&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;localModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;AutoMLLocalModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;manifestPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;manifestPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;VisionOnDeviceAutoMLImageLabelerOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;localModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;localModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confidenceThreshold&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;  
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;labeler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Vision&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;vision&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onDeviceAutoMLImageLabeler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;YPImagePickerConfiguration&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;showsCrop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ratio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;showsPhotoFilters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;picker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;YPImagePicker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;picker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;didFinishPicking&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;unowned&lt;/span&gt; &lt;span class="n"&gt;picker&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;photo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;singlePhoto&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;photo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;VisionImage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;photo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_didFinishPicking&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="n"&gt;labeler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;labels&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;GuideResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;label&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_setResult&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="k"&gt;break&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;picker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;animated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dismiss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;animated&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;completion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This project also leveraged SwiftUI so I ended up building an Apple Watch and iPad version as well  &lt;/p&gt;

&lt;p&gt;I'm really proud with how it came out. I released both apps under the LaundrySnap name in the respective app stores back in May but I just launched it on Product Hunt Today!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.producthunt.com/posts/laundrysnap" rel="noopener noreferrer"&gt;Product Hunt Link&lt;/a&gt;&lt;br&gt;
&lt;a href="https://apps.apple.com/us/app/laundry-snap/id1509340764" rel="noopener noreferrer"&gt;Apple App Store&lt;/a&gt;&lt;br&gt;
&lt;a href="https://play.google.com/store/apps/details?id=com.laundrysnap&amp;amp;hl=en_US&amp;amp;ref=producthunt" rel="noopener noreferrer"&gt;Google Play Store&lt;/a&gt;&lt;/p&gt;

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

</description>
      <category>android</category>
      <category>ios</category>
      <category>machinelearning</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Continuously Delivering at Maxwell Health</title>
      <dc:creator>James Hrisho</dc:creator>
      <pubDate>Thu, 07 Nov 2019 15:08:00 +0000</pubDate>
      <link>https://forem.com/securingsincity/continuously-delivering-at-maxwell-health-57k</link>
      <guid>https://forem.com/securingsincity/continuously-delivering-at-maxwell-health-57k</guid>
      <description>&lt;p&gt;When I read Jez Humble’s book &lt;em&gt;Continuous Delivery&lt;/em&gt; a few years ago, I felt like I was being watched. I thought Jez had been monitoring us and watching us struggle with deployments. In 2015, Maxwell Health released once a week. It was a coordinated affair and rife with what we discovered were anti-patterns. We would deploy off-hours, we coordinated deployments between teams, and each environment had its own build. If things went wrong, we would try to fix forward. It caused unnecessary stress, introduced risk for our customer experience and our software, and we had to make a change.&lt;/p&gt;

&lt;p&gt;Today, Maxwell deploys code to production dozens of times a day without incident. It took coordination and dedication to change our process, and it was well worth the effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  We ship small artifacts
&lt;/h2&gt;

&lt;p&gt;In our old deployment pipeline, we tied our branching strategy to our deployments. Our strategy was a variation on &lt;a href="https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow"&gt;git flow&lt;/a&gt;. When creating a new feature, an engineer would branch off of master and name your branch &lt;em&gt;feature-abc&lt;/em&gt;. We then had a branch for each of our environments - QA, Staging, and Production. The engineer merged their branch to the QA branch for testing. Once the feature passed testing, the _feature-abc _branch could then be merged a second time, this time to master, and master would be merged into the staging and production branches. Each merge was its own build and this process encouraged mismatches between environments. What was on QA wasn’t guaranteed to be exactly what was deployed to staging or production.&lt;/p&gt;

&lt;p&gt;After experiencing confusion, coordination issues, and too many mis-merged features, we adopted a version of &lt;a href="https://guides.github.com/introduction/flow/"&gt;Github Flow&lt;/a&gt;. An engineer creates a branch off of master as they had before. Once approved, the engineer testing that code merges the branch to master. The build pipeline then builds an artifact, in our case a docker image, and deploys it to our QA environment. Each commit once on master needs to be deployable. This keeps the pipeline clear and able to be deployed to production without incident. Each commit being deployable also means that authors must have strong automated tests to ensure confidence in their change. If it fails any testing on the QA environment or blocks the pipeline for whatever reason, we revert it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NvfdHs6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://engineering.maxwellhealth.com/images/Continuously-Delivering0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NvfdHs6_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://engineering.maxwellhealth.com/images/Continuously-Delivering0.jpg" alt="our branching strategy" title="our branching strategy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If exploratory testing is successful in QA, the team can then ship that artifact to other environments by creating a Git tag. Our build tool knows, based on the name of the tag, to ship the artifact from that Git hash to the target environment. We even simplified it by building a small make command for it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PSgapdia--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://engineering.maxwellhealth.com/images/Continuously-Delivering1.png%23full-width" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PSgapdia--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://engineering.maxwellhealth.com/images/Continuously-Delivering1.png%23full-width" alt="our custom make tooling" title="our custom make tooling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our tooling also enables quick rollback. To rollback, you would call the same command for a SHA you want to go back to. Usually the previous deployment.&lt;/p&gt;

&lt;p&gt;Our old branching strategy encouraged long-lived branches. There would be painful merge conflicts, different merge order on QA vs production, and each environment would behave slightly different. To accommodate the Github flow/artifact approach, each change needed to be small, releasable, and well tested. With smaller releases, both improvements and bug fixes are easier to reason about and verify. Our code review process is less painful, and we have fewer incidents in production.&lt;/p&gt;

&lt;h2&gt;
  
  
  SLOs for Builds, Deployments, and Rollbacks
&lt;/h2&gt;

&lt;p&gt;We decided it is important to focus on rollbacks as part of our strategy. In the past, we would fix forward instead of rollback. Fixing forward, while well-intentioned, encouraged us to make matters worse. We would try to make changes while under duress. In the worst cases, we caused bugs in production while trying to fix other issues.&lt;/p&gt;

&lt;p&gt;Instead, we want rollbacks to be the first tool in our engineers’ toolboxes. Our guideline is for our teams to make rollbacks possible less than a minute. As a result, the quickness of a rollback makes it the default instead of the last resort. Since our rollback strategy is identical to deployment (using a make command to send a specific Docker image to a specific environment), our deployment time also improved.&lt;/p&gt;

&lt;p&gt;We also encourage builds to be less than 10 minutes. Our branching strategy encourages reverts and merging to master more often. Each of these events trigger builds, so long builds are an interrupt for teams. We must keep build times as short as possible. We spend money both on our team's time and our build server's time while we build. So time spent building should be minimal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Identical Environments
&lt;/h2&gt;

&lt;p&gt;To enable confidence in our deployments, we had to be certain of our environments. If one environment is quite different, we open ourselves up for bugs. The right way to do this is to invest in the tools that make your infrastructure repeatable and auditable. For us, that meant investing in our infrastructure-as-code strategy. At Maxwell, we leverage Docker, Terraform, Kubernetes, and other tools to make sure that our environments are as similar as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Separating Release From Deployment
&lt;/h2&gt;

&lt;p&gt;Finally, Maxwell encourages our teams to separate the concepts of deployment and release. We even made sure our vocabulary on the topic was well defined. Deployments are the act of moving code to an environment, while releases are the process of making functionality available to a stakeholder. Although we deploy several times a day, our releases might be less frequent, and are controlled by our product owners. Releases usually consist of more than one small change. Releases might include coordination of several teams work. For example, one team might be building the reporting functionality that is tied to new data we’re collecting. We would want to release that to our customers together but not have to coordinate the deployment of their code. Releases also include training for internal stakeholders, or a communication to our customers.&lt;/p&gt;

&lt;p&gt;We enable this separation of releases and deployments by the use of feature toggles.  Feature toggles allow us to hide functionality to all or a portion of users. We use an open-source library but there are many options for how to manage toggling your code. Our deployments have become much safer as putting work behind a feature toggle means we can deploy incremental parts of a feature rather than waiting for the entire feature to be complete and pushing a large body of code to production at once. Toggles also ensure that our functionality works in production without disrupting our customers. When our product team feels a feature is ready they can then turn on a feature toggle when they are ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metrics For Success
&lt;/h2&gt;

&lt;p&gt;These are a small number of the many changes our organization has made to become more efficient. We're constantly improving our processes, including in how we monitor, alert, and test. We are quick to respond to our customers. But more importantly, we're more confident in our work each day.&lt;/p&gt;

&lt;p&gt;We started with metrics that we felt would make our teams successful. We knew we wanted to optimize for more frequent deployments and fewer incidents related to them. We wanted to minimize the number of times we fixed forward, as we recognized that as a failed release. We wanted the frequency that we ship code to be separated from the frequency we released to customers. Before starting the journey to continuous delivery, consider the objectives you are trying to achieve. In order to determine success, create metrics that measure a team's progress over time. These goals should have a reasonable end state in mind. For example, a build can always be faster, but what length of time is a success for your team? Chances are, the answer will be unique to the tools you use and the domain of your business.&lt;/p&gt;

&lt;p&gt;While the journey can be challenging, don't give up. Each improvement builds upon itself. We've found that every six months we're unrecognizable to the organization we were six months before that. We're a more mature, yet more nimble version of ourselves.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
