<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: YNAB</title>
    <description>The latest articles on DEV Community by YNAB (@ynab).</description>
    <link>https://dev.to/ynab</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%2Forganization%2Fprofile_image%2F1091%2Fe500e743-56f2-4db9-85b6-2de7b79acb5d.png</url>
      <title>DEV Community: YNAB</title>
      <link>https://dev.to/ynab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ynab"/>
    <language>en</language>
    <item>
      <title>How we use OpenAPI / Swagger for the YNAB API</title>
      <dc:creator>Brady Holt</dc:creator>
      <pubDate>Mon, 16 Mar 2020 21:27:46 +0000</pubDate>
      <link>https://dev.to/ynab/how-we-use-openapi-swagger-for-the-ynab-api-5453</link>
      <guid>https://dev.to/ynab/how-we-use-openapi-swagger-for-the-ynab-api-5453</guid>
      <description>&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;OpenAPI Specification&lt;/th&gt;
&lt;th&gt;➡&lt;/th&gt;
&lt;th&gt;✅ Tests&lt;br&gt;✅ Documentation&lt;br&gt;✅ Client Libraries&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.youneedabudget.com" rel="noopener noreferrer"&gt;YNAB&lt;/a&gt; combines software with 4 simple rules to help our users gain control their money.  Back in 2018 we released an API to help our community build things to connect their budget to other apps and services.&lt;/p&gt;

&lt;p&gt;We built the &lt;a href="https://api.youneedabudget.com/" rel="noopener noreferrer"&gt;YNAB API&lt;/a&gt; using the &lt;a href="https://swagger.io/docs/specification/about/" rel="noopener noreferrer"&gt;OpenAPI Specification&lt;/a&gt; and &lt;a href="https://swagger.io/" rel="noopener noreferrer"&gt;Swagger tooling&lt;/a&gt;.  In retrospect we think it was a good decision and has provided many benefits.  This post gives a landscape of our setup and how the tooling works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The specification file
&lt;/h2&gt;

&lt;p&gt;Everything starts with our &lt;a href="https://swagger.io/docs/specification/2-0/basic-structure/" rel="noopener noreferrer"&gt;OpenAPI Specification&lt;/a&gt; file: &lt;a href="https://api.youneedabudget.com/papi/spec-v1-swagger.json" rel="noopener noreferrer"&gt;https://api.youneedabudget.com/papi/spec-v1-swagger.json&lt;/a&gt;.  This is a fairly simple JSON file that we edit when anything changes on the API. &lt;br&gt;
 This file defines the endpoints and the shape of request and response data.&lt;/p&gt;

&lt;p&gt;With this spec file in place, we get access to some great tooling.&lt;/p&gt;
&lt;h2&gt;
  
  
  Tests
&lt;/h2&gt;

&lt;p&gt;We use a Ruby gem called &lt;a href="https://github.com/westfieldlabs/apivore" rel="noopener noreferrer"&gt;Apivore&lt;/a&gt; to test our actual API implementation against our OpenAPI spec.  When our tests run, they exercise all the spec defined endpoints and ensure they are present and work as expected.  With Apivore, you have a &lt;code&gt;validate_all_paths&lt;/code&gt; method, which does a simple validation to ensure endpoints are available and return the expected statuses.  But, you can also exercise the API by passing certain data and Apivore will ensure the shape of the data responses match your spec.  So, if your spec says an endpoint returns an array of sharks: &lt;code&gt;[{"id": 1, "name": "megamouth"},{"id": 2, "name": "hammerhead"}]&lt;/code&gt; but a particular request returns a single shark: &lt;code&gt;{"id": 1, "name": "megamouth"}&lt;/code&gt; a test will fail.  Another example: If you were to change the name of a field in the JSON response, a test would fail.&lt;/p&gt;
&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;p&gt;Here, one of our tests ensures that requesting a non-existent budget at &lt;code&gt;/budgets/:id&lt;/code&gt; returns a 404.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'response with 404 for a non-existent budget'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="ss"&gt;:get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/budgets/{budget_id}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="s1"&gt;'budget_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;SecureRandom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we ensure the &lt;code&gt;/budgets/:id/payees/:id&lt;/code&gt; endpoint returns a payee, when requested, and also that the shape of that payee conforms to our spec:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'returns a single payee'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="ss"&gt;:get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/budgets/{budget_id}/payees/{payee_id}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ability to use a tool like Apivore against our spec is a huge win because we get automatic testing.  Having this alone would be a case for using an OpenAPI spec.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation
&lt;/h2&gt;

&lt;p&gt;Using &lt;a href="https://swagger.io/tools/swagger-ui/" rel="noopener noreferrer"&gt;Swagger UI&lt;/a&gt; we are able to automatically generate our &lt;a href="https://api.youneedabudget.com/v1" rel="noopener noreferrer"&gt;documentation page&lt;/a&gt; just by pointing to our spec.  We did make some customizations to suit our preferences but any changes to our spec file are automatically reflected on that page.&lt;/p&gt;

&lt;p&gt;For example, the documentation for &lt;code&gt;GET /budgets/:id&lt;/code&gt; shows the query parameters that can be passed, expected response status code, and the shape of the response data.&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%2Fp4iu8a4n4uev3pvixdro.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%2Fp4iu8a4n4uev3pvixdro.png" alt="Endpoint"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Swagger UI also has the ability to actually use the API on the page itself which is a great help for developers wanting to test something or quickly see the API responses.&lt;/p&gt;

&lt;p&gt;For example, this is what the page looks like when requesting a specific payee:&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%2Fqkkdpwz1fpio84566lx2.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%2Fqkkdpwz1fpio84566lx2.png" alt="Endpoint Try-it Now"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Client Libraries
&lt;/h2&gt;

&lt;p&gt;Arguably, Swagger tooling is most known for &lt;a href="https://swagger.io/tools/swagger-codegen/" rel="noopener noreferrer"&gt;Swagger Codegen&lt;/a&gt;, which generates client libraries for interfacing with an API.&lt;/p&gt;

&lt;p&gt;We use Codegen to generate our &lt;a href="https://github.com/ynab/ynab-sdk-js" rel="noopener noreferrer"&gt;JavaScript client&lt;/a&gt; and our &lt;a href="https://github.com/ynab/ynab-sdk-ruby" rel="noopener noreferrer"&gt;Ruby client&lt;/a&gt;.  And others in our community use it to build &lt;a href="https://api.youneedabudget.com/#clients-community" rel="noopener noreferrer"&gt;clients for other languages&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One of the nice things about Codegen is the ability to customize the generated client with the use of templates.  For example, we &lt;a href="https://github.com/ynab/ynab-sdk-js/tree/master/swagger-templates" rel="noopener noreferrer"&gt;specify a number of templates&lt;/a&gt; to override the defaults on our JavaScript client.  This allows us to customize things to our suit our preferences.  &lt;/p&gt;

&lt;h3&gt;
  
  
  TypeScript Definitions
&lt;/h3&gt;

&lt;p&gt;Our JavaScript client uses the &lt;code&gt;typescript-fetch&lt;/code&gt; generator which, along with generating a JavaScript client usable from both Node.js and the browser, generates &lt;a href="https://github.com/ynab/ynab-sdk-js/blob/master/dist/index.d.ts" rel="noopener noreferrer"&gt;TypeScript definition files&lt;/a&gt;.  This is really useful because developers who are using TypeScript tooling (like &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;VS Code&lt;/a&gt;) can get develop-time support.&lt;/p&gt;

&lt;h4&gt;
  
  
  Examples
&lt;/h4&gt;

&lt;p&gt;IntelliSense support so a developer can clearly see the available fields:&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%2Fk9cu9sq08s5n8sj6s2b7.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%2Fk9cu9sq08s5n8sj6s2b7.png" alt="IntelliSense"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Develop-time errors (a.k.a. red squiggles) so a developer can see when they have accessed a field that does not exist:&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%2Fps1palq1e1pfn1o5kfug.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%2Fps1palq1e1pfn1o5kfug.png" alt="Red squiggles"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enums selection so a developer can easily select from a list of supported values:&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%2Fgfts2tp0rzzllyq2krmx.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%2Fgfts2tp0rzzllyq2krmx.png" alt="Enums"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All of this support is coming directly from the original OpenAPI specification file!&lt;/p&gt;

&lt;h3&gt;
  
  
  Overall Experience
&lt;/h3&gt;

&lt;p&gt;We've been pleased with our usage of an OpenAPI specification and Swagger tooling to build out our API and the ecosystem around it.  Of course, there have been a few bumps along the way and we still would like to tweak some things but the amount of benefit this tooling brings is significant and allows us to ship things more rapidly.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Practice: Semantic Colors for Developers</title>
      <dc:creator>Emily Carlin</dc:creator>
      <pubDate>Wed, 12 Feb 2020 20:15:09 +0000</pubDate>
      <link>https://dev.to/ynab/the-practice-semantic-colors-for-developers-1o6g</link>
      <guid>https://dev.to/ynab/the-practice-semantic-colors-for-developers-1o6g</guid>
      <description>&lt;p&gt;We've already covered &lt;a href="https://dev.to/ynab/a-semantic-color-system-the-theory-hk7"&gt;the theory&lt;/a&gt; behind our semantic color system as well as &lt;a href="https://dev.to/ynab/semantic-colors-for-designers-2lf2"&gt;how it works for designers&lt;/a&gt;. This post covers how it works when the rubber hits the road: In code! &lt;/p&gt;

&lt;p&gt;We believe that a design system isn’t worth much if it’s only used by designers. So when we started working on this new approach to colors, we knew we wanted to make it simple and usable for developers, too. &lt;/p&gt;

&lt;p&gt;So we &lt;strong&gt;built a Figma integration&lt;/strong&gt; that takes all of the color information from our color file and outputs usable code (special thanks/shoutout to Kyle Robinson Young on the YNAB development team, who helped build the integration). &lt;/p&gt;

&lt;p&gt;YNAB offers an iOS app, an Android app, and a web app. We rely on our design system to keep things consistent between each platform, so the integration outputs code for each platform. &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%2F1kjkxjjx97agumuw94ec.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%2F1kjkxjjx97agumuw94ec.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each platform has some idiosyncrasies as far as how colors are defined and how light/dark mode switching happens, so we’ll run through each of them. &lt;/p&gt;

&lt;h3&gt;
  
  
  iOS
&lt;/h3&gt;

&lt;p&gt;For iOS, the integration outputs a color file that is broken into two sections. This is where &lt;em&gt;all&lt;/em&gt; of our iOS app's colors are defined. &lt;/p&gt;

&lt;p&gt;The first section of the file defines the palette colors. These are private because we never refer to them directly — instead, we refer to semantic colors. This keeps things consistent and guarantees that they look good in light and dark mode. &lt;/p&gt;

&lt;p&gt;In the next section of the file, we have our semantic color definitions. These are what actually we use to apply color. Each and every semantic color points at a palette color for light mode and for dark mode. &lt;/p&gt;

&lt;p&gt;One of our iOS developers wrote a simple function, that looks at the user’s display mode and determines which color variant to display. That way, things will “just work” between modes. We also built in a safe fallback, in case users aren’t running iOS 13 yet.&lt;/p&gt;

&lt;p&gt;We use the description field of the semantic colors from Figma to populate the proper references to the base palette for each semantic color. &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%2F4b2b7m7an2wfu759qbx5.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%2F4b2b7m7an2wfu759qbx5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Android
&lt;/h3&gt;

&lt;p&gt;For Android, the integration outputs to three color-related files. &lt;/p&gt;

&lt;p&gt;First, there’s &lt;code&gt;palette.xml&lt;/code&gt;. This is the base color palette where all possible colors are defined. &lt;/p&gt;

&lt;p&gt;Next, there’s &lt;code&gt;colors.xml&lt;/code&gt; and &lt;code&gt;colors.xml (night)&lt;/code&gt;. These each have each semantic color listed, with the proper reference to the base palette for each mode — light mode definitions go in palette.xml and dark mode definitions go in &lt;code&gt;colors.xml (night)&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;When we’re applying colors, we simply refer to colors defined in &lt;code&gt;colors.xml&lt;/code&gt; and the right variant renders based on the user’s mode. &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%2Fimdlo5w2r3qay1vda5q6.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%2Fimdlo5w2r3qay1vda5q6.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Web
&lt;/h3&gt;

&lt;p&gt;We use Stylus for our web app, so we output a &lt;code&gt;palette.styl,&lt;/code&gt; &lt;code&gt;colors.styl&lt;/code&gt;, and &lt;code&gt;dark-theme.styl&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;As you can probably anticipate from the structure of iOS and Android, &lt;code&gt;palette.styl&lt;/code&gt; contains the base palette colors. ‘Colors.styl&lt;code&gt;and ‘dark-mode.styl&lt;/code&gt; contain CSS variable definitions that reference the proper base palette colors.&lt;/p&gt;

&lt;p&gt;So when we are applying colors, we use the CSS variables we define in &lt;code&gt;colors.styl&lt;/code&gt; and &lt;code&gt;dark-mode.styl&lt;/code&gt; and render the right variant based on the mode the user has selected. &lt;/p&gt;

&lt;p&gt;We haven’t released dark mode for the web, so this approach is still experimental, but we’re confident it will work just as well as the system has been working for iOS and Android. &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%2Fvxwwm9nwg8lcjz1wqd3a.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%2Fvxwwm9nwg8lcjz1wqd3a.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Communication between designers and developers
&lt;/h3&gt;

&lt;p&gt;The fact that we output color definitions directly from Figma means that when a developer looks at a design, they can use the exact same name as the designer and the code will “just work.”&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%2Fzfibq973o3su7obz796i.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%2Fzfibq973o3su7obz796i.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Figma integration makes it easy and lightweight to keep the system up-to-date; relying on manual updates and communication for a system like this would be a surefire way for it to quickly get out-of-date, messy, and to start to diverge between different platforms. &lt;/p&gt;

&lt;p&gt;With this system, we simply run the integration any time colors change in Figma (which is our “source of truth” for all things color). Then developers immediately get access to the latest and greatest colors. &lt;/p&gt;

&lt;p&gt;But the technical specificities here are less important than the fact that the philosophy and the language around colors are shared between designers and developers. This system gives us a shared language for talking about colors, and empowers everyone on the team to pick the right color for the job. &lt;/p&gt;

&lt;h4&gt;
  
  
  Questions? Comments? Get in touch!
&lt;/h4&gt;

&lt;p&gt;That’s all for our series on how we built a semantic color system for designers and developers at YNAB! Feel free to reach out if you have any questions or suggestions. Our hope is that this system can be as useful to other teams as it has been to us! &lt;/p&gt;

</description>
      <category>design</category>
    </item>
    <item>
      <title>The Practice: Semantic Colors for Designers</title>
      <dc:creator>Emily Carlin</dc:creator>
      <pubDate>Wed, 12 Feb 2020 19:58:24 +0000</pubDate>
      <link>https://dev.to/ynab/semantic-colors-for-designers-2lf2</link>
      <guid>https://dev.to/ynab/semantic-colors-for-designers-2lf2</guid>
      <description>&lt;p&gt;In this post, we’ll cover how the semantic color approach we described in the &lt;a href="https://dev.to/ynab/a-semantic-color-system-the-theory-hk7"&gt;first post&lt;/a&gt; works for designers, in practice. &lt;/p&gt;

&lt;h3&gt;
  
  
  Setting colors up in the design system
&lt;/h3&gt;

&lt;p&gt;Our team’s design tool of choice is Figma, but most of what we describe here could also be accomplished in Sketch (and perhaps other design tools). &lt;/p&gt;

&lt;p&gt;Out of the box, Figma only supports one layer of abstraction for colors. You define a style, and that’s that. Here’s how we set things up to support our additional layer of abstraction:&lt;/p&gt;

&lt;p&gt;First, we create a file in our &lt;code&gt;Design System&lt;/code&gt; project called &lt;code&gt;Colors&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;On one page, we set up our base palette. These base palette colors constitute each and every color that can possibly appear in our apps. We make these colors private to the file by prepending a &lt;code&gt;.&lt;/code&gt;to the style name. That way, the base palette colors won’t even appear when we publish the color file as a library. &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%2Fqg1wo3sqri41iu919otp.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%2Fqg1wo3sqri41iu919otp.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On a new page, we define our semantic colors.&lt;/p&gt;

&lt;p&gt;For each semantic color style, we define one light mode version and one dark mode version. In theory, we could define as many as we’d like (maybe we want a “super dark” mode, etc.) &lt;/p&gt;

&lt;p&gt;We name these colors with the following convention: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Group Mode/Specific&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Groups&lt;/code&gt; are things like “Label” “Background” “Header” etc. Mode corresponds to whether the given color is for light or dark mode. And &lt;code&gt;Specific&lt;/code&gt; corresponds to the particular usage of the color within the group. This produces colors like:&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;The semantic color for primary actions, &lt;code&gt;Primary Action&lt;/code&gt; is defined with the styles &lt;code&gt;Primary Light/Action&lt;/code&gt; and &lt;code&gt;Primary Dark/Action&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;The semantic color for accents within headers, &lt;code&gt;Header Accent&lt;/code&gt; is defined with the styles &lt;code&gt;Header Light/Accent&lt;/code&gt; and &lt;code&gt;Header Dark/Accent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The semantic color for our default labels, &lt;code&gt;Label Default&lt;/code&gt; is defined as &lt;code&gt;Label Light/Default&lt;/code&gt; and &lt;code&gt;Label Dark/Default&lt;/code&gt;
&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;As you can see, the light/dark style variants of each of our semantic colors is where we have to hack our way past Figma’s single-layer concept of color. &lt;/p&gt;

&lt;p&gt;We further push Figma’s approach to color by denoting the base palette color that each semantic color references in the style’s description field. In the example below, you can see that &lt;code&gt;Primary Action&lt;/code&gt; points to &lt;code&gt;primary600&lt;/code&gt; in light mode and &lt;code&gt;primary500&lt;/code&gt; in dark mode. &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%2Fjlz5se0fjq6lnttewuox.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%2Fjlz5se0fjq6lnttewuox.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This description is what connects the semantic color to the base palette color, via a custom plugin that we wrote. Whenever we change our base palette colors, our plugin will automatically update the semantic colors for us, so that we never have to do anything manually.&lt;/p&gt;

&lt;p&gt;This description also comes in handy later when we export these colors from Figma to usable code — more on how that works in part 3, where we discuss how this system works for developers. &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%2Fairp0z7cfk5nf6t716ry.gif" 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%2Fairp0z7cfk5nf6t716ry.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Using the colors file as a library in other files
&lt;/h3&gt;

&lt;p&gt;When we publish the color file, designers have access to all of the semantic colors. &lt;/p&gt;

&lt;p&gt;Each and every color has a light mode and a dark mode variant that are in the same position and have the same name within the color inspector. &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%2Fdckxn41z77shfi4m8llu.gif" 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%2Fdckxn41z77shfi4m8llu.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So to get a dark mode version of a screen, you can simply toggle each color to use the dark mode variant. This means we don’t have to maintain different components for different modes — everything happens at the level of individual colors. &lt;/p&gt;

&lt;p&gt;To make this even easier for designers to use, we plan to build a plugin that automatically flips colors from light to dark (Brian Lovin at Github already &lt;a href="https://twitter.com/brian_lovin/status/1202787778246909953" rel="noopener noreferrer"&gt;built something that does exactly this&lt;/a&gt;, though it isn’t available for public use at this point). &lt;/p&gt;

&lt;p&gt;We also plan to make a plugin (or use one that someone else has made!) that allows for type-ahead search to make color selection more ergonomic. But for now, we’ve organized semantic colors alphabetically so that designers can quickly find what they’re looking for. &lt;/p&gt;

&lt;h3&gt;
  
  
  A flexible and efficient system
&lt;/h3&gt;

&lt;p&gt;That’s all there is to it — we build our semantic color file, include it in other files, and go forth and design! &lt;/p&gt;

&lt;h4&gt;
  
  
  Questions? Want to try out our plugins?
&lt;/h4&gt;

&lt;p&gt;If you have questions about how to set this system up for designers, please feel free to ask! There’s nothing “secret” about this and we’d love for something here to be useful to other designers. &lt;/p&gt;

&lt;p&gt;We plan to publish the “semantic color updater” plugin as well as the Figma integration that outputs code (more on that in the next section) — let us know if your team is interested in trying out early versions of either one of these. &lt;/p&gt;

&lt;p&gt;The next post covers how this system &lt;a href="https://dev.to/emilycarlin/the-practice-semantic-colors-for-developers-1o6g"&gt;works for developers&lt;/a&gt; — both in the code and in terms of collaboration with designers. &lt;/p&gt;

</description>
      <category>design</category>
    </item>
    <item>
      <title>The Theory: A Semantic Color System</title>
      <dc:creator>Emily Carlin</dc:creator>
      <pubDate>Wed, 12 Feb 2020 19:35:01 +0000</pubDate>
      <link>https://dev.to/ynab/a-semantic-color-system-the-theory-hk7</link>
      <guid>https://dev.to/ynab/a-semantic-color-system-the-theory-hk7</guid>
      <description>&lt;p&gt;This post is the first in a three-part series about how our team at &lt;a href="https://www.youneedabudget.com/" rel="noopener noreferrer"&gt;You Need a Budget&lt;/a&gt; (YNAB) thinks about color in our design system. We'll go over the principles of how our system works, what inspired us to build it, and why we're excited about it. &lt;/p&gt;

&lt;p&gt;The other posts cover how the system works for &lt;a href="https://dev.to/ynab/semantic-colors-for-designers-2lf2"&gt;designers&lt;/a&gt; and for &lt;a href="https://dev.to/emilycarlin/the-practice-semantic-colors-for-developers-1o6g"&gt;developers&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;Over the past few months, the team at YNAB revamped how we approach colors in our design system. &lt;/p&gt;

&lt;p&gt;Colors are deceptively simple. They are a foundational element of interfaces but all-too-frequently end up becoming a sprawling mess of inline definitions, different naming conventions across different platforms, confusion around when to use what color, and issues with updates when things change. And dark mode support, which is becoming the norm, introduces yet another dimension of complexity to colors. &lt;/p&gt;

&lt;p&gt;Our new system addresses these challenges head-on by using a combination of semantic naming and an additional “layer of abstraction” (more on what exactly this means later) in both our designs and in code. &lt;/p&gt;

&lt;p&gt;This series is all about what we might call the “form” of colors in our design system: How we structure the system and how it works for designers and developers. &lt;/p&gt;

&lt;p&gt;This series won’t cover the “content” of colors in our design system: Things like how we selected the actual color values we use, how we ensure adequate contrast, our color decisions in designing for dark mode, etc. &lt;/p&gt;

&lt;p&gt;Okay, let’s get into it! &lt;/p&gt;

&lt;h3&gt;
  
  
  What’s in a name?
&lt;/h3&gt;

&lt;p&gt;If you’re a designer or a developer, chances are you’ve seen the words “semantic” and “color” in the same sentence before. It usually refers to a way of naming colors based on how they are used as opposed to their hue. This is one of &lt;a href="https://css-tricks.com/what-do-you-name-color-variables/" rel="noopener noreferrer"&gt;many theories&lt;/a&gt; on the best way to name color. &lt;/p&gt;

&lt;p&gt;With a semantic name, you might name a color “destructive” or “negative” — something that connotes what the color means in your interface, as opposed to something like “red” (or even something more fun, like “tomato”). &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%2Fuf44ilf4qi6u1spp67po.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%2Fuf44ilf4qi6u1spp67po.png" alt="Three circles named with variations on "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Naming colors semantically has two benefits: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;b&gt;It helps designers and developers decide what color to use.&lt;/b&gt; Instead of needing to memorize or check documentation to decide what color to make a “delete” button, you simply grab the color that relates to destruction.&lt;/li&gt;

&lt;li&gt;
&lt;b&gt;It makes your color system more efficient and flexible.&lt;/b&gt; If you decide you want to update your primary color to be purple instead of blue, you simply update the value for the primary color (assuming you’re using color styles in a tool like Figma or Sketch and color variables in code). If the colors were named based on hue, you’d need to go change every single place the color is used from “blue” to “purple.” &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Our new approach to color introduces an additional layer of abstraction to address some of the problems that are left unsolved by simply naming each of your colors semantically. &lt;/p&gt;

&lt;h3&gt;
  
  
  The base palette
&lt;/h3&gt;

&lt;p&gt;A color palette is, of course, an integral piece of any design system. The palette represents the universe of possibility for color in an interface. &lt;/p&gt;

&lt;p&gt;A palette is a great start for building visually consistent apps — a defined set of colors mitigates the chance that a rogue hex value will sneak its way in. &lt;/p&gt;

&lt;p&gt;Here’s what our palette looks like at YNAB: &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%2Fysyyzhqaqmgxtzoy7kiv.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%2Fysyyzhqaqmgxtzoy7kiv.png" alt="A palette of different colors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each of the colors has a semantic name (e.g. &lt;code&gt;primary&lt;/code&gt;, &lt;code&gt;accent&lt;/code&gt;, etc.) as well as a number that corresponds to its lightness (e.g. &lt;code&gt;900&lt;/code&gt; for the darkest variants; &lt;code&gt;100&lt;/code&gt; for the lightest variants). But if we stopped here, a lot would still remain up for interpretation as far as when to use what color. And not in a good “&lt;em&gt;this leaves space for creativity!&lt;/em&gt;” way; more in a “&lt;em&gt;What primary color variant do we use for buttons again?&lt;/em&gt;” way. &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%2Fjtdnrxocsft300fov9g2.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%2Fjtdnrxocsft300fov9g2.png" alt="Laptop with thought bubble coming out that says "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The semantic colors
&lt;/h3&gt;

&lt;p&gt;Our semantic colors go further than simply naming colors based on the general realm of their usage. They are a second layer of abstraction that sits on top of the base palette. &lt;/p&gt;

&lt;p&gt;Our color system consists of two layers: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The base palette, which defines every possible color value in our app. &lt;/li&gt;
&lt;li&gt; The semantic palette, which defines colors based on how they are used. Each and every semantic color points to a color from the base palette. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, we have a semantic color for our primary action color and another one for the background of headers. Each of those semantic colors references a color from the base palette.&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%2Fmdogkwm5iod6dl57cy78.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%2Fmdogkwm5iod6dl57cy78.png" alt="Two different semantic colors pointing to two different palette colors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you may be thinking, “This seems like a bunch of extra work for something that we get for free with symbols/components.” And in the case of something like a button or a header, that may very well be true — when you design the primary button component, you pick a color from the palette and then others simply use that component in their designs without needing to think about the specific color. &lt;/p&gt;

&lt;p&gt;But as things get more complex, the benefits of this two-layer system become clear. &lt;/p&gt;

&lt;h3&gt;
  
  
  Visual Consistency
&lt;/h3&gt;

&lt;p&gt;YNAB is budgeting software, which means that we frequently use color as a visual signal for positive and negative account balances (we never rely only on color, but color and accessibility would be a whole separate post). &lt;/p&gt;

&lt;p&gt;For example, the budget view features “pills” that display the amount remaining in a given category of a user’s budget. There is also a bar at the top of the screen that displays overall budget status. &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%2Fyla1srg30v1bkuxg39z1.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%2Fyla1srg30v1bkuxg39z1.png" alt="Two interface elements that use the same color"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To keep things consistent, we want both of these elements to use the exact same color. That way, users can start to learn that when they see this particular red color, it always means the same thing — a negative balance!&lt;/p&gt;

&lt;p&gt;In our semantic color system, we name this color &lt;code&gt;statusNegative&lt;/code&gt; and set it to reference a color from our base palette. So if we want to update this color, we simply point it at a different palette color and &lt;strong&gt;the change propagates to all elements that are meant to convey a negative status.&lt;/strong&gt; And if we update a base palette color, the change will ripple through all of the semantic colors that reference that color (and then all of the elements that use those semantic colors). &lt;/p&gt;

&lt;p&gt;This is what we mean by introducing an additional layer of abstraction. Semantic colors act as an intermediary level of specificity, between the raw value of colors in the base palette and the usage of those colors in specific components.&lt;/p&gt;

&lt;p&gt;And here’s the best part: &lt;strong&gt;Semantic colors make it easy for designers to create new elements that are visually consistent with the rest of the app.&lt;/strong&gt; If we wanted to create a graph on a dashboard that is in a negative state, we’d simply drop in &lt;code&gt;statusNegative&lt;/code&gt; instead of arbitrarily searching through our red hues. &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%2Fr14dz44r5t3ven2nrz9t.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%2Fr14dz44r5t3ven2nrz9t.png" alt="Drake frowning at disparately colored elements and smiling at cohesively colored elements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Dark Mode
&lt;/h3&gt;

&lt;p&gt;Beyond visual consistency, a major benefit of this system is how easily it supports dark mode. In fact, adapting our apps to dark mode is what inspired this approach to color in the first place. &lt;/p&gt;

&lt;p&gt;Let’s consider the color we use for primary elements — &lt;code&gt;primaryAction&lt;/code&gt;. This color references &lt;code&gt;primary600&lt;/code&gt; from the base palette. &lt;/p&gt;

&lt;p&gt;Great. But what about dark mode? &lt;/p&gt;

&lt;p&gt;Well, &lt;b&gt;all we have to do is create an additional mapping for &lt;code&gt;primaryAction&lt;/code&gt;.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;For dark mode, we map it to &lt;code&gt;primary500&lt;/code&gt;, a lighter blue, because we want primary elements to “pop” more on dark backgrounds (like accessibility, choosing colors for dark mode could be a whole separate article. We won’t get into the specifics here, but check out &lt;a href="https://blog.superhuman.com/how-to-design-delightful-dark-themes-7b3da644ff1f" rel="noopener noreferrer"&gt;this article&lt;/a&gt; by the team at Superhuman for a great primer). &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%2F2jxvt0n6jq4wezdwvedt.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%2F2jxvt0n6jq4wezdwvedt.png" alt="One color mapping for light mode; another one for dark mode"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Each of our semantic colors points to two base palette colors: one for light mode and one for dark mode.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;That way, we can just apply a &lt;code&gt;primaryAction&lt;/code&gt; style to our buttons and the right palette variant will render based on the user’s mode. &lt;/p&gt;

&lt;p&gt;You may be thinking: “Why can’t you just define a dark mode variant of &lt;code&gt;primary600&lt;/code&gt;? This doesn’t work because there are some colors that should get darker in dark mode (think backgrounds) and some colors that should get lighter in dark mode (think labels and accents). &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%2Fcjgyqof8tg6jvkquiaju.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%2Fcjgyqof8tg6jvkquiaju.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Long story short ...
&lt;/h3&gt;

&lt;p&gt;The two-layer semantic approach to colors allows us to flexibly update colors, keep our app visually consistent, and efficiently design for dark mode. &lt;/p&gt;

&lt;p&gt;The next two posts in this series will cover the ins and outs of how this system actually works — for designers and for developers. &lt;/p&gt;

&lt;p&gt;Thanks to Alan Dennis (who came up with the structure of this approach) and the rest of the YNAB design and development teams for helping to bring this system to life. &lt;/p&gt;

&lt;p&gt; Additional thanks to Alan Dennis, Dylan Mason, and Tristan Harward for giving feedback on the first draft of this post. &lt;/p&gt;

</description>
      <category>design</category>
    </item>
    <item>
      <title>YNAB at KotlinConf 2019</title>
      <dc:creator>Brady Holt</dc:creator>
      <pubDate>Mon, 06 Jan 2020 14:38:07 +0000</pubDate>
      <link>https://dev.to/ynab/ynab-at-kotlinconf-2019-63k</link>
      <guid>https://dev.to/ynab/ynab-at-kotlinconf-2019-63k</guid>
      <description>&lt;p&gt;A few weeks ago some of the YNAB team attended &lt;a href="https://kotlinconf.com/"&gt;KotlinConf 2019&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We have been using Kotlin in our Android app for some time and are particularly interested in its &lt;a href="https://kotlinlang.org/docs/reference/multiplatform.html"&gt;multiplatform  capability&lt;/a&gt; as a way to share code across Android, iOS and the Web.&lt;/p&gt;

&lt;p&gt;After attending quite a few multiplatform focused sessions, chatting with folks at the conference, and discussing things as a team, we're planning to start experimenting with multiplatform usage across Android and iOS and then eventually on the Web.  There is significant potential here that we want to explore!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RR8Z00XE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bodic5e3wio5quifnb12.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RR8Z00XE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bodic5e3wio5quifnb12.jpg" alt="YNAB at KotlinConf 2019"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Left to Right: Kevin, Graham, Taylor, Jeff, Brady&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Elegant memory management with Kotlin and J2V8</title>
      <dc:creator>Graham Borland</dc:creator>
      <pubDate>Tue, 29 Oct 2019 17:22:52 +0000</pubDate>
      <link>https://dev.to/ynab/elegant-memory-management-with-kotlin-and-j2v8-38bp</link>
      <guid>https://dev.to/ynab/elegant-memory-management-with-kotlin-and-j2v8-38bp</guid>
      <description>&lt;p&gt;At &lt;a href="https://youneedabudget.com/"&gt;YNAB&lt;/a&gt; we have a cross-platform library written in TypeScript (compiled to JavaScript) which contains all of our shared business logic for Android, iOS and Web. &lt;/p&gt;

&lt;p&gt;On Android we use &lt;a href="https://github.com/eclipsesource/J2V8"&gt;J2V8&lt;/a&gt; as our bridge into the JavaScript world; it's a nice Java wrapper around &lt;a href="https://v8.dev/"&gt;Google's V8 JavaScript engine&lt;/a&gt;. It works beautifully, but one of the challenges it brings is memory management. It's so tricky that the J2V8 maintainers wrote &lt;a href="https://eclipsesource.com/blogs/2016/07/29/improved-memory-management-with-j2v8/"&gt;a blog post about it&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Because J2V8 bridges V8 and Java, three different memory models are in play. Both Java and JavaScript provide a managed memory model with their own GC. JNI / C++ which sits in the middle is completely unmanaged. This leads to a complex situation...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To cut a long story short, we have to explicitly release any JS objects we create in our Java/Kotlin code. &lt;/p&gt;

&lt;h2&gt;
  
  
  Remember to close the door
&lt;/h2&gt;

&lt;p&gt;We can release these objects manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// create a JS object&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;obj&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;V8Object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// do something with the object in JS land&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"someProperty"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;54321&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executeJSFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"someJSFunction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// now release it&lt;/span&gt;
&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;But it's a bit of a pain having to remember to call &lt;code&gt;close()&lt;/code&gt; for every object. &lt;code&gt;V8Object&lt;/code&gt; implements the &lt;code&gt;Closeable&lt;/code&gt; interface which means we can use Java's try-with-resources or Kotlin's &lt;code&gt;use { }&lt;/code&gt; to take care of cleanup where we only have a single object to deal with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;V8Object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v8&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
    &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"someProperty"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;54321&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executeJSFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"someJSFunction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&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;It gets hairy when we need to track multiple JS objects, though. To help, J2V8 provides a &lt;code&gt;MemoryManager&lt;/code&gt;. When we create one of these it starts tracking &lt;code&gt;V8Object&lt;/code&gt; allocations while it is open, and releasing the &lt;code&gt;MemoryManager&lt;/code&gt; causes all of those objects which were allocated during its lifetime to be released in turn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;manager&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MemoryManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v8&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;obj1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;V8Object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v8&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;obj2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;V8Object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"someProperty"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;54321&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executeJSFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"someJSFunction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;   &lt;span class="c1"&gt;// obj1 and obj2 are both released&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It would be nice if we could use try-with-resources or &lt;code&gt;use { }&lt;/code&gt; again here, to avoid the explicit call to &lt;code&gt;manager.release()&lt;/code&gt;, but &lt;code&gt;MemoryManager&lt;/code&gt; doesn't implement &lt;code&gt;Closeable&lt;/code&gt; so we can't.&lt;/p&gt;

&lt;h2&gt;
  
  
  An &lt;del&gt;elephant&lt;/del&gt; elegant solution
&lt;/h2&gt;

&lt;p&gt;What we can do, though, is add a helper function which wraps all the &lt;code&gt;MemoryManager&lt;/code&gt; stuff and provides a scope for allocating and safely cleaning up as many &lt;code&gt;V8Object&lt;/code&gt;s as we like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;V8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&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;scope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MemoryManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;release&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;It has to be &lt;code&gt;inline&lt;/code&gt; so that we don't interfere with any return value from the &lt;code&gt;body&lt;/code&gt; lambda. And making it an extension function on &lt;code&gt;V8&lt;/code&gt; gives us this concise and elegant syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;v8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;scope&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;obj1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;V8Object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v8&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;obj2&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;V8Object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;obj1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"someProperty"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;54321&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;obj2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executeJSFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"someJSFunction"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;   &lt;span class="c1"&gt;// obj1 and obj2 are both released&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Elephants never forget... and now, neither do we! This approach helps us to solve some of the memory-related pain points when mixing JavaScript and good old Java/Kotlin code, without too much boilerplate. We do have a keen eye on Kotlin multiplatform for the future, but our JavaScript shared library is serving us very nicely in the meantime.&lt;/p&gt;

&lt;p&gt;The code is available on &lt;a href="https://gist.github.com/GrahamBorland/f4b9e92ed0df2b0fbe2b1e8453c4f4ed"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Progressive Conversion of TypeScript Namespaces to Modules</title>
      <dc:creator>Brady Holt</dc:creator>
      <pubDate>Mon, 16 Sep 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/ynab/progressive-conversion-of-typescript-namespaces-to-modules-3f1j</link>
      <guid>https://dev.to/ynab/progressive-conversion-of-typescript-namespaces-to-modules-3f1j</guid>
      <description>&lt;p&gt;We love TypeScript at &lt;a href="https://youneedabudget.com"&gt;YNAB&lt;/a&gt;. One of our main modules is something we call the “Shared Library” and it is a quite large TypeScript project. Actually, it’s comprised of 3 library projects and 3 test projects. It’s big. And, it was initially written using TypeScript namespaces, before TypeScript had support for ES modules.&lt;/p&gt;

&lt;p&gt;We wanted to start converting this library over to using ES modules for the various benefits that gives including the ability to tree-shake and better development tooling. But, it became obvious we needed to find a &lt;em&gt;progressive&lt;/em&gt; way to do this because a few attempts at an all-or-nothing approach proved daunting. Thousands of errors and no simple or obvious way to automate the conversion.&lt;/p&gt;

&lt;p&gt;Guidance for progressively converting a project from namespaces to modules is slim. There is &lt;a href="https://github.com/Microsoft/TypeScript/issues/12473"&gt;this GitHub issue&lt;/a&gt; where some discuss approaches but there are still some gaps the approaches.&lt;/p&gt;

&lt;p&gt;To setup progressive migration, we ended up doing the following which has been working well for us.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;code&gt;"exclude": ["**/*.m.ts"]&lt;/code&gt; to the tsconfig.json file in the original global / namespace project. This allows you to create modules with .m.ts extention and keep the &lt;code&gt;outFile&lt;/code&gt; config.&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;tsconfig.module.json&lt;/code&gt; file adjacent to the main tsconfig.json file.&lt;/li&gt;
&lt;li&gt;Use a &lt;a href="https://www.typescriptlang.org/docs/handbook/project-references.html"&gt;project reference&lt;/a&gt; in the tsconfig.module.json file pointing to the namespace project: &lt;code&gt;"references": [{ "path": "./tsconfig.json" }]&lt;/code&gt;. This makes the global / namespace &lt;em&gt;types&lt;/em&gt; available from within the modules project. It doesn’t emit the code for this project but it tells TypeScript to assume these types will be available at runtime.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It looks like this:&lt;/p&gt;

&lt;h4&gt;
  
  
  tsconfig.json
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../dist/package.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"composite"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"**/*.ts"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"exclude"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"**/*.m.ts"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  tsconfig.module.json
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"esnext"&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./MyClass.m.ts"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"references"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./tsconfig.json"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With the above setup, you can create module files with the extension &lt;code&gt;.m.ts&lt;/code&gt; adjacent to the existing namespace files like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;- MyClass.ts​
- MyClass.m.ts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then, as &lt;a class="comment-mentioned-user" href="https://dev.to/danielrosenwasser"&gt;@danielrosenwasser&lt;/a&gt;
 &lt;a href="https://github.com/Microsoft/TypeScript/issues/12473#issuecomment-263374060"&gt;pointed out&lt;/a&gt;, you can use existing code from the namespaced code and wrap it in the module file. You can also just export it as is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;MyClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;my_namespace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MyClass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Since this setup is using ES modules, you can now use a bundler like webpack to prepare it for web consumption. In the following example, webpackwill be used with ts-loader. Notice ts-loader is configured to use the &lt;code&gt;tsconfig.module.json&lt;/code&gt; config file.&lt;/p&gt;

&lt;h4&gt;
  
  
  webpack.config.js
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/MyClass.m.ts&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
  &lt;span class="na"&gt;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
    &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
        &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;tsx&lt;/span&gt;&lt;span class="se"&gt;?&lt;/span&gt;&lt;span class="sr"&gt;$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
        &lt;span class="na"&gt;use&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
            &lt;span class="na"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ts-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
            &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
              &lt;span class="na"&gt;configFile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./tsconfig.module.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// Use the module project config!​&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bundle.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;​&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Finally, in your entry webpage, you can include a reference to the original namespace outFile and also the webpack bundle.&lt;/p&gt;

&lt;h4&gt;
  
  
  index.html
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;​
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"dist/package.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!-- outFile output from tsc --&amp;gt;&lt;/span&gt;​
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"dist/bundle.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt; &lt;span class="c"&gt;&amp;lt;!-- webpack bundle --&amp;gt;&lt;/span&gt;​
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once you’ve converted over all the namespaced source files to modules, you can remove the original namespace project and stop loading it.&lt;/p&gt;

&lt;p&gt;A more exhaustive example can be found in this repository: &lt;a href="https://github.com/bradymholt/ts-progressive-convert-namespace-modules"&gt;https://github.com/bradymholt/ts-progressive-convert-namespace-modules&lt;/a&gt;.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
