<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cheesecake Labs Blog | Category | Process</title>
	<atom:link href="https://blog-stg.cheesecakelabs.com/category/process/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Top web &#38; mobile app design and development company focused on reinventing collaborative development. We develop iOS, Android and Web applications in partnership with the best USA and worldwide companies.</description>
	<lastBuildDate>Fri, 01 Jul 2022 17:24:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.5</generator>

<image>
	<url>https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2022/06/cheesecake-labs-favicon-blue.png</url>
	<title>Cheesecake Labs Blog | Category | Process</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Storytelling your way to innovation</title>
		<link>https://blog-stg.cheesecakelabs.com/storytelling-way-innovation/</link>
		
		<dc:creator><![CDATA[Mayara Cristine Wandall]]></dc:creator>
		<pubDate>Mon, 06 Jul 2020 17:40:53 +0000</pubDate>
				<category><![CDATA[Business]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Process]]></category>
		<guid isPermaLink="false">https://blog-stg.cheesecakelabs.com/?p=6763/</guid>

					<description><![CDATA[<p>Innovation matters. It is determinant for organizational growth and consequently to the products that we are building. Having said that, when it comes down to exploring new opportunities that could lead us to innovation, the way we build and tell these stories can lead us to success (or not). But why isn&#8217;t that so easy? [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/storytelling-way-innovation/">Storytelling your way to innovation</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Innovation matters. It is determinant for organizational growth and consequently to the products that we are building.</p>
<p>Having said that, when it comes down to exploring new opportunities that could lead us to innovation, the way we build and tell these stories can lead us to success (or not). But why isn&#8217;t that so easy? Because we are programmed with many behavioral mechanisms that prevent us from acting. To briefly illustrate, one of these behavioral mechanisms is the so-called “negativity bias.”<span id="more-6763"></span></p>
<h2>Understanding our bias</h2>
<p>Essentially, this means that we are much more likely to focus on the dwell of something that’s gone wrong than on things that have gone well. This scenario has been built by our society and it is intrinsic to our collective unconscious. This is what kept us safe in prehistoric times when faced with situations of danger, but it is not what is going to make us succeed in welcoming new ideas, for example, <em>innovation</em>.</p>
<p>This also has a direct impact on our power to continue improving and bringing transformation to the organizations we&#8217;re a part of.</p>
<p><a href="https://www.amazon.com.br/Leading-Transformation-Charge-Companys-Future/dp/1633696545/ref=asc_df_1633696545/?tag=googleshopp00-20&amp;linkCode=df0&amp;hvadid=379712558847&amp;hvpos=1o1&amp;hvnetw=g&amp;hvrand=4085954201121950721&amp;hvpone=&amp;hvptwo=&amp;hvqmt=&amp;hvdev=c&amp;hvdvcmdl=&amp;hvlocint=&amp;hvlocphy=1001706&amp;hvtargid=pla-546334616382&amp;psc=1">Transformation is one of the most challenging things leaders face</a>. What I mean when I say transformation is mapping possibilities, possible futures that we can materialize, and then successfully overcoming any obstacles preventing us to achieve the desired goal. At Cheesecake Labs, transformation is undergoing, leading us to realign and improve everything constantly.</p>
<p>With that in mind, can we transform organizations and products without transforming people and the way they connect in order to build the future? That&#8217;s when storytelling comes to play.</p>
<h2>Where to start</h2>
<p>I always say that if you don&#8217;t know where to start, you should start with the stories. The stories you tell your colleagues, your leaders, yourself. A single-story carries one of the most amazing powers it can have: the power to transform.</p>
<p>These stories may answer meaningful (and strategic) questions: what are the other possibilities? What does the future look like? What problems are you trying to solve? What path makes more sense to pursue in order to reach the desired goal? I&#8217;m always asking myself: how can we write better stories together?</p>
<p>A single-story has the potential to explore new possible futures, explain the strategy required to get there, and attract other people to make it happen. Stories have the potential to motivate an organizational transformation, and that means innovation!</p>
<p>Effective storytellers can reach the golden spot to innovation: engage people to embark on this new idea/product/future, and all of this is done in a structured way.</p>
<h2>Essential elements of a strategic narrative</h2>
<p>I believe that a great story includes the human context (what will be done and by whom), the shared purpose (why do you want others to embrace this story with you?) and what makes the story unique (the desired outcome or the possible future that you envision). It is not only the outcome that makes a story unique but also the journey itself.</p>
<p>To illustrate how you can act hands-on, I&#8217;ve used Friends TV series episodes as an example because it is the greatest tv series in the whole world! You can also check this great <a href="https://www.amazon.com/Writing-Story-Dramatic-Nonfiction-Reference/dp/0452272955/ref=as_li_ss_tl?ie=UTF8&amp;qid=1453309714&amp;sr=8-1&amp;keywords=Writing+for+Story:+Craft+Secrets+of+Dramatic+Nonfiction&amp;linkCode=sl1&amp;tag=propoint-20&amp;linkId=2fcf40e30f19e9c5b215ddad80300747">book</a> as a reference as well as other frameworks.</p>
<h3>The Arc</h3>
<p>The narrative arc is a term that describes a story&#8217;s full progression. It visually evokes the idea that every story has a relatively calm beginning, a middle where tension, character conflict, and narrative momentum builds to a peak, and an end where the conflict is resolved.</p>
<p>You may already be familiar with one classic example of the story arc: a startup idea, a challenging beginning, reaching success. This may sound oversimplified, and it is. Adding complexity to a basic story arc is part of what differs one story from another, even when they’re ostensibly dealing with the same ideas.</p>
<p><img fetchpriority="high" decoding="async" class="aligncenter wp-image-6859 size-full" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2020/07/Screen-Shot-2020-06-29-at-11.07.00.png" alt="Pink background with colorful text boxes explaining a Friend’s series episode called “The One Where Ross Got High”. The image intends to illustrate the paragraph concept above, showing the episode’s timeline." width="1176" height="642" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2020/07/Screen-Shot-2020-06-29-at-11.07.00.png 1176w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2020/07/Screen-Shot-2020-06-29-at-11.07.00-768x419.png 768w" sizes="(max-width: 1176px) 100vw, 1176px" /></p>
<p>On a daily basis routine, this means I may engage my team in new projects using the arc narrative. First I give them specific information about our new partners, their interests and settings like: who and where are them? What do they feel about this product? How did they get to us? Having said that, I climb up the story with the wrinkles: what problem do they want to solve with this product? Which pains and frustrations do they have? With that in mind we can reach the climax with the team&#8217;s purpose on how they can help it and all the skills needed to deliver an excellent product. The falling action (resolution) is the part of the story we&#8217;ll write together.</p>
<h3>The Hero&#8217;s Journey</h3>
<p>Monomyth (also called the <a href="https://www.amazon.com.br/Heros-Journey-Campbell-Collected-English-ebook/dp/B07K5KBWGZ/ref=sr_1_4?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=2DK7EIWMQDNUB&amp;keywords=joseph+campbell+a+jornada+do+heroi&amp;qid=1589563973&amp;sprefix=joseph+campbell+%2Caps%2C273&amp;sr=8-4">hero’s journey</a>) first described by <a href="https://www.amazon.com.br/Heros-Journey-Campbell-Collected-English-ebook/dp/B07K5KBWGZ/ref=sr_1_4?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=2DK7EIWMQDNUB&amp;keywords=joseph+campbell+a+jornada+do+heroi&amp;qid=1589563973&amp;sprefix=joseph+campbell+%2Caps%2C273&amp;sr=8-4">Joseph Campbell</a> is a story structure found in many movies and tales across the world.</p>
<p><a href="https://en.wikipedia.org/wiki/Hero%27s_journey#/media/File:Heroesjourney.svg"><img decoding="async" class="aligncenter wp-image-6862 size-full" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2020/07/1_GKPgF0OehluqlFlD59RNCQ.jpeg" alt="White background with black illustration. The image illustrates the famous concept of &quot;The Hero's Journey', commonly used in fictional creations." width="401" height="423"></a></p>
<p>It’s an adventurous and challenging journey of a Hero, who moves from certainty to uncertainty and returns safely with reward. For this article&#8217;s point of interest, &#8220;hero&#8221; can be a disruptive idea that is born through uncertain conditions as we know it (this point in human history is a great example) but has the power to bring extraordinary and reliable results (reward).</p>
<p>As an example, I&#8217;m using one of Friends episode to illustrate the Hero&#8217;s Journey structure as follows:</p>
<p><img decoding="async" class="aligncenter wp-image-6860 size-full" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2020/07/Screen-Shot-2020-06-29-at-11.07.09.png" alt="A grey background with colorful text boxes and a timeline. The image illustrates the structure of the Hero's Journey, which are: common world; call to adventure; refusal of the call; meeting the mentor; tests, allies, enemies; approach to the goal; the ordeal; reward; the road back; ressurection; return." width="1186" height="658" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2020/07/Screen-Shot-2020-06-29-at-11.07.09.png 1186w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2020/07/Screen-Shot-2020-06-29-at-11.07.09-768x426.png 768w" sizes="(max-width: 1186px) 100vw, 1186px" /></p>
<p><img decoding="async" class="aligncenter wp-image-6861 size-full" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2020/07/Screen-Shot-2020-06-29-at-11.07.18.png" alt="A grey background with colorful text boxes and a timeline, using a Friend's series episode called &quot;The one with all the resolutions&quot;, as an exemple to illustrate the Hero's Journey concept." width="1190" height="646" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2020/07/Screen-Shot-2020-06-29-at-11.07.18.png 1190w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2020/07/Screen-Shot-2020-06-29-at-11.07.18-768x417.png 768w" sizes="(max-width: 1190px) 100vw, 1190px" /></p>
<h3>Science Fiction</h3>
<p>Science fiction is a great tool to inspire thinking about new and possible futures in addition to the impact of technology on human lives. Silicon Valley has a deep connection with Science Fiction (as an example, the book <a href="https://www.amazon.com.br/Fahrenheit-451-Ray-Bradbury/dp/8525052248/ref=sr_1_1?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;keywords=Fahrenheit+451&amp;qid=1589563774&amp;sr=8-1">Fahrenheit 451</a> written in 1953 inspired earbuds creation).</p>
<p>Imagine the future 5 to 10 years from now. Consider real-life problems using technology. Think about the stories behind it. Write about it. At this point, do not worry too much about <em><strong>how</strong></em> it’s all going to happen. Just take the time to think about the future. As described in &#8220;<a href="https://www.amazon.com.br/Leading-Transformation-Charge-Companys-Future/dp/1633696545">Leading Transformation</a>&#8220;, from this point forward, a multitude of options will present itself. Once that is achieved you will be able to write a strategic narrative about how the future could be. Use the arc or the hero journey (the user) with a dilemma (a real-life problem) and a resolution.</p>
<p>We may explore possible futures using the power of science fiction. Science fiction can be used as part of a product creation process. With Sci-fi, there are no boundaries. Out of the box thinking is not only allowed, but encouraged. We can create little scenarios or even larger dramas to integrate the product we&#8217;re building into a narrative that is engaging and aligned with the product&#8217;s purpose.</p>
<p>What is your setting (time)? The future, an alternative timeline or historical past that conflicts with historical background? Where does the story take place? Outer space, other worlds, or alternative versions of the earth? What are the narrative elements? A new technology, a new product, a new scientific principle or a new political system? These are some of the questions to start creating a Sci-fi narrative. Explore. Dream. Discover.</p>
<h2>Storytelling as a Project Manager</h2>
<p>I consider it crucial to question ourselves how we are telling the stories about our efforts towards innovation. We need to realize the power of stories and embrace the fact that it is determinant to our efforts to succeed.</p>
<p>Conversely, as a Project Manager at Cheesecake Labs, I&#8217;m constantly challenging myself considering the team&#8217;s unique perspectives in a positive manner, using these tools (science fiction, the hero&#8217;s journey, the arc) as I see fit. It is important to maintain a continuous conversation about the products that we are building &#8211; we are always trying to ask as well as answering the right questions together in order to build it meaningfully &#8211; truly adding value to our partner&#8217;s businesses and Cakers. We believe in the stories we&#8217;re writing while developing products, always keeping the drive to help build successful tech products that solve real-world problems.</p>
<p>Working together through the stories, the best way possible &#8211; this is how we bring innovation to the table.</p>
<h2>References</h2>
<p><a href="https://www.amazon.com.br/Fahrenheit-451-Ray-Bradbury/dp/8525052248/ref=sr_1_1?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;keywords=Fahrenheit+451&amp;qid=1589563774&amp;sr=8-1">Fahrenheit 451</a><br />
<a href="https://www.amazon.com.br/Leading-Transformation-Charge-Companys-Future/dp/1633696545">Leading Transformation</a><br />
<a href="https://www.amazon.com.br/Heros-Journey-Campbell-Collected-English-ebook/dp/B07K5KBWGZ/ref=sr_1_4?__mk_pt_BR=%C3%85M%C3%85%C5%BD%C3%95%C3%91&amp;crid=2DK7EIWMQDNUB&amp;keywords=joseph+campbell+a+jornada+do+heroi&amp;qid=1589563973&amp;sprefix=joseph+campbell+%2Caps%2C273&amp;sr=8-4">The hero’s journey</a></p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/storytelling-way-innovation/">Storytelling your way to innovation</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>An efficient way to structure React Native projects</title>
		<link>https://blog-stg.cheesecakelabs.com/efficient-way-structure-react-native-projects/</link>
					<comments>https://blog-stg.cheesecakelabs.com/efficient-way-structure-react-native-projects/#comments</comments>
		
		<dc:creator><![CDATA[Mayara Cristine Wandall]]></dc:creator>
		<pubDate>Mon, 16 Sep 2019 13:54:30 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Process]]></category>
		<category><![CDATA[development]]></category>
		<guid isPermaLink="false">https://blog-stg.cheesecakelabs.com/?p=6392/</guid>

					<description><![CDATA[<p>Let’s discuss a structure to start new projects or when you need to scale large projects.&#160;We will use React Native project structure as a basis for this architecture, but the concepts can be leveraged in projects using other frameworks. For the purpose of this post, I will use the following patterns and packages: &#8211; React [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/efficient-way-structure-react-native-projects/">An efficient way to structure React Native projects</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span style="font-weight: 400;">Let’s discuss a structure to start new projects or when you need to scale large projects.&nbsp;</span><span style="font-weight: 400;">We will use React Native project structure as a basis for this architecture, but the concepts can be leveraged in projects using other frameworks.</span><span id="more-6392"></span></p>
<p><span style="font-weight: 400;">For the purpose of this post, I will use the following patterns and packages:</span></p>
<p><span style="font-weight: 400;">&#8211; </span><a href="https://reactnavigation.org/"><span style="font-weight: 400;">React Navigation</span></a><span style="font-weight: 400;">: Routing and navigation for your <a href="https://blog-stg.cheesecakelabs.com/blog/react-native-examples-innovative-brands/">React Native apps</a>;</span></p>
<p><span style="font-weight: 400;">&#8211; </span><a href="https://github.com/axios/axios"><span style="font-weight: 400;">Axios</span></a><span style="font-weight: 400;">: Promise-based HTTP client for the browser and node.js.</span></p>
<p><span style="font-weight: 400;">Follow the required installation steps on </span><a href="https://facebook.github.io/react-native/docs/getting-started"><span style="font-weight: 400;">Getting Started · React Native</span></a><span style="font-weight: 400;">. After configuring the React Native CLI on your machine, verify if&nbsp; `react-native -v` is available on your terminal.</span></p>
<p><span style="font-weight: 400;">You should get a return similar to this:</span></p>
<pre class="language-swift"><code class="language-swift">$ react-native-cli: 2.0.1
$ react-native: n/a - not inside a React Native project directory</code></pre>
<p><span style="font-weight: 400;">So we can proceed to create our project.</span></p>
<p>Cheesecake Labs is the <a href="https://blog-stg.cheesecakelabs.com/blog/top-5-react-native-development-company/">top #5 React Native Development Company</a> and has delivered <a href="https://blog-stg.cheesecakelabs.com/blog/quality-assurance/">quality</a> cross-platform applications to a number of clients.</p>
<h2><span style="font-weight: 400;">Creating a project from Scratch</span></h2>
<p><img decoding="async" class="aligncenter size-full wp-image-6396" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/rn-from-scratch.png" alt="A page with 'Give it a try' written on the top. It has two steps: Run this and Read these." width="1150" height="418" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/rn-from-scratch.png 1150w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/rn-from-scratch-768x279.png 768w" sizes="(max-width: 1150px) 100vw, 1150px" /><br />
<span style="font-weight: 400;">Choose a directory of your choice to create our base project using the following command:</span></p>
<pre class="language-swift"><code class="language-swift">$ react-native init ReactNativeCklExample</code></pre>
<p><span style="font-weight: 400;"><br />
After the execution, you can access the directory using the </span><span style="font-weight: 400;">cd</span><span style="font-weight: 400;"> ReactNativeCklExample</span><span style="font-weight: 400;">. You will get a structure similar to this:</span></p>
<pre class="language-swift"><code class="language-swift">.
├── __tests__
│   ├── App-test.js
├── android
├── ios
├── node_modules
├── .buckconfig
├── .eslintrc.js
├── .flowconfig
├── .gitattributes
├── .gitignore
├── .prettierrc.js
├── .watchmanconfig
├── App.js
├── app.json
├── babel.config.js
├── index.js
├── metro.config.js
├── package.json
└── yarn.lock</code></pre>
<p>Some of the most popular mobile apps were built with the React Native framework. You probably have a few installed on your own smartphone. Here’s how the <a href="https://blog-stg.cheesecakelabs.com/blog/react-native-examples-innovative-brands/">world’s most innovative brands use React Native</a> (+5 great examples)</p>
<h2><span style="font-weight: 400;">Structuring the pillars</span></h2>
<figure id="attachment_6397" aria-describedby="caption-attachment-6397" style="width: 695px" class="wp-caption aligncenter"><img decoding="async" class="size-full wp-image-6397" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/Screen-Shot-2019-09-13-at-14.15.17.png" alt="A wall of colorful bricks like Lego." width="695" height="338"><figcaption id="caption-attachment-6397" class="wp-caption-text">Photo by Omar Flores</figcaption></figure>
<p><i></i><span style="font-weight: 400;">We will define a structure for our project to grow efficiently and make its maintenance easier.</span></p>
<p><span style="font-weight: 400;">Our first step will be to define the directory structure within `src` (Source). This directory will contain all major project files.</span></p>
<p><span style="font-weight: 400;">Let’s create the following initial structure for our project:</span></p>
<pre class="language-swift"><code class="language-swift">.
├── src
│   ├── assets
│   │  ├── fonts
│   │  ├── images
│   ├── components
│   │  ├── atoms
│   │  ├── molecules
│   │  ├── organisms
│   ├── navigations
│   ├── scenes
│   ├── styles
│   ├── utils
│   ├── index.js</code></pre>
<p><span style="font-weight: 400;">Right now you might be wondering why there are so many folders and files, but don’t worry, further on the post we&#8217;ll go over their purpose and how important each one of them is.</span><br />
<a href="https://content.cheesecakelabs.com/ebook-app-development"><img decoding="async" class="wp-image-7639 size-full aligncenter" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2021/06/ebook-app-value-guide-development-4.png" alt="" width="1930" height="926" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2021/06/ebook-app-value-guide-development-4.png 1930w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2021/06/ebook-app-value-guide-development-4-768x368.png 768w" sizes="(max-width: 1930px) 100vw, 1930px" /></a></p>
<h2><span style="font-weight: 400;">Enabling the use of the alias</span></h2>
<p><span style="font-weight: 400;">To simplify the require/import of paths in our project, we must configure directory aliases. So let&#8217;s install the following packages:</span></p>
<pre class="language-swift"><code class="language-swift">$ yarn add -D eslint-import-resolver-babel-module@^5.1.0 
eslint-plugin-import@^2.18.2 babel-plugin-module-resolver@^3.2.0</code></pre>
<p><span style="font-weight: 400;">After installing the dependencies, let’s configure the </span><b>.babelrc</b><span style="font-weight: 400;">:</span></p>
<p><b>.babelrc</b></p>
<pre class="language-swift"><code class="language-swift">{
  "plugins": [
    [
      "module-resolver",
      {
        "cwd": "babelrc",
        "root": ["./src"],
        "extensions": [".js", ".ios.js", ".android.js"],
        "alias": {
          "_assets": "./src/assets",
          "_components": "./src/components",
          "_atoms": "./src/components/atoms",
          "_molecules": "./src/components/molecules",
          "_organisms": "./src/components/organisms",
          "_navigations": "./src/navigations",
          "_scenes": "./src/scenes",
          "_services": "./src/services",
          "_styles": "./src/styles",
          "_utils": "./src/utils"
        }
      }
    ]
  ]
}</code></pre>
<p><span style="font-weight: 400;">Edit the </span><b>.eslintrc.js</b><span style="font-weight: 400;"> file to avoid lint errors when using the new alias:</span></p>
<p>&nbsp;</p>
<pre class="language-swift"><code class="language-swift">module.exports = {
  root: true,
  extends: '@react-native-community',
  plugins: ['import'],
  settings: {
    'import/resolver': {
      node: {
        paths: ['src'],
        alias: {
          _assets: './src/assets',
          _components: './src/components',
          _atoms: './src/components/atoms',
          _molecules: './src/components/molecules',
          _organisms: './src/components/organisms',
          _navigations: './src/navigations',
          _scenes: './src/scenes',
          _services: './src/services',
          _styles: './src/styles',
          _utils: './src/utils',
        },
      },
    },
  },
};</code></pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400;">Read more about alias setup at </span><a href="https://github.com/tleunen/babel-plugin-module-resolver#getting-started"><span style="font-weight: 400;">Babel Plugin Module Resolver</span></a><span style="font-weight: 400;">.</span></p>
<p><a href="https://blog-stg.cheesecakelabs.com/contact/"><img decoding="async" class="size-full wp-image-7260 aligncenter" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2021/03/Blog-banner-CTA.png" alt="" width="650" height="200"></a></p>
<h2><span style="font-weight: 400;">Enable editors to alias autocompletion</span></h2>
<p><span style="font-weight: 400;">Create the </span><b>jsconfig.json</b><span style="font-weight: 400;"> file and use the same alias that was defined in <strong>.babelrc</strong>. Check it out below:</span></p>
<pre class="language-swift"><code class="language-swift">{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "_assets": ["src/assets/*"],
      "_components": ["src/components/*"],
      "_atoms": ["src/components/atoms/*"],
      "_molecules": ["src/components/molecules/*"],
      "_organisms": ["src/components/organisms/*"],
      "_navigations": ["src/navigations/*"],
      "_scenes": ["src/scenes/*"],
      "_services": ["src/services/*"],
      "_styles": ["src/styles/*"],
      "_utils": ["src/utils/*"]
    }
  }
}</code></pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400;">Once you have edited it, it’s time to test the alias. Let’s edit our `src/index.js` file by adding a test component as follows:</span></p>
<p>&nbsp;</p>
<pre class="language-swift"><code class="language-swift">import React from 'react';
import {View,Text} from 'react-native';

const App = () =&gt; (
  &lt;View&gt;
    &lt;Text&gt;Hello World&lt;/Text&gt;
  &lt;/View&gt;
);

export default App;</code></pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400;">Now in our </span><b>index.js</b><span style="font-weight: 400;"> in the project root we will import the <strong>App</strong> component as follows:</span></p>
<pre class="language-swift"><code class="language-swift">import App from './src';</code></pre>
<p><span style="font-weight: 400;">This way you will have your alias set up working on your project. \o/</span></p>
<h2><span style="font-weight: 400;">Atomic Components</span></h2>
<figure id="attachment_6401" aria-describedby="caption-attachment-6401" style="width: 1024px" class="wp-caption aligncenter"><img decoding="async" class="size-full wp-image-6401" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/atomic-design-process.png" alt="5 icons representing atoms, molecules, organisms, templates and pages." width="1024" height="768" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/atomic-design-process.png 1024w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/atomic-design-process-768x576.png 768w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption id="caption-attachment-6401" class="wp-caption-text">Illustration by Brad Frost</figcaption></figure>
<p><span style="font-weight: 400;">For a better understanding of atomic system/components I indicate the reading</span></p>
<p><a href="https://blog-stg.cheesecakelabs.com/blog/atomic-design-react/"><span style="font-weight: 400;">Atomic Design with React</span></a><span style="font-weight: 400;">.</span></p>
<p><span style="font-weight: 400;">We will not dive into the concepts of atomic, only the organization we have chosen to use in this project.</span><span style="font-weight: 400;">&nbsp;</span></p>
<p><span style="font-weight: 400;">&#8211; Atoms &#8211; The smallest possible components, such as buttons, titles, inputs or event color pallets, animations, and fonts.</span></p>
<p><span style="font-weight: 400;">&#8211; Molecules &#8211; They are the composition of one or more components of atoms.</span></p>
<p><span style="font-weight: 400;">&#8211; Organisms &#8211; The combination of molecules that work together or even with atoms that compose more elaborate interfaces.</span></p>
<p><span style="font-weight: 400;">Remembering the directories we use to organize your components:</span></p>
<pre class="language-swift"><code class="language-swift">.
├── src
│   ├── components
│   │  ├── atoms
│   │  ├── molecules
│   │  ├── organisms</code></pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400;">In each component directory, we have an <strong>index.js</strong> file that exports the specified category.</span></p>
<p><span style="font-weight: 400;">Let’s create a component called </span><b>HelloWorld</b><span style="font-weight: 400;"> in </span><b>src/atoms</b><span style="font-weight: 400;"> to understand the idea:</span></p>
<p><b>src/atoms/hello-world.js</b></p>
<pre class="language-swift"><code class="language-swift">import React from 'react';
import {Text} from 'react-native';

const HelloWorld = ({name}) =&gt; &lt;Text&gt;Hello World {name}!&lt;/Text&gt;;

export default HelloWorld;</code></pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400;">We export as follows:&nbsp;</span></p>
<p><b>src/atoms/index.js</b></p>
<pre class="language-swift"><code class="language-swift">export {default as HelloWorld} from './hello-world';</code></pre>
<p><span style="font-weight: 400;">Now we can use this component in </span><b>src/index.js</b><span style="font-weight: 400;">:</span></p>
<pre class="language-swift"><code class="language-swift">import React from 'react';
import {HelloWorld} from '_atoms'; 

const App = () =&gt; &lt;</code>HelloWorld name="Helder Burato Berto" /&gt;;</pre>
<pre class="language-swift">export default App;</pre>
<p><i><span style="font-weight: 400;">Note: The App.js in the project root can be removed, it will no longer be used.</span></i></p>
<h2><span style="font-weight: 400;">Our Scenes</span></h2>
<p><span style="font-weight: 400;">I have a habit of dividing every application screen as a scene and so each one has its directory.</span></p>
<p><span style="font-weight: 400;">We will define some scenes that will not be used this time, and then we will configure these navigations using the created screens.</span></p>
<pre class="language-swift"><code class="language-swift">.
├── src
│   ├── scenes
│   │  ├── login
│   │  │	 ├── index.js // LoginScreen
│   │  ├── home
│   │  │	 ├── index.js // HomeScreen
│   │  ├── about
│   │  │	 ├── index.js // AboutScreen</code></pre>
<p><span style="font-weight: 400;">At the </span><b>Login</b><span style="font-weight: 400;"> screen, we will add a navigation button to go to the </span><b>Home</b><span style="font-weight: 400;"> screen. See below:</span></p>
<pre class="language-swift"><code class="language-swift">import React from 'react';
import {SafeAreaView, Text, TouchableHighlight} from 'react-native';

const LoginScreen = ({navigation}) =&gt; (
  &lt;SafeAreaView&gt;
    &lt;Text&gt;Screen: Login&lt;/Text&gt;

    &lt;TouchableHighlight onPress={() =&gt; navigation.navigate('Home')}&gt;
      &lt;Text&gt;Go to home&lt;/Text&gt;
    &lt;/TouchableHighlight&gt;
  &lt;/SafeAreaView&gt;
);

export default LoginScreen;</code></pre>
<p><i><span style="font-weight: 400;">Note: The navigation object will be available on all screens that are surrounded by the navigator object.</span></i></p>
<h2><span style="font-weight: 400;">Ways of Navigation</span></h2>
<figure id="attachment_6406" aria-describedby="caption-attachment-6406" style="width: 1024px" class="wp-caption aligncenter"><img decoding="async" class="size-full wp-image-6406" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/unnamed-1.png" alt="Picture of the point of view of the bow region of a boat." width="1024" height="682" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/unnamed-1.png 1024w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/unnamed-1-768x512.png 768w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption id="caption-attachment-6406" class="wp-caption-text">Photo by Joseph Barrientos</figcaption></figure>
<p><span style="font-weight: 400;">In this step, we will need to add some new dependencies to the project. See below:</span></p>
<pre class="language-swift"><code class="language-swift">$ yarn add react-navigation@^4.0.0 react-navigation-stack@^1.5.3 
react-navigation-tabs@^2.4.0 react-native-gesture-handler@^1.4.1 
react-native-reanimated@^1.2.0</code></pre>
<p><span style="font-weight: 400;">You can read more about it </span><a href="https://reactnavigation.org/docs/en/getting-started.html"><span style="font-weight: 400;">here</span></a><span style="font-weight: 400;">.</span></p>
<p><span style="font-weight: 400;">In our application, we will have two types of navigation.</span></p>
<p><span style="font-weight: 400;">In the </span><b>Login</b><span style="font-weight: 400;"> screen, we will have </span><b>Stack</b><span style="font-weight: 400;"> navigation type and in the rest of the app we will have </span><b>Tab</b><span style="font-weight: 400;"> navigation type.</span></p>
<p><i><span style="font-weight: 400;">Note: This is just an example of navigation, not a pattern. If you need to use other types of navigation, you can create them at the src/navigations.</span></i></p>
<p><span style="font-weight: 400;">In the </span><b>src/navigations</b><span style="font-weight: 400;"> directory we will define the following structure:</span></p>
<pre class="language-swift"><code class="language-swift">.
├── src
│   ├── navigations
│   │  ├── index.js            // RootNavigator
│   │  ├── auth-navigator.js   // AuthNavigator
│   │  ├── app-navigator.js    // AppNavigator</code></pre>
<p>&nbsp;</p>
<ol>
<li><span style="font-weight: 400;"> In the </span><b>auth-navigator.js</b><span style="font-weight: 400;"> we will define the navigation type for the login screen:</span></li>
</ol>
<pre class="language-swift"><code class="language-swift">import {createStackNavigator} from 'react-navigation-stack';

import LoginScreen from '_scenes/login';

const AuthNavigatorConfig = {
  initialRouteName: 'Login',
  header: null,
  headerMode: 'none',
};

const RouteConfigs = {
  Login:LoginScreen,
};

const AuthNavigator = createStackNavigator(RouteConfigs, AuthNavigatorConfig);

export default AuthNavigator;</code></pre>
<p>&nbsp;</p>
<ol start="2">
<li><span style="font-weight: 400;"> In the </span><b>app-navigator.js</b><span style="font-weight: 400;"> we will define the type of navigation to internal screens app:</span></li>
</ol>
<pre class="language-swift"><code class="language-swift">import {createBottomTabNavigator} from 'react-navigation-tabs';

import HomeScreen from '_scenes/home';
import AboutScreen from '_scenes/about';

const TabNavigatorConfig = {
  initialRouteName: 'Home',
  header: null,
  headerMode: 'none',
};

const RouteConfigs = {
  Home:{
    screen:HomeScreen,
  },
  About:{
    screen:AboutScreen,
  },
};

const AppNavigator = createBottomTabNavigator(RouteConfigs, TabNavigatorConfig);

export default AppNavigator;</code></pre>
<p>&nbsp;</p>
<ol start="3">
<li><span style="font-weight: 400;"> In the </span><b>index.js</b><span style="font-weight: 400;"> we will define our </span><b>RootNavigator</b><span style="font-weight: 400;"> merging the auth and app navigators:</span></li>
</ol>
<pre class="language-swift"><code class="language-swift">import {createAppContainer, createSwitchNavigator} from 'react-navigation';

import AuthNavigator from './auth-navigator';
import AppNavigator from './app-navigator';

const RootNavigator = createSwitchNavigator(
  {
    Auth: AuthNavigator,
    App: AppNavigator,
  },
  {
    initialRouteName: 'Auth',
  },
);

export default createAppContainer(RootNavigator);</code></pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400;">Now you can import the </span><b>Navigator</b><span style="font-weight: 400;"> object into your </span><b>src/index.js</b><span style="font-weight: 400;"> as follows:</span></p>
<p>&nbsp;</p>
<pre class="language-swift"><code class="language-swift">import React from 'react';

import Navigator from '_navigations';

const App = () =&gt; &lt;Navigator /&gt;;

export default App;</code></pre>
<p><span style="font-weight: 400;">This way you will have simple and functional navigation.</span></p>
<h2><span style="font-weight: 400;">Reusable Services</span></h2>
<p><span style="font-weight: 400;">Not everything can be considered a component in React Native, a well-known approach used to create separate modules and in some cases containing business rules are the use of services.</span></p>
<p><span style="font-weight: 400;">Directory for creating services:</span></p>
<p><b>src/services</b></p>
<p><span style="font-weight: 400;">They can be shared with multiple screens and components in your project.</span></p>
<p><span style="font-weight: 400;">Commonly used to create services that make contact with external APIs and use the </span><b>axios</b><span style="font-weight: 400;"> library that we mentioned at the beginning of the post.</span></p>
<h2><span style="font-weight: 400;">Shared Styles</span></h2>
<figure id="attachment_6409" aria-describedby="caption-attachment-6409" style="width: 1199px" class="wp-caption aligncenter"><img decoding="async" class="size-full wp-image-6409" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/Screen-Shot-2019-09-16-at-10.19.25-AM.png" alt="A yellow ball bouncing from between brackets to between parenthesis. " width="1199" height="599" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/Screen-Shot-2019-09-16-at-10.19.25-AM.png 1199w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/09/Screen-Shot-2019-09-16-at-10.19.25-AM-768x384.png 768w" sizes="(max-width: 1199px) 100vw, 1199px" /><figcaption id="caption-attachment-6409" class="wp-caption-text">Illustration by Dominic Magnifico</figcaption></figure>
<p><span style="font-weight: 400;">Based in </span><a href="https://developer.mozilla.org/en-US/docs/Glossary/CSS_preprocessor"><span style="font-weight: 400;">CSS preprocessor</span></a><span style="font-weight: 400;"> we use some default files in our style structure:</span></p>
<p>&nbsp;</p>
<pre class="language-swift"><code class="language-swift">.
├── src
│   ├── styles
│   │  ├── index.js        // Export all          
│   │  ├── colors.js       // Colors pallet
│   │  ├── mixins.js       // Mixins to use CSSinJS
│   │  ├── spacing.js      // Paddings, margins and scale
│   │  ├── typography.js   // Fonts types and sizes</code></pre>
<p>&nbsp;</p>
<p><b>index.js</b></p>
<pre class="language-swift"><code class="language-swift">
import * as Colors from './colors';
import * as Spacing from './spacing';
import * as Typography from './typography';
import * as Mixins from './mixins';

export { Typography, Spacing, Colors, Mixins };</code></pre>
<p>&nbsp;</p>
<p><b>colors.js</b></p>
<pre class="language-swift"><code class="language-swift">
export const PRIMARY = '#1779ba';
export const SECONDARY = '#767676';
export const WHITE = '#FFFFFF';
export const BLACK = '#000000';

// ACTIONS
export const SUCCESS = '#3adb76';
export const WARNING = '#ffae00';
export const ALERT = '#cc4b37';

// GRAYSCALE
export const GRAY_LIGHT = '#e6e6e6';
export const GRAY_MEDIUM = '#cacaca';
export const GRAY_DARK = '#8a8a8a';</code></pre>
<p>&nbsp;</p>
<p><b>mixins.js</b></p>
<pre class="language-swift"><code class="language-swift">import {Dimensions,PixelRatio} from 'react-native';</code></pre>
<pre>const WINDOW_WIDTH = Dimensions.get('window').width;
const guidelineBaseWidth = 375;

export const scaleSize = size =&gt; (WINDOW_WIDTH/guidelineBaseWidth) * size;

export const scaleFont = size =&gt; size * PixelRatio.getFontScale();

function dimensions(top, right = top, bottom = top, left = right, property){
  let styles = {};

  styles[`${property}Top`] = top;
  styles[`${property}Right`] = right;
  styles[`${property}Bottom`] = bottom;
  styles[`${property}Left`] = left;

  return styles;
}

export function margin(top, right, bottom, left){
  return dimensions(top, right, bottom, left, 'margin');
}

export function padding(top, right, bottom, left){
  return dimensions(top, right, bottom, left, 'padding');
}

export function boxShadow(color, offset = {height:2,width:2},
                           radius = 8, opacity = 0.2){
  return {
    shadowColor: color,
    shadowOffset: offset,
    shadowOpacity: opacity,
    shadowRadius: radius,
    elevation: radius,
  };
}</pre>
<p>&nbsp;</p>
<p><b>spacing.js</b></p>
<pre class="language-swift"><code class="language-swift">
import {scaleSize} from './mixins';

export const SCALE_18 = scaleSize(18);
export const SCALE_16 = scaleSize(16);
export const SCALE_12 = scaleSize(12);
export const SCALE_8 = scaleSize(8);</code></pre>
<p>&nbsp;</p>
<p><b>typography.js</b></p>
<pre class="language-swift"><code class="language-swift">
import { scaleFont } from './mixins';

// FONT FAMILY
export const FONT_FAMILY_REGULAR = 'OpenSans-Regular';
export const FONT_FAMILY_BOLD = 'OpenSans-Bold';

// FONT WEIGHT
export const FONT_WEIGHT_REGULAR = '400';
export const FONT_WEIGHT_BOLD = '700';

// FONT SIZE
export const FONT_SIZE_16 = scaleFont(16);
export const FONT_SIZE_14 = scaleFont(14);
export const FONT_SIZE_12 = scaleFont(12);

// LINE HEIGHT
export const LINE_HEIGHT_24 = scaleFont(24);
export const LINE_HEIGHT_20 = scaleFont(20);
export const LINE_HEIGHT_16 = scaleFont(16);

// FONT STYLE
export const FONT_REGULAR = {
  fontFamily: FONT_FAMILY_REGULAR,
  fontWeight: FONT_WEIGHT_REGULAR,
};

export const FONT_BOLD = {
  fontFamily: FONT_FAMILY_BOLD,
  fontWeight: FONT_WEIGHT_BOLD,
};</code></pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400;">This is our basic style settings to structure our application.</span></p>
<p><span style="font-weight: 400;">This way you can import into any of your components the following <strong>Typography, Spacing, Colors, Mixins</strong> objects, which will have access to the functionality of each style object.</span></p>
<h3><span style="font-weight: 400;">Extra: Custom Font</span></h3>
<p><span style="font-weight: 400;">To enable custom fonts you need to create the <strong>react-native.config.js</strong> in the project root and set the directory where your </span><b>.ttf</b><span style="font-weight: 400;"> files are as follows:</span></p>
<p>&nbsp;</p>
<pre class="language-swift"><code class="language-swift">
module.exports = {
  assets:['./src/assets/fonts/'],
};</code></pre>
<p>&nbsp;</p>
<p><span style="font-weight: 400;">After that, you should run the `react-native link` to link your fonts to the iOS / Android native code.</span></p>
<h2><span style="font-weight: 400;">Defining Utils</span></h2>
<p><span style="font-weight: 400;">We have the </span><b>src/utils</b><span style="font-weight: 400;"> directory where we add all our utility/helper methods that can be shared across our entire project.</span></p>
<p><span style="font-weight: 400;">Whenever you come across situations where you get caught repeating code is a good situation to create a util/helper.</span></p>
<h2><span style="font-weight: 400;">Wrapping up</span></h2>
<p><span style="font-weight: 400;">I have been working with this format on the last React Native projects I worked on and I can say that it helped me a lot regarding the organization and <a href="https://blog-stg.cheesecakelabs.com/blog/building-app-phase-3-product-development/">development</a> of the project.</span></p>
<p><span style="font-weight: 400;">This is just one way we found to be productive and better organized among our team, I hope it helps you too.</span></p>
<p><span style="font-weight: 400;">Feel free to comment below if you have any questions, I’ll be happy to help you.</span></p>
<p><span style="font-weight: 400;">Enjoy programming!</span></p>
<p><span style="font-weight: 400;">The repository of this example is available at </span><a href="https://github.com/CheesecakeLabs/ReactNativeCklExample"><span style="font-weight: 400;">ReactNativeCklExample</span></a><span style="font-weight: 400;">.</span></p>
<h2><span style="font-weight: 400;">References</span></h2>
<p><span style="font-weight: 400;">&#8211; </span><a href="https://medium.com/@alexmngn/why-react-developers-should-modularize-their-applications-d26d381854c1"><span style="font-weight: 400;">Why React developers should modularize their applications?</span></a></p>
<p><span style="font-weight: 400;">&#8211; </span><a href="https://medium.com/@alexmngn/how-to-better-organize-your-react-applications-2fd3ea1920f1"><span style="font-weight: 400;">How to better organize your React applications?</span></a></p>
<p><span style="font-weight: 400;">&#8211; </span><a href="https://medium.com/the-andela-way/how-to-structure-a-react-native-app-for-scale-a29194cd33fc"><span style="font-weight: 400;">How To Structure a React Native App For Scale</span></a></p>
<p><span style="font-weight: 400;">&#8211; </span><a href="https://www.freecodecamp.org/news/how-to-structure-your-project-and-manage-static-resources-in-react-native-6f4cfc947d92/"><span style="font-weight: 400;">How to structure your project and manage static resources in React Native</span></a></p>
<p><a href="https://blog-stg.cheesecakelabs.com/contact/"><img decoding="async" class="size-full wp-image-7260 aligncenter" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2021/03/Blog-banner-CTA.png" alt="" width="650" height="200"></a></p>
<div id="gtx-trans"></div>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/efficient-way-structure-react-native-projects/">An efficient way to structure React Native projects</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog-stg.cheesecakelabs.com/efficient-way-structure-react-native-projects/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Understanding when and how Android Views have dimensions set</title>
		<link>https://blog-stg.cheesecakelabs.com/understanding-android-views-dimensions-set/</link>
					<comments>https://blog-stg.cheesecakelabs.com/understanding-android-views-dimensions-set/#respond</comments>
		
		<dc:creator><![CDATA[Mayara Cristine Wandall]]></dc:creator>
		<pubDate>Thu, 08 Aug 2019 20:44:22 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Process]]></category>
		<category><![CDATA[mobile development]]></category>
		<guid isPermaLink="false">https://blog-stg.cheesecakelabs.com/?p=6345/</guid>

					<description><![CDATA[<p>I believe that almost every Android dev has at least once tried to get a View’s dimension, but it returned 0, nada. This is a very common situation, it is one of those problems that we just Google for a solution and find a workaround that seems to work. We add it to the code [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/understanding-android-views-dimensions-set/">Understanding when and how Android Views have dimensions set</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span style="font-weight: 400;">I believe that almost every Android dev has at least once tried to get a View’s dimension, but it returned 0, </span><i><span style="font-weight: 400;">nada</span></i><span style="font-weight: 400;">. This is a very common situation, it is one of those problems that we just Google for a solution and find a workaround that seems to work. We add it to the code without having much idea of what’s going on and that’s it. In this article I’ll explain why this happens and why many of the most used workarounds should be avoided. In the end, I’ll give you a very sweet solution about Android views.</span></p>
<p><span id="more-6345"></span></p>
<h1><span style="font-weight: 400;">Views dimension in Activity lifecycle&nbsp;</span></h1>
<p><span style="font-weight: 400;">One of the very basic Android concepts that we first learn is the Activity lifecycle. We understand that the </span><span style="font-weight: 400;">onCreate()</span><span style="font-weight: 400;"> callback is where the UI should be declared and configured. Having this in mind, let’s say we have a View that for some reason needs a manual setup like this:</span></p>
<pre class="language-swift"><code class="language-swift">myView.layoutParams.width = myView.width / 2</code></pre>
<p><span style="font-weight: 400;">This sets </span><span style="font-weight: 400;">myView</span><span style="font-weight: 400;"> width based on its own width, this means that this code should run only once. You add it inside </span><span style="font-weight: 400;">onCreate()</span><span style="font-weight: 400;"> right after setting content view, run the application but it doesn’t work as expected. </span><span style="font-weight: 400;">myView</span><span style="font-weight: 400;"> had a width of zero and then your code just divided 0 by 2. So you think, maybe the view will be laid out in </span><span style="font-weight: 400;">onStart()</span><span style="font-weight: 400;">. You test it and again it doesn’t work. Maybe </span><span style="font-weight: 400;">onResume()</span><span style="font-weight: 400;"> will work? Wait&#8230; what?! </span><span style="font-weight: 400;">onResume</span><span style="font-weight: 400;"> doesn’t work either?! The next lifecycle step should be when the Activity is already running and you are still unable to finish the UI setup. What else can we do?</span></p>
<p><img decoding="async" class="aligncenter wp-image-6356" src="https://s3.amazonaws.com/ckl-website-static/wp-content/uploads/2019/08/meme-nazare-fotoreproducao-via-google_2094781-e1565296766341.jpg" alt="A meme of a blond woman thinking with some formular drawn on her picture." width="420" height="238"></p>
<p><span style="font-weight: 400;">Ok, let’s be radical and try </span><a href="https://developer.android.com/reference/android/app/Activity#onWindowFocusChanged(boolean)"><span style="font-weight: 400;">onWindowsFocusChanged()</span></a><span style="font-weight: 400;">. </span><i><span style="font-weight: 400;">Voilà</span></i><span style="font-weight: 400;">, it works! You are happy and can go back to work. Suddenly your app goes to background and a phone call pops up, it’s your mom asking you to buy some bread on your way home. After the call ends, your app comes back to the foreground, as well as your frustration. </span><span style="font-weight: 400;">myView</span><span style="font-weight: 400;"> has now half the width that it should, and you realize that </span><span style="font-weight: 400;">onWindowsFocusChanged()</span><span style="font-weight: 400;"> was called again after the app came back to the foreground.&nbsp;</span></p>
<p><img decoding="async" class="aligncenter wp-image-6346 size-full" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/08/gifdiego1resized.gif" alt="Gif of Jim Carrey drinking a glass of water and spitting it out." width="280" height="304"></p>
<p><span style="font-weight: 400;">We now know that for some reason there isn’t a lifecycle callback for when the activity UI is fully laid out, which is something that some stacks provide for us, such as on iOS. So the question is, when is a view fully laid out and drawn?</span></p>
<h1><span style="font-weight: 400;">How Android draws the UI</span></h1>
<p><span style="font-weight: 400;">An Activity layout is drawn upon the view hierarchy. From the image below, you can see that this hierarchy is a tree with two different nodes &#8211; ViewGroup and View.</span></p>
<p><img decoding="async" class="alignnone size-full wp-image-6347 aligncenter" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/08/image-7.png" alt="View group's hierarchy picture." width="474" height="253"></p>
<p><span style="font-weight: 400;">ViewGroup is also a View, but it is a layout or container that can contain many children. Examples of ViewGroups are LinearLayout and ConstraintLayout. View is any other UI component.&nbsp;</span></p>
<p><span style="font-weight: 400;">Each View has two different types of sizes: the measured width and height, which is basically how big it wants to be, and the width and height that are the actual dimensions they have after being laid out. The desired size cannot always be provided, e.g. a view could request a width larger than its parent’s width.&nbsp;</span></p>
<p><span style="font-weight: 400;">Both measured and actual sizes are set in two steps:&nbsp;</span></p>
<ul>
<li style="font-weight: 400;"><b>Measure pass</b><span style="font-weight: 400;">: each View has a desired size &#8211; a measured dimension that is basically how big it wants to be. The measure pass is a process that starts from the root View Group and goes in a top-down transversal way setting the measured width and height of each View based on requirements passed from parent to children. Each View returns to its descendants the desired dimension. When this phase is over, every View has both measured width and height set.</span></li>
<li style="font-weight: 400;"><b>Layout pass</b><span style="font-weight: 400;">: also top-down transversal, each parent is responsible for positioning its children Views based on actual sizes, which are not always the measured sizes set on Measure pass &#8211; every View has a measured width and height.</span></li>
</ul>
<p><span style="font-weight: 400;">After the layout pass finishes, the layout can finally be drawn by the OS.&nbsp;</span></p>
<p><span style="font-weight: 400;">This is a very basic explanation, but it is enough to have an idea of how the draw process works. But when does it happen? The </span><a href="https://developer.android.com/guide/topics/ui/how-android-draws"><span style="font-weight: 400;">documentation</span></a><span style="font-weight: 400;"> states that it starts when the Activity receives focus, then let’s see it happening with a small code that I wrote.&nbsp;</span></p>
<p><span style="font-weight: 400;">The code has a custom LinearLayout and TextView which I created just to override </span><span style="font-weight: 400;">onMeasure()</span><span style="font-weight: 400;">, </span><span style="font-weight: 400;">onLayout()</span><span style="font-weight: 400;">/</span><span style="font-weight: 400;">layout()</span><span style="font-weight: 400;"> and </span><span style="font-weight: 400;">draw()</span><span style="font-weight: 400;"> functions and add some logs to them. You can check it out in this </span><a href="https://gist.github.com/diegohkd/06d35a67a4d16f18c60fb0785381704d"><span style="font-weight: 400;">Gist</span></a><span style="font-weight: 400;">.&nbsp;</span></p>
<p><span style="font-weight: 400;">Running it results in these logs:</span></p>
<pre><span style="font-weight: 400;">1 onCreate() executed</span>

<span style="font-weight: 400;">2 onStart() executed</span>

<span style="font-weight: 400;">3 onResume() executed</span>

<span style="font-weight: 400;">4 LinearLayout: entering onMeasure(). Measured width: 0</span>

<span style="font-weight: 400;">5 TextView: entering onMeasure(). Measured width: 0</span>

<span style="font-weight: 400;">6 TextView: leaving onMeasure(). Measured width: 171</span>

<span style="font-weight: 400;">7 LinearLayout: leaving onMeasure(). Measured width: 171</span>

<span style="font-weight: 400;">8 LinearLayout: entering onLayout(). Actual width: 171</span>

<span style="font-weight: 400;">9 TextView: entering layout(). Actual width: 0</span>

<span style="font-weight: 400;">10 TextView: leaving layout(). Actual width: 171</span>

<span style="font-weight: 400;">11 LinearLayout: leaving onLayout(). Actual width: 171</span>

<span style="font-weight: 400;">12 onWindowFocusChanged() executed</span>

<span style="font-weight: 400;">13 LinearLayout: entering onMeasure(). Measured width: 171</span>

<span style="font-weight: 400;">14 TextView: entering onMeasure(). Measured width: 171</span>

<span style="font-weight: 400;">15 TextView: leaving onMeasure(). Measured width: 171</span>

<span style="font-weight: 400;">16 LinearLayout: leaving onMeasure(). Measured width: 171</span>

<span style="font-weight: 400;">17 LinearLayout: entering onLayout(). Actual width: 171</span>

<span style="font-weight: 400;">18 TextView: entering layout(). Actual width: 171</span>

<span style="font-weight: 400;">19 TextView: leaving layout(). Actual width: 171</span>

<span style="font-weight: 400;">20 LinearLayout: leaving onLayout(). Actual width: 171</span>

<span style="font-weight: 400;">21 TextView: draw() executed</span></pre>
<p><span style="font-weight: 400;">We can perfectly see measure and layout passes happening from lines 1 to 11, with measured and actual sizes of both views going from 0 to 171.</span> We can also notice that the two passes happen twice, once before onWindowFocusChanged()and again from lines 13 to 21, but TextView calls draw() only when the Activity gets focus. This means that the layout is indeed drawn only after the Activity receives focus, but the views are laid out before it.</p>
<p><span style="font-weight: 400;">Understanding this whole process is very helpful, but it’s still hard to know how to have a callback for when the entire screen is laid out.</span></p>
<h1><span style="font-weight: 400;">Most common solutions</span></h1>
<p><span style="font-weight: 400;">After doing a little research, you will probably find some solutions that people claim they work, which usually are:</span></p>
<ul>
<li style="font-weight: 400;"><a href="https://developer.android.com/reference/android/view/View.html#post(java.lang.Runnable)"><b>View.post(Runnable action)</b></a><span style="font-weight: 400;">: this can be used to send your UI setup code to the message queue. Adding this after calling</span><span style="font-weight: 400;"> setContentView()</span><span style="font-weight: 400;"> inside </span><span style="font-weight: 400;">onCreate()</span><span style="font-weight: 400;"> usually makes your code run after the UI is laid out. But you don’t have much control of message queue, which means this approach is much more a workaround than an elegant solution that we know will always work.</span></li>
<li style="font-weight: 400;"><a href="https://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener"><b>ViewTreeObserver.OnGlobalLayoutListener</b></a><span style="font-weight: 400;">: with this listener, you can set up a code that will be executed when global layout changes happen in the whole view tree. There’s a nice </span><a href="https://antonioleiva.com/kotlin-ongloballayoutlistener/"><span style="font-weight: 400;">article</span></a><span style="font-weight: 400;"> with its usage explained by Antonio Leiva. But in the article there’s also a tweet from Chris Banes where he explains that this approach is overkill because it is triggered when layout changes happened to any view in the tree, and even with some improvements, such as removing the listener after the first call, it’s not guaranteed that when the listener is called your view has already been laid out, i.e. it might not have width and height set yet.</span></li>
<li style="font-weight: 400;"><a href="https://developer.android.com/reference/android/view/View.OnLayoutChangeListener"><b>View.OnLayoutChangeListener</b></a><span style="font-weight: 400;">:&nbsp;</span><span style="font-weight: 400;">“Interface definition for a callback to be invoked when the layout bounds of a view changes due to layout processing.”</span><span style="font-weight: 400;">This looks promising. It will be triggered only when a specific view is changed instead of the whole view tree. But what if at the time that this listener is added, this view is already laid out and then it never runs your code? In this case, we could make it run the code straight away. We could even write a Kotlin extension for this, right? Nah, no need, it’s already done and it’s in the </span><a href="https://developer.android.com/jetpack/?gclid=CjwKCAjw98rpBRAuEiwALmo-yucQWH7JJn4CtwH8j2OKJwYU7ObSXu7k8VSH_kvUL34AaK-1nTauthoCOOEQAvD_BwE"><span style="font-weight: 400;">Android Jetpack</span></a><span style="font-weight: 400;">.</span></li>
</ul>
<h1><span style="font-weight: 400;">Android KTX and doOnLayout to the rescue</span></h1>
<p><a href="https://developer.android.com/kotlin/ktx.html"><span style="font-weight: 400;">Android KTX</span></a><span style="font-weight: 400;"> is a library that is part of Android Jetpack and has a lot of useful Kotlin extensions. For our case, it has the </span><a href="https://developer.android.com/reference/kotlin/androidx/core/view/package-summary#doonlayout"><span style="font-weight: 400;">View.doOnLayout()</span></a><span style="font-weight: 400;"> extension with a callback for when a view is laid out, and it also ensures that the callback runs even if the View has already been laid out and hasn’t requested layout. If you are wondering what’s the magic behind it, there isn’t. It uses View.OnLayoutChangeListener without any crazy logic, as you can see in the </span><a href="https://android.googlesource.com/platform/frameworks/support/+/android-room-release/core/ktx/src/main/java/androidx/core/view/View.kt"><span style="font-weight: 400;">source code</span></a><span style="font-weight: 400;">.</span></p>
<p><span style="font-weight: 400;"><img decoding="async" class="alignnone size-full wp-image-6348 aligncenter" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/08/gifdiego2.gif" alt="A gif of Steve Carell slapping a table and saying 'thank you'." width="350" height="194"></span></p>
<h1><span style="font-weight: 400;">A lifecycle callback for when the entire layout is laid out</span></h1>
<p><span style="font-weight: 400;">With </span><span style="font-weight: 400;">doOnLayout()</span><span style="font-weight: 400;"> we have a callback for when a specific view is laid out, but what if you want a callback that is called when the entire layout is laid out? Well, we know that the root View is the last one to be laid out, so this means that by using </span><span style="font-weight: 400;">doOnLayout()</span><span style="font-weight: 400;"> with the root View, it will be called when all other Views have already been laid out. There’s just a small problem: how to get the root View?&nbsp;</span></p>
<p><span style="font-weight: 400;">To achieve this goal in a generic way, we could get the content view of top-level window decor using a base Activity class:</span></p>
<pre class="language-swift"><code class="language-swift"><span style="font-weight: 400;">abstract class BaseActivity: AppCompatActivity() {</span>

<span style="font-weight: 400;">&nbsp;&nbsp;&nbsp;&nbsp;protected open fun doOnRootViewLayout(action: () -&gt; Unit) {</span>

<span style="font-weight: 400;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;val rootView = window.decorView.findViewById&lt;View&gt;(android.R.id.content)</span>

<span style="font-weight: 400;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rootView.doOnLayout {</span>

<span style="font-weight: 400;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action()</span>

<span style="font-weight: 400;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span>

<span style="font-weight: 400;">&nbsp;&nbsp;&nbsp;&nbsp;}</span>

<span style="font-weight: 400;">}</span>

</code></pre>
<p><span style="font-weight: 400;">Unfortunately I couldn’t find much information about this approach and how safe it is, except an </span><a href="https://android-developers.googleblog.com/2009/03/window-backgrounds-ui-speed.html"><span style="font-weight: 400;">article</span></a><span style="font-weight: 400;"> explaining that this low-level layer can change in other Android versions or devices. Also on Android documentation there isn’t much information about </span><a href="https://developer.android.com/reference/android/R.id#content"><span style="font-weight: 400;">android.R.id.content</span></a><span style="font-weight: 400;">.&nbsp;</span></p>
<p><span style="font-weight: 400;">My suggestion is to give an ID to the root view of your layout and use this view to call </span><span style="font-weight: 400;">doOnLayout()</span><span style="font-weight: 400;">, which also works with Fragments and custom views.</span></p>
<h1><span style="font-weight: 400;">Wrapping up</span></h1>
<p>We were able to understand when Views have dimensions set and are drawn. For some reason there is not a lifecycle callback for that, but at least we came up with a working solution using doOnLayout.</p>
<p>Working with Android is a mix of love and hate, we all know that. Sometimes very basic things are difficult to achieve or understand (and it is even harder to understand why they are not explained in the documentation). I hope this article helps you to diminish the hate moments caused by some Android flaws (although it might have added more questions than answers) and write a better code and UI without fear of all that obscurity that Android sometimes leaves to us.</p>
<h1><span style="font-weight: 400;">References</span></h1>
<p><a href="https://developer.android.com/guide/components/activities/activity-lifecycle"><span style="font-weight: 400;">https://developer.android.com/guide/components/activities/activity-lifecycle</span></a></p>
<p><a href="https://developer.android.com/reference/android/app/Activity#onWindowFocusChanged(boolean)"><span style="font-weight: 400;">https://developer.android.com/reference/android/app/Activity#onWindowFocusChanged(boolean)</span></a></p>
<p><a href="https://developer.android.com/guide/topics/ui/how-android-draws"><span style="font-weight: 400;">https://developer.android.com/guide/topics/ui/how-android-draws</span></a></p>
<p><a href="https://developer.android.com/reference/android/view/View.html#post(java.lang.Runnable)"><span style="font-weight: 400;">https://developer.android.com/reference/android/view/View.html#post(java.lang.Runnable)</span></a></p>
<p><a href="https://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener"><span style="font-weight: 400;">https://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener</span></a></p>
<p><a href="https://antonioleiva.com/kotlin-ongloballayoutlistener/"><span style="font-weight: 400;">https://antonioleiva.com/kotlin-ongloballayoutlistener/</span></a></p>
<p><a href="https://developer.android.com/reference/android/view/View.OnLayoutChangeListener"><span style="font-weight: 400;">https://developer.android.com/reference/android/view/View.OnLayoutChangeListener</span></a></p>
<p><a href="https://developer.android.com/jetpack/"><span style="font-weight: 400;">https://developer.android.com/jetpack/</span></a></p>
<p><a href="https://developer.android.com/kotlin/ktx"><span style="font-weight: 400;">https://developer.android.com/kotlin/ktx</span></a></p>
<p><a href="https://developer.android.com/reference/kotlin/androidx/core/view/package-summary#doonlayout"><span style="font-weight: 400;">https://developer.android.com/reference/kotlin/androidx/core/view/package-summary#doonlayout</span></a></p>
<p><a href="https://android.googlesource.com/platform/frameworks/support/+/android-room-release/core/ktx/src/main/java/androidx/core/view/View.kt"><span style="font-weight: 400;">https://android.googlesource.com/platform/frameworks/support/+/android-room-release/core/ktx/src/main/java/androidx/core/view/View.kt</span></a></p>
<p><a href="https://android-developers.googleblog.com/2009/03/window-backgrounds-ui-speed.html"><span style="font-weight: 400;">https://android-developers.googleblog.com/2009/03/window-backgrounds-ui-speed.html</span></a></p>
<p><a href="https://developer.android.com/reference/android/R.id#content"><span style="font-weight: 400;">https://developer.android.com/reference/android/R.id#content</span></a></p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/understanding-android-views-dimensions-set/">Understanding when and how Android Views have dimensions set</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog-stg.cheesecakelabs.com/understanding-android-views-dimensions-set/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How I created the Product Thinking Canvas</title>
		<link>https://blog-stg.cheesecakelabs.com/created-product-thinking-canvas/</link>
					<comments>https://blog-stg.cheesecakelabs.com/created-product-thinking-canvas/#respond</comments>
		
		<dc:creator><![CDATA[Mayara Cristine Wandall]]></dc:creator>
		<pubDate>Fri, 12 Jul 2019 17:14:26 +0000</pubDate>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[Process]]></category>
		<guid isPermaLink="false">https://blog-stg.cheesecakelabs.com/?p=6326/</guid>

					<description><![CDATA[<p>I recently shared content about Product Thinking during an event and this mindset is changing the way I’m looking at Projects and Products. There are great articles out there about Product Thinking, like this one, but no canvas that brings together all the main questions Product Thinking focuses on. With that being said, I took [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/created-product-thinking-canvas/">How I created the Product Thinking Canvas</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span style="font-weight: 400;">I recently shared content about Product Thinking during an event and this mindset is changing the way I’m looking at Projects and Products.</span></p>
<p><span style="font-weight: 400;">There are great articles out there about Product Thinking, like </span><a href="https://medium.com/@jaf_designer/why-product-thinking-is-the-next-big-thing-in-ux-design-ee7de959f3fe"><span style="font-weight: 400;">this one</span></a><span style="font-weight: 400;">, but no canvas that brings together all the main questions Product Thinking focuses on.</span></p>
<p><span style="font-weight: 400;">With that being said, I took a stab at it and created one (</span><i><span style="font-weight: 400;">there is a tiny possibility others are looking for something like this but never found it</span></i><span style="font-weight: 400;">).</span></p>
<p><span id="more-6326"></span></p>
<p><span style="font-weight: 400;">The result you can check below:</span></p>
<p><img decoding="async" class="alignnone size-full wp-image-6336" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/07/Product-Thinking-GDG.jpg" alt="" width="960" height="540" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/07/Product-Thinking-GDG.jpg 960w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/07/Product-Thinking-GDG-768x432.jpg 768w" sizes="(max-width: 960px) 100vw, 960px" /></p>
<p><span style="font-weight: 400;">The Product Thinking canvas tackles user first (problem + target audience) followed by job to be done (vision + what you can do with our product + strategy) and finally the goals to be achieved and which features will ensure the product meets them.</span></p>
<p><span style="font-weight: 400;">The heart of the canvas is: </span><b>what you can do with our product </b><span style="font-weight: 400;">because this sentence impacted me profoundly:</span></p>
<p><span style="font-weight: 400;">“Here’s what our product can do” and “Here’s what you can do with our product” sound similar, but they are completely different approaches.</span></p>
<p><span style="font-weight: 400;">— Jason Fried (@jasonfried) November 13, 2013</span></p>
<p><span style="font-weight: 400;">As an example to materialize this sentence, we can state that Uber is not providing an app; it&#8217;s providing the possibility of connecting riders and drivers, anywhere, anytime.</span></p>
<p><span style="font-weight: 400;">Along with the fact that Product Thinking focuses on resolving real problems, it also opens up the opportunity to build products that can help us faster, that have the ability to know us more and surprise us whenever possible.</span></p>
<p><span style="font-weight: 400;">I hope this post inspires you to research further about Product Thinking and empower you to build more human-centered, product-oriented and business-relevant products.</span></p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/created-product-thinking-canvas/">How I created the Product Thinking Canvas</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog-stg.cheesecakelabs.com/created-product-thinking-canvas/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>MVVM in iOS</title>
		<link>https://blog-stg.cheesecakelabs.com/mvvm-in-ios/</link>
					<comments>https://blog-stg.cheesecakelabs.com/mvvm-in-ios/#comments</comments>
		
		<dc:creator><![CDATA[Mayara Cristine Wandall]]></dc:creator>
		<pubDate>Thu, 23 May 2019 20:01:56 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Process]]></category>
		<category><![CDATA[mobile development]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[iOS development]]></category>
		<guid isPermaLink="false">https://blog-stg.cheesecakelabs.com/?p=6247/</guid>

					<description><![CDATA[<p>One of my biggest concerns as a developer is how a project is structured. Defining a good and clean architecture with helpful names and nice design patterns is very important. It helps you and other developers to easily understand how different components of the code connect to each other and makes our lives easier in [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/mvvm-in-ios/">MVVM in iOS</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span style="font-weight: 400;">One of my biggest concerns as a developer is how a project is structured. Defining a good and clean architecture with helpful names and nice design patterns is very important. It helps you and other developers to easily understand how different components of the code connect to each other and makes our lives easier in the long term. It&#8217;s also very important to keep a good documentation about it. Always keep the README.md file updated. It helps new developers a lot.</span></p>
<p><span id="more-6247"></span></p>
<p><img decoding="async" class="size-full wp-image-6252 aligncenter" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/05/image3.gif" alt="Gif of four megazords running." width="500" height="375"></p>
<p><span style="font-weight: 400;">Here at Cheesecake Labs we care a lot about how the projects are structured. This is very important when working in teams in the same codebase. This way everybody codes in the same style. Keeping code readable for everybody during the whole project.</span></p>
<p><a href="https://developer.android.com/topic/libraries/architecture"><span style="font-weight: 400;">Android Architecture Components</span></a><span style="font-weight: 400;"> brought a new way to connect the views to the backend of Android projects: the &#8220;ViewModel&#8221;. The name explains itself. It&#8217;s an intermediary layer that connects the View (UI) to the Model (Business logic, APIs and persistency). It makes the structure of Android projects more simple to understand and it is also a good way to keep view and business logic decoupled, organized and easy to test.</span></p>
<p><span style="font-weight: 400;">MVVM is not mentioned in Google&#8217;s documentation, but the implementation of the Android ViewModels fits very well in the MVVM design pattern. So that&#8217;s what we decided to use.</span></p>
<p><span style="font-weight: 400;">MVVM worked so well in Android projects that we decided to use it in iOS projects too. And the results have been very good so far.</span></p>
<h1><span style="font-weight: 400;">MVVMC</span></h1>
<p><span style="font-weight: 400;">ViewModel is not a new concept. It&#8217;s the main part of the MVVM design pattern that was first introduced in 2005 by Josh Gossman in this </span><a href="https://blogs.msdn.microsoft.com/johngossman/2005/10/08/introduction-to-modelviewviewmodel-pattern-for-building-wpf-apps/"><span style="font-weight: 400;">post</span></a><span style="font-weight: 400;"> at Microsoft&#8217;s blog. It was created to be used as a design pattern in .NET applications, but of course we can use it anywhere &#8211; including Android and iOS projects. Each platform has its implementation particularities, so for iOS we are using the way the Runtastic team introduced in </span><a href="https://www.runtastic.com/blog/en/mvvmc-adapting-the-mvvm-design-pattern-at-runtastic/"><span style="font-weight: 400;">this blog post</span></a><span style="font-weight: 400;">. The MVVMC.</span></p>
<p><b>MVVMC</b><span style="font-weight: 400;"> is made of five main layers:</span></p>
<p><img decoding="async" class="size-full wp-image-6254 aligncenter" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/05/image5.png" alt="Image of MVVMC five main layers connected to each other." width="806" height="459" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/05/image5.png 806w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/05/image5-768x437.png 768w" sizes="(max-width: 806px) 100vw, 806px" /></p>
<h2><span style="font-weight: 400;">View</span></h2>
<p><span style="font-weight: 400;">This is the UI. It </span><b>shows information</b><span style="font-weight: 400;"> to the user and </span><b>tells the ViewModel about User actions</b><span style="font-weight: 400;">. It should not know about ViewModel implementation, so the ViewModel can be unit tested with a &#8220;mocked&#8221; view. There are a lot of ways to connect these layers. Here is an example using simple delegates:</span></p>
<pre class="language-swift"><code class="language-swift">class RocketLaunchViewController: UIViewController {
     var viewModel: ArticlesListViewModel?   
     
     override func viewDidLoad() {
          super.viewDidLoad()
          viewModel?.onViewDidLoad()
     }
     
     @IBAction func didTapLaunchButton(_ sender: Any) {
          viewModel?.onLaunchButtonTapped()
     }
}
 
extension RocketLaunchViewController: RocketLaunchViewDelegate {
     func showSuccessMessage() {
          //Show success message
     }
}</code></pre>
<h2><span style="font-weight: 400;">Model</span></h2>
<p><span style="font-weight: 400;">The model is an abstraction of the app data. Usually we define entities that represents the objects and business logic that define how these entities relate to themselves. Each project has a particular model structure that can be fetched from an API, persisted in the database, sent to a Bluetooth device, etc… Model layer is shared between all modules of the project, so it&#8217;s important to keep this layer consistent and safe.</span></p>
<h2><span style="font-weight: 400;">ViewModel</span></h2>
<p><img decoding="async" class="alignnone size-full wp-image-6258 aligncenter" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/05/ezgif.com-optimize-1.gif" alt="" width="320" height="240"></p>
<p><span style="font-weight: 400;">This is the glue that makes all parts working together. The ViewModel is responsible for telling the View what should be shown to the user and to respond to whatever the user does in the UI. The ViewModel uses an Interactor to access the model layer and the Coordinator to communicate to other modules. Here is a small example:</span></p>
<pre class="language-swift"><code class="language-swift">protocol RocketLaunchViewDelegate: class {
     func showSuccessMessage()
}
 
class RocketLaunchViewModel {
     weak var view: RocketLaunchViewDelegate?
     var interactor: RocketLaunchInteractor?
     var coordinator: RocketLaunchCoordinator?

     func onViewDidLoad() {
          interactor?.fetchRockectData() { result in
               if result.status == .success {
                    self.view?.showSuccessMessage()
               }
          }
     }

     func onLaunchButtonTapped() {
          coordinator?.showLaunchProgressModule()
     }
}</code></pre>
<h2><span style="font-weight: 400;">Interactor</span></h2>
<p><span style="font-weight: 400;">The interactor exposes the model layer to the ViewModel. Access to Database, API requests and other data that are external to the current module should be asked to the interactor by the ViewModel. Usually we create data access that is shared between all modules, like an API Manager, or Database Manager that concentrates logic that keep the data consistent. Interactor is the part that should communicate to these managers.</span></p>
<h2><span style="font-weight: 400;">Coordinator</span></h2>
<p><span style="font-weight: 400;">This part of the MVVMC pattern was added to handle communication between MVVMC modules. It is the way ViewModel uses to communicate and initiate other modules. This is also used to assemble a new MVVMC module. Code tells more than words, so:</span></p>
<pre class="language-swift"><code class="language-swift">class RocketLaunchCoordinator {
     var viewController: UIViewController?
     
     func initModule() -&gt; UIViewController {
          let interactor = RocketLaunchInteractor()
          let viewModel = RocketLaunchViewModel(coordinator: self, interactor: interactor)
          let viewController = UIStoryboard.loadViewController() as RocketLaunchViewController
          viewController.viewModel = viewModel
          return viewController
     }
      
     func showLaunchProgressModule() {
          let viewController = LaunchProgressCoordinator().initModule()
          viewController?.presentViewController(viewController, animated: true)
     }
}</code></pre>
<p><span style="font-weight: 400;">That&#8217;s it!</span></p>
<p>&nbsp;</p>
<p><img decoding="async" class="size-medium aligncenter" src="https://i.imgur.com/AiulNyn.gif?noredirect" alt="Megazord transforming with lightnings around it. " width="495" height="495"></p>
<p><span style="font-weight: 400;">MVVM is simple and we can maintain a design pattern that is similar in both mobile platform. It defines how things connect and keeps all the code in its place according to what they should be doing.</span></p>
<h2><span style="font-weight: 400;">Is it better than VIPER?</span></h2>
<p><span style="font-weight: 400;">Yes &#8211; this is my short answer!</span></p>
<p><span style="font-weight: 400;">The long explanation is: for some time VIPER has been our design pattern to be used as the default structure of the modules of mobile apps at CKL. VIPER has brought established solutions to some common issues we have being through. It decouples things, so they can be tested. And defines responsibilities for every layer, so we know where to put code, avoiding the famous Massive View Controllers.</span></p>
<p><span style="font-weight: 400;">So, what&#8217;s wrong with it?</span></p>
<p><span style="font-weight: 400;">VIPER has too many layers. This started to become a problem. Every new module needs a big set of classes, even when the module is a simple one, like a login page. There are too many things we need to plug and a lot of abstraction layers to understand.</span></p>
<p><span style="font-weight: 400;">MVVM brings all the testability and decoupling we need in a smaller and more simple to understand pattern. MVVM core has only 3 layers. And the name of these layers explain themselves. Of course we added Coordinator and Interactors to the set. But the core of the pattern is simple and the same for both platforms.</span></p>
<p><span style="font-weight: 400;">Also, I don&#8217;t like snakes. ????</span></p>
<p><img decoding="async" class="alignnone size-full wp-image-6255 aligncenter" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/05/image41.gif" alt="Gif of a Megazord holding a sword." width="500" height="376"></p>
<h2><span style="font-weight: 400;">References</span></h2>
<ul>
<li style="font-weight: 400;"><a href="https://medium.com/developermind/blurring-the-lines-between-mvvm-and-viper-dcb3dc9815ac"><span style="font-weight: 400;">https://medium.com/developermind/blurring-the-lines-between-mvvm-and-viper-dcb3dc9815ac</span></a></li>
<li style="font-weight: 400;"><a href="https://blogs.msdn.microsoft.com/johngossman/2005/10/08/introduction-to-modelviewviewmodel-pattern-for-building-wpf-apps/"><span style="font-weight: 400;">https://blogs.msdn.microsoft.com/johngossman/2005/10/08/introduction-to-modelviewviewmodel-pattern-for-building-wpf-apps/</span></a></li>
<li style="font-weight: 400;"><a href="https://developer.android.com/topic/libraries/architecture"><span style="font-weight: 400;">https://developer.android.com/topic/libraries/architecture</span></a></li>
<li style="font-weight: 400;"><a href="https://www.runtastic.com/blog/en/mvvmc-adapting-the-mvvm-design-pattern-at-runtastic/"><span style="font-weight: 400;">https://www.runtastic.com/blog/en/mvvmc-adapting-the-mvvm-design-pattern-at-runtastic/</span></a></li>
<li style="font-weight: 400;"><a href="https://blog-stg.cheesecakelabs.com/blog/ios-project-architecture-using-viper/"><span style="font-weight: 400;">https://blog-stg.cheesecakelabs.com/blog/ios-project-architecture-using-viper/</span></a></li>
</ul>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/mvvm-in-ios/">MVVM in iOS</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog-stg.cheesecakelabs.com/mvvm-in-ios/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>The perks of a Team Radar Retrospective</title>
		<link>https://blog-stg.cheesecakelabs.com/fun-agile-retrospective-team-radar/</link>
					<comments>https://blog-stg.cheesecakelabs.com/fun-agile-retrospective-team-radar/#comments</comments>
		
		<dc:creator><![CDATA[Mayara Cristine Wandall]]></dc:creator>
		<pubDate>Mon, 06 May 2019 20:06:18 +0000</pubDate>
				<category><![CDATA[Process]]></category>
		<category><![CDATA[Culture]]></category>
		<guid isPermaLink="false">https://blog-stg.cheesecakelabs.com/?p=6236/</guid>

					<description><![CDATA[<p>One of my favorite parts of the PM job is to search and try new and fun ways of conducting Sprint Retrospectives. =] Sprint Retrospective is an opportunity for the team to inspect itself and create a plan for improvements to be enacted during the next Sprint. I like to think that when we start [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/fun-agile-retrospective-team-radar/">The perks of a Team Radar Retrospective</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span style="font-weight: 400;">One of my favorite parts of the PM job is to search and try new and fun ways of conducting Sprint Retrospectives. =]</span></p>
<p><span style="font-weight: 400;">Sprint Retrospective is an opportunity for the team to inspect itself and create a plan for improvements to be enacted during the next Sprint.</span></p>
<p><span id="more-6236"></span></p>
<p><span style="font-weight: 400;">I like to think that when we start the retrospective the team is feeling like: &#8220;Yay! How are we going to tackle retrospective today? I&#8217;m so excited!&#8221; instead of &#8220;Oh okay, we&#8217;re doing that again.&#8221;</span></p>
<p><span style="font-weight: 400;">Interested to have a big picture of what&#8217;s happening inside the team? Let&#8217;s get to it!</span></p>
<h1><b>About Team Radar</b></h1>
<p><span style="font-weight: 400;">Team Radar is very similar to the </span><a href="https://sites.google.com/site/effectivecvwriting/the-competency-wheel"><span style="font-weight: 400;">Competency Wheel</span></a><span style="font-weight: 400;">. Radars are great because it presents data in a visual way, helping the teams understanding the present moment through a variety of topics. Since it is a visual tool, you can easily map &#8220;hot&#8221; topics and open the channel to start the discussions around it.</span></p>
<h1><b>Prep work</b></h1>
<p><span style="font-weight: 400;">I&#8217;ve created a </span><a href="https://docs.google.com/presentation/d/1gK06hyAUeDYjbHB1QGYidSkIf-023Bb0KWD-t4tZ8Fo/edit#slide=id.p"><span style="font-weight: 400;">template</span></a><span style="font-weight: 400;"> with the topics I selected for this first Radar and printed copies for all the team. I selected some soft topics (collaboration, partner contact, fun) and mixed it up with technical topics (technical debt, definition of done, refactoring, scrum and design).</span></p>
<p><span style="font-weight: 400;">I also created a </span><a href="https://docs.google.com/spreadsheets/d/1Ga9tF6PoU6olR6OToRLMT8q6R2T5BFAn1FvdNWwAYBw/edit#gid=443696844"><span style="font-weight: 400;">spreadsheet</span></a><span style="font-weight: 400;"> to record each one of the team&#8217;s inputs and quickly have the ability to assess the most important topics to discuss.</span></p>
<h1><b>Conducting Team Radar</b></h1>
<h2><b>Start of retrospective</b></h2>
<p><span style="font-weight: 400;">I&#8217;ve started the retrospective by sharing with the team what we would be doing and created a shared understanding regarding each one of the listed topics. We defined what would represent the smallest and highest values for each one of them.</span></p>
<h2><b>Filling out the team radar</b></h2>
<p><span style="font-weight: 400;">Using Radar&#8217;s </span><a href="https://docs.google.com/presentation/d/1gK06hyAUeDYjbHB1QGYidSkIf-023Bb0KWD-t4tZ8Fo/edit#slide=id.p"><span style="font-weight: 400;">printed</span></a><span style="font-weight: 400;"> version I asked the team to individually rate the topics based on what we defined for each one of them. We&#8217;ve used the scale from 1 to 10 and everyone marked down their answers. Refactoring and Technical Debt were the only ones that the smaller the value the better (less refactoring/rework, less technical debt for whatever reason).</span></p>
<h2><b>Connecting the dots</b></h2>
<p><span style="font-weight: 400;">Once everyone was done with rating the topics, I&#8217;ve asked them to connect the dots from the eight axis. Now everyone had their individual radar. It was so fun because some of them used their creativity to fill the radar out as you can check below:</span></p>
<p><img decoding="async" class="alignnone size-full wp-image-6237" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-06-at-4.59.36-PM.png" alt="" width="588" height="441"></p>
<p><img decoding="async" class="alignnone size-full wp-image-6238" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-06-at-4.59.51-PM.png" alt="" width="634" height="476"></p>
<h2><b>Taking it to the next level</b></h2>
<p><span style="font-weight: 400;">We then transposed all this rich data into the </span><a href="https://docs.google.com/spreadsheets/d/1Ga9tF6PoU6olR6OToRLMT8q6R2T5BFAn1FvdNWwAYBw/edit#gid=443696844"><span style="font-weight: 400;">spreadsheet</span></a><span style="font-weight: 400;"> and the result was the team&#8217;s radar as follows:</span></p>
<p><img decoding="async" class="alignnone size-full wp-image-6239" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2019/05/Screen-Shot-2019-05-06-at-5.00.11-PM.png" alt="" width="595" height="401"></p>
<p><span style="font-weight: 400;">I displayed the team Radar on a big screen and the conversation about the most relevant topics started. We documented the key takeaways and generated some important action items from there.</span></p>
<h1><b>Conclusions</b></h1>
<p><span style="font-weight: 400;">The team had fun and I did too! It generated a lot of great discussions about the defined topics. The team also had the chance to propose some other topics to be discussed next time &#8211; this means we will do another radar retrospective for sure.</span></p>
<h2><b>References</b></h2>
<p><a href="https://medium.com/the-liberators/retrospective-do-the-team-radar-1794057653e9"><span style="font-weight: 400;">Retrospective: Do the team radar</span></a></p>
<p><a href="https://www.barryovereem.com/retrospective-using-the-team-radar/"><span style="font-weight: 400;">Retrospective: Using the Team Radar</span></a></p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/fun-agile-retrospective-team-radar/">The perks of a Team Radar Retrospective</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog-stg.cheesecakelabs.com/fun-agile-retrospective-team-radar/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Starting with Graph Databases: A Quick look into Neo4j</title>
		<link>https://blog-stg.cheesecakelabs.com/starting-graph-databases-quick-look-neo4j/</link>
					<comments>https://blog-stg.cheesecakelabs.com/starting-graph-databases-quick-look-neo4j/#respond</comments>
		
		<dc:creator><![CDATA[Mayara Cristine Wandall]]></dc:creator>
		<pubDate>Fri, 07 Dec 2018 18:32:40 +0000</pubDate>
				<category><![CDATA[Process]]></category>
		<guid isPermaLink="false">https://blog-stg.cheesecakelabs.com/?p=6103/</guid>

					<description><![CDATA[<p>Let’s talk about Neo4j, a graph database that recently has attracted a significant number of fans. My goal is for you to have a brief (I promise to be quick) vision of how it works and to give you some examples to make it more tangible. We are used to write data using tables, to [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/starting-graph-databases-quick-look-neo4j/">Starting with Graph Databases: A Quick look into Neo4j</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span style="font-weight: 400;">Let’s talk about Neo4j, a graph database that recently has attracted a significant number of fans. My goal is for you to have a brief (I promise to be quick) vision of how it works and to give you some examples to make it more tangible.</span></p>
<p><span style="font-weight: 400;">We are used to write data using tables, to relate them through primary keys and, by looking directly at the data, you only see IDs. Graph databases were designed mainly so that this doesn&#8217;t happen. Its purpose is for you to have a complete understanding when looking at the data.</span><span id="more-6103"></span></p>
<figure id="attachment_6106" aria-describedby="caption-attachment-6106" style="width: 700px" class="wp-caption alignnone"><img decoding="async" class="size-full wp-image-6106" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/12/natam-post1.png" alt="" width="700" height="450"><figcaption id="caption-attachment-6106" class="wp-caption-text">Example of a simple school database diagram.</figcaption></figure>
<p><span style="font-weight: 400;">First of all, to understand an advantage of graph databases, it&#8217;s very good to know a few concepts that reinforce the idea of software close to the business rules. For that, it is worth reading </span><a href="https://en.wikipedia.org/wiki/Domain-driven_design"><span style="font-weight: 400;">Domain-Driven Design</span></a><span style="font-weight: 400;">, where the model should be as close as possible to the business. </span></p>
<p><span style="font-weight: 400;">In Neo4j, that is done with Cypher: a declarative SQL-inspired language for describing patterns in visual graphs using an ASCII syntax. It allows us to state what we want to select, insert, update or delete from our graph data without requiring us to describe exactly how to do it.</span></p>
<p><span style="font-weight: 400;">To be more practical, mind the example below, where the same &#8220;query&#8221; is implemented with SQL and Cypher.</span></p>
<pre class="language-sql" style="font-size: 20px;"><code class="language-sql">SELECT f.* FROM students s
INNER JOIN person p
ON p.id = s.person_id
INNER JOIN friend f
ON f.friend_from_id = p.id
WHERE s.id = 45
ORDER BY p.name</code></pre>
<pre class="language-sql" style="font-size: 20px;"><code class="language-sql">MATCH
(student :Student)-[FRIEND]-&amp;gt;(person :Person)
WHERE student.id = 45
RETURN person
ORDER BY person.name</code></pre>
<p><span style="font-weight: 400;">Above there&#8217;s a &#8220;query&#8221; to search for a specific student&#8217;s friends, where in the traditional mode (SQL) we need to better understand the database structure and know how they relate, causing a greater use of &#8220;JOINS&#8221;. In Cypher relations are more intuitive for reading.</span></p>
<p><span style="font-weight: 400;">Graph databases are a more natural way of storing the data. You don&#8217;t have to worry about tables and foreign keys and it keeps everything within two simple concepts: nodes and relations. Each node or relation can have its attributes and labels of identification, a way to categorize the data.</span></p>
<p><span style="font-weight: 400;">To make it easier to understand, let’s map a school in a simple way, where we have students, teachers and courses. How would a diagram represent this? Would you do it in a graph database? It is actually simpler than you think! Just draw it:</span></p>
<p><img decoding="async" class="alignnone size-full wp-image-6109" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/12/natam-post4.png" alt="" width="700" height="450"></p>
<p><span style="font-weight: 400;">Now, hands-on! </span><span style="font-weight: 400;"><br />
</span><span style="font-weight: 400;">You can </span><a href="https://neo4j.com/download/"><span style="font-weight: 400;">install Neo4j on your computer</span></a><span style="font-weight: 400;"> or do it using Docker:</span></p>
<pre class="language-yaml"><code class="language-yaml">image: neo4j:3.4.5
ports:
  - "7474:7474"
  - "7473:7473"
  - "7687:7687"
</code></pre>
<p><span style="font-weight: 400;">Don&#8217;t forget to follow the <a href="https://neo4j.com/docs/developer-manual/current/cypher/syntax/naming/">rules and nomenclature recommendations</a>.</span></p>
<p><span style="font-weight: 400;">Creating our first nodes:</span></p>
<pre class="language-sql"><code class="language-sql">CREATE (s)-[k:KNOWS]-&gt;(t), (t)-[ts:TEACHES]-&gt;(c), (s)-[e:ENROLLED]-&gt;(c)
CREATE (user1:Person:Student { name: "Natam" })
CREATE (user2:Person:Teacher { name: "Natalia" })
CREATE (course:Course { title: “Math” })</code></pre>
<p><em><span style="font-weight: 400;">Now let’s relate them:</span></em></p>
<pre class="language-sql"><code class="language-sql">MATCH (s:Student {name:"Natam"}), (t:Teacher {name:"Natalia"}), (c:Course {title:"Math"})</code></pre>
<p><span style="font-weight: 400;">Now that we have our data, we need to consult it. Let’s do this?</span></p>
<pre class="language-sql"><code class="language-sql">MATCH (n) RETURN n</code></pre>
<p><span style="font-weight: 400;">This command will return an overview of your graph. You can apply more filters and conditions to your &#8220;query&#8221;. Check this out: </span><a href="https://medium.com/r/?url=https%3A%2F%2Fneo4j.com%2Fdocs%2Fdeveloper-manual%2Fcurrent%2Fcypher%2Fclauses%2Fwhere%2F"><span style="font-weight: 400;">https://neo4j.com/docs/developer-manual/current/cypher/clauses/where/</span></a></p>
<h1><b>Conclusion, but already?</b></h1>
<p><span style="font-weight: 400;">Yes! The purpose of this post is for you to get to know this incredible technology and how basic is its structure. If you found it interesting and want to learn more about it, try modeling applications you already know using Neo4j. I’m sure you’ll be even more surprised!</span></p>
<p><span style="font-weight: 400;">I will leave a few links in case you want to know more concepts related to this technology.</span></p>
<h3>REFERENCES</h3>
<p><a href="https://medium.com/r/?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FSemantic_Web"><span style="font-weight: 400;">Semantic Web &#8211; Wikipedia</span></a></p>
<p><a href="https://medium.com/r/?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FSemantic_Web"><span style="font-weight: 400;">The Semantic Web is an extension of the World Wide Web through standards by the World Wide Web Consortium (W3C). The…</span><span style="font-weight: 400;">en.wikipedia.org</span></a></p>
<p><a href="https://medium.com/r/?url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FOntology"><span style="font-weight: 400;">Ontology &#8211; Wikipedia</span></a></p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/starting-graph-databases-quick-look-neo4j/">Starting with Graph Databases: A Quick look into Neo4j</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog-stg.cheesecakelabs.com/starting-graph-databases-quick-look-neo4j/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Three Tools for the Analytics Kings Under the Sky</title>
		<link>https://blog-stg.cheesecakelabs.com/three-tools-analytics-kings-sky/</link>
					<comments>https://blog-stg.cheesecakelabs.com/three-tools-analytics-kings-sky/#respond</comments>
		
		<dc:creator><![CDATA[Mayara Cristine Wandall]]></dc:creator>
		<pubDate>Thu, 12 Jul 2018 17:24:01 +0000</pubDate>
				<category><![CDATA[Process]]></category>
		<category><![CDATA[Mobile]]></category>
		<guid isPermaLink="false">https://blog-stg.cheesecakelabs.com/?p=6023/</guid>

					<description><![CDATA[<p>In the Tolkien&#8217;s universe, twenty Rings of Power were forged and given as gift to the rulers of Middle-Earth, the Elves, the Dwarfs and the Humans. There were Three rings for the Elven kings under the sky, the most powerful of the twenty, after the One ring. In our universe, a lot of tools were [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/three-tools-analytics-kings-sky/">Three Tools for the Analytics Kings Under the Sky</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span style="font-weight: 400;">In the Tolkien&#8217;s universe, twenty Rings of Power were forged and given as gift to the rulers of Middle-Earth, the Elves, the Dwarfs and the Humans. There were </span><b>Three rings for the Elven kings under the sky</b><span style="font-weight: 400;">, the most powerful of the twenty, after the One ring.</span></p>
<p><span style="font-weight: 400;">In our universe, a lot of tools were created and given as gift to the rulers of the Earth. If we focus on technology, more precisely in mobile metrics, we can say that there are </span><b>Three tools for the Analytics kings under the sky</b><span style="font-weight: 400;"> &#8211; and they are as powerful as the elven rings.</span></p>
<p><span id="more-6023"></span></p>
<figure id="attachment_6024" aria-describedby="caption-attachment-6024" style="width: 810px" class="wp-caption alignnone"><img decoding="async" class="wp-image-6024 size-full" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/07/Screen-Shot-2018-07-12-at-12.19.43-PM.png" alt="Three hands with rings with the tools's logos on it." width="810" height="416" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/07/Screen-Shot-2018-07-12-at-12.19.43-PM.png 810w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/07/Screen-Shot-2018-07-12-at-12.19.43-PM-768x394.png 768w" sizes="(max-width: 810px) 100vw, 810px" /><figcaption id="caption-attachment-6024" class="wp-caption-text">The three <del>rings</del> tools for the Analytics kings under the sky.</figcaption></figure>
<p><span style="font-weight: 400;">Let&#8217;s say that you had a mobile app idea, started to work on it, and finally started the development process. Everything is running ok and the screens looks gorgeous, but you feel that something&#8217;s missing: </span><b>Data</b><span style="font-weight: 400;">.</span></p>
<p><span style="font-weight: 400;">You may know how much users downloaded the app or started a session, but there is no info about which screen they opened or which button they clicked. Maybe you are trying to create a better search performance, but, in fact, the users are more attracted to the timeline than to the search, which is used by only 5% of your users. How to know about it? </span><b>Metrics</b><span style="font-weight: 400;">.</span></p>
<p><span style="font-weight: 400;">But how and where should the data be sent? How much will it cost?</span><br />
<span style="font-weight: 400;">I researched and tested three tools: Google Analytics, Firebase and MixPanel. </span><br />
<span style="font-weight: 400;">I&#8217;m glad to show you about them in the next lines, giving them a personal score and hoping to help you with this decision.</span></p>
<h1 style="text-align: left;">Google Analytics</h1>
<p><span style="font-weight: 400;">The </span><del><span style="font-weight: 400;">Ring</span></del><span style="font-weight: 400;"> Tool of Water, of preservation and protection. Some may say it looks more like a star than a </span><del><span style="font-weight: 400;">ring</span></del><span style="font-weight: 400;"> tool.</span></p>
<p><span style="font-weight: 400;">You have probably heard about or even used Google Analytics (GA). It is the oldest one among the three tools, </span><span style="font-weight: 400;">forged</span><span style="font-weight: 400;"> launched in 2005 and is widely used. If you mention that your product doesn&#8217;t have metrics implemented, you can hear something like &#8220;Not even Google Analytics?&#8221;.</span></p>
<p><span style="font-weight: 400;">It was the first platform that I ever used to metrify mobile apps. The setup is easy, the docs are great and it works very well. It also has some out of the box features, like screen funnels, and even allows you to create custom dashboards.</span></p>
<figure id="attachment_6025" aria-describedby="caption-attachment-6025" style="width: 685px" class="wp-caption alignnone"><img decoding="async" class="size-full wp-image-6025" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/07/Screen-Shot-2018-07-12-at-12.26.18-PM.png" alt="GA's Screen Funnel example" width="685" height="420"><figcaption id="caption-attachment-6025" class="wp-caption-text">GA&#8217;s Screen Funnel example.</figcaption></figure>
<p><span style="font-weight: 400;">You can also set </span><span style="font-weight: 400;">Custom dimensions</span><span style="font-weight: 400;"> to the tracked events, so you can add more info to it, like a </span><b>search query</b><span style="font-weight: 400;"> into the </span><b>performed search</b><span style="font-weight: 400;"> event. A setup is needed to use this feature, but there&#8217;s a </span><a href="https://support.google.com/analytics/answer/2709829?hl=en"><span style="font-weight: 400;">good doc for it</span></a><span style="font-weight: 400;">.</span></p>
<p><span style="font-weight: 400;">There is a </span><b>Real-Time</b><span style="font-weight: 400;"> view that allows you to see tracked events &#8220;live&#8221; and it works very well, with very little delay, but you can&#8217;t check the custom dimensions in this view. </span></p>
<p><span style="font-weight: 400;">So if you want to check the custom dimension for a tracked event you need to wait for it to be &#8220;flushed&#8221; and be available at the </span><b>Behavior</b><span style="font-weight: 400;"> session, which can take a few </span><b>hours</b><span style="font-weight: 400;"> to happen.</span></p>
<p><span style="font-weight: 400;">You can show your data in a great way for your team with </span><a href="https://datastudio.google.com/"><span style="font-weight: 400;">Google Data Studio</span></a><span style="font-weight: 400;">.</span></p>
<h3><b>Score: </b><b>7</b></h3>
<p><span style="font-weight: 400;">GA is a great tool. There are some features in Beta version, so it&#8217;s still in development and maintenance, but there are some reasons for this score. </span><br />
<span style="font-weight: 400;">The setup tutorials recommend you to use Firebase as the tracking solution for Google Analytics. </span></p>
<p><span style="font-weight: 400;">Also, for you to extract more info, like custom funnels and formulas, that are not an out of the box feature, you have to study it deeper. Fortunately, Google offers </span><a href="https://analytics.google.com/analytics/academy/"><span style="font-weight: 400;">online courses</span></a><span style="font-weight: 400;"> for it. </span></p>
<p><span style="font-weight: 400;">Good to mention that it&#8217;s free if you are not an enterprise with high traffic volume (otherwise it could cost $150,000/year USD).</span></p>
<h1 style="text-align: left;">Firebase</h1>
<p><span style="font-weight: 400;">The </span><del><span style="font-weight: 400;">Ring</span></del><span style="font-weight: 400;"> Tool of Fire, that gives hope and helped Gandalf to fight with the Balrog.</span></p>
<p><span style="font-weight: 400;">Firebase was </span><del><span style="font-weight: 400;">forged</span></del><span style="font-weight: 400;"> founded in 2011 and acquired by Google in 2014. It is a HUGE platform and has a lot of functionalities, like authentication, database, storage, notifications, A/B testing, analytics and more.</span></p>
<p><span style="font-weight: 400;">If you already use Firebase for anything else, like notifications, some data will already be there, like the </span><b>Screens</b><span style="font-weight: 400;"> and infos related to the app, like </span><b>First Opens</b><span style="font-weight: 400;"> and </span><b>App Remove</b><span style="font-weight: 400;">.</span></p>
<p><span style="font-weight: 400;">Firebase&#8217;s Dashboard is similar to the GA&#8217;s Home, but there is an easier access to create funnels and perform some other analysis.</span><br />
<span style="font-weight: 400;">In contrast, there is no screen funnel like the GA has.</span></p>
<p><span style="font-weight: 400;">Firebase has many default events, like </span><b>Search</b><span style="font-weight: 400;">, </span><b>Sign Up</b><span style="font-weight: 400;"> and </span><b>Login</b><span style="font-weight: 400;">. If you want to know more about them, their </span><a href="https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event"><span style="font-weight: 400;">doc</span></a><span style="font-weight: 400;"> is great. </span></p>
<p><span style="font-weight: 400;">You can send </span><span style="font-weight: 400;">Parameters</span><span style="font-weight: 400;"> with the event to add more info to it, like the GA&#8217;s Custom Dimensions, but they have a restricted view.</span></p>
<p><span style="font-weight: 400;">Firebase allows you to link your data to other platforms, like BigQuery, that can perform analysis even more in details and can be used to </span><a href="https://datastudio.google.com/"><span style="font-weight: 400;">Google Data Studio</span></a><span style="font-weight: 400;">, but you need to upgrade your account for it.</span></p>
<p><span style="font-weight: 400;">Firebase has a StreamView that shows you where in the globe people are using your app right now, allowing you to check out user snapshot&#8217;s in real time. Also, the tracked events are &#8220;flushed&#8221; to the Events dashboards in </span><b>minutes</b><span style="font-weight: 400;">.</span></p>
<figure id="attachment_6026" aria-describedby="caption-attachment-6026" style="width: 797px" class="wp-caption alignnone"><img decoding="async" class="size-full wp-image-6026" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/07/Screen-Shot-2018-07-12-at-12.32.46-PM.png" alt="World map to exemplify Firebase's StreamView." width="797" height="478" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/07/Screen-Shot-2018-07-12-at-12.32.46-PM.png 797w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/07/Screen-Shot-2018-07-12-at-12.32.46-PM-768x461.png 768w" sizes="(max-width: 797px) 100vw, 797px" /><figcaption id="caption-attachment-6026" class="wp-caption-text">Firebase&#8217;s StreamView example.</figcaption></figure>
<h3><b>Score: </b><b>8</b></h3>
<p><span style="font-weight: 400;">Firebase is the Google recommended tool, allowing more in deep analyze of your data.</span><br />
<span style="font-weight: 400;">The other features are a great point for Firebase, allowing you to create an app using only Firebase as the server with the database and authentication functionalities.</span><br />
<span style="font-weight: 400;">The Dashboard is more punctual, but the lack of the screen funnel is a negative point.</span><br />
<span style="font-weight: 400;">The event names pattern are also a negative point, and having in mind that linking with BigQuery is only possible to do with an upgraded account. It may require you a greater effort to present the data to, for example, the marketing team.</span></p>
<p><span style="font-weight: 400;">The Firebase Analytics is totally free, but other tools of the platform may need an upgrade, and there are </span><a href="https://firebase.google.com/pricing/"><span style="font-weight: 400;">3 pricing plans</span></a><span style="font-weight: 400;">.</span></p>
<h1 style="text-align: left;">MixPanel</h1>
<p><span style="font-weight: 400;">The </span><del><span style="font-weight: 400;">Ring</span></del><span style="font-weight: 400;"> Tool of Air, may be considered the mightiest of these three bands, possessing the power to heal and to preserve.</span><br />
<del><span style="font-weight: 400;">Forged</span></del><span style="font-weight: 400;"> Founded in 2009, MixPanel is a great platform that also has functionalities like notifications and A/B testing, but its main focus is on analytics.</span></p>
<p><span style="font-weight: 400;">Their </span><a href="https://mixpanel.com/help/reference/android"><span style="font-weight: 400;">doc</span></a><span style="font-weight: 400;"> is not that good, the Android samples are all in Java (at Cheesecake Labs we use Kotlin), some screenshots are outdated, but it could be worse.</span><br />
<span style="font-weight: 400;">With MixPanel you create your own dashboard, including the reports you want to see there and allowing you to send email digests of this info for whoever you want.</span></p>
<p><span style="font-weight: 400;">The additional infos of the tracked events are called </span><span style="font-weight: 400;">Properties</span><span style="font-weight: 400;">, and are sent to the SDK as a JSON object with key value pairs.</span></p>
<p><span style="font-weight: 400;">The </span><b>Analysis</b><span style="font-weight: 400;"> session has a lot of tools that are very simple to setup and with results that are easy to understand, making the analysis of your data the best possible.</span></p>
<p><b>Insights</b><span style="font-weight: 400;"> is a report that can be customized for event and period of time. I consider this the &#8220;default events view&#8221;.</span></p>
<figure id="attachment_6027" aria-describedby="caption-attachment-6027" style="width: 897px" class="wp-caption alignnone"><img decoding="async" class="wp-image-6027 size-full" src="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/07/Screen-Shot-2018-07-12-at-12.35.18-PM.png" alt="MixPanel Analysis session - Insights' view." width="897" height="517" srcset="https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/07/Screen-Shot-2018-07-12-at-12.35.18-PM.png 897w, https://ckl-website-static.s3.amazonaws.com/wp-content/uploads/2018/07/Screen-Shot-2018-07-12-at-12.35.18-PM-768x443.png 768w" sizes="(max-width: 897px) 100vw, 897px" /><figcaption id="caption-attachment-6027" class="wp-caption-text">MixPanel Analysis session &#8211; Insights&#8217; view.</figcaption></figure>
<p><span style="font-weight: 400;">To segment the analysis of an event by a dimension, that is what </span><b>Segmentation</b><span style="font-weight: 400;"> is for, and the results can be very interesting.</span></p>
<p><span style="font-weight: 400;">The </span><b>Live View</b><span style="font-weight: 400;"> works very well, taking only </span><b>seconds</b><span style="font-weight: 400;"> to show the events, and after you see the data there, you can already use them to your analysis. </span></p>
<p><b>Formulas</b><span style="font-weight: 400;"> allow you to understand the relation between events.</span></p>
<p><b>Funnels</b><span style="font-weight: 400;"> are the way to know how many users don&#8217;t complete a sequence of actions (e.g. sign up, agree with terms and conditions, and complete a profile), and MixPanels has a great result view.</span></p>
<p><b>Retention</b><span style="font-weight: 400;"> is the traditional check of users coming back to the app.</span></p>
<p><span style="font-weight: 400;">The last of this session, but not least, </span><b>Signal</b><span style="font-weight: 400;">, helps to understand actions that drive users to convert or retain.</span></p>
<p><span style="font-weight: 400;">MixPanel also has a </span><b>Users</b><span style="font-weight: 400;"> session to </span><b>Explore</b><span style="font-weight: 400;">, </span><b>Cohort</b><span style="font-weight: 400;"> and </span><b>Predict</b><span style="font-weight: 400;">. </span><b>Explore</b><span style="font-weight: 400;"> give you access to the user&#8217;s properties (device related), including all the tracked events and an action where you can interact directly with e-mail or notification. At </span><b>Cohort </b><span style="font-weight: 400;">you can group users that have a similar behavior in a period of time. While </span><b>Predict</b><span style="font-weight: 400;"> tells you which users are likely to convert based on what they do and who they are.</span></p>
<p><span style="font-weight: 400;">The </span><b>Take Action</b><span style="font-weight: 400;"> session is for </span><b>Campaign</b><span style="font-weight: 400;">, </span><b>Messaging</b><span style="font-weight: 400;"> and </span><b>A/B testing</b><span style="font-weight: 400;">.</span></p>
<h3><b>Score: </b><b>9</b></h3>
<p><span style="font-weight: 400;">The layout and the way the results are shown are the great part of MixPanel. Everything is crystal-clear.</span><br />
<span style="font-weight: 400;">It&#8217;s also the faster tool to check out the tracked events.</span><br />
<span style="font-weight: 400;">The tools to analyze your data are right in front of you, with video tutorials to help you and, if you still have some doubts, there is a Support chat in the bottom right corner.</span><br />
<span style="font-weight: 400;">The most negative point of MixPanel comparing to GA and Firebase is related to the screen tracking, since it&#8217;s not an out of the box functionality.</span></p>
<p><span style="font-weight: 400;">There are also </span><a href="https://mixpanel.com/pricing/"><span style="font-weight: 400;">3 pricing plans</span></a><span style="font-weight: 400;">, starting from Free going to Startup, that allows more members to the project and more time for the data history for $999/year, ending at Enterprise, with unlimited data history and premium support, and to get to know the price you need to contact them.</span></p>
<h1 style="text-align: left;">Summing Up</h1>
<p><span style="font-weight: 400;">In the end, it&#8217;s up to you, but if you question me about metrics at Prancing Pony, I would say something like this:</span></p>
<p><span style="font-weight: 400;">If you are a data scientist of a huge app that contains a lot of traffic with a lot of data to analyze and the price is not a problem, I would say to you to go with MixPanel. It probably will make your life easier, not only understanding your users and your data, but presenting it to your teammates too. Probably if this is your case, the price of the platform will not be an obstacle.</span></p>
<p><span style="font-weight: 400;">But in the case that the price really matters or if you don&#8217;t have that high traffic volume, I would like to suggest you to go with Google Analytics having in mind the Google Data Studio integration and the event names without a certain pattern, but you know, Firebase is the most up-to-date and I&#8217;m afraid of a depreciation of GA.</span></p>
<p><span style="font-weight: 400;">In other case, if your app is completely new and you don&#8217;t even have a Back-end developer for the database and authentication part, Firebase is the right platform for you.</span></p>
<p>&nbsp;</p>
<p><span style="font-weight: 400;">Thanks and good analysis for we all!</span></p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/three-tools-analytics-kings-sky/">Three Tools for the Analytics Kings Under the Sky</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog-stg.cheesecakelabs.com/three-tools-analytics-kings-sky/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Keeping data integrity with Django migrations</title>
		<link>https://blog-stg.cheesecakelabs.com/keeping-data-integrity-django-migrations/</link>
					<comments>https://blog-stg.cheesecakelabs.com/keeping-data-integrity-django-migrations/#comments</comments>
		
		<dc:creator><![CDATA[Mayara Cristine Wandall]]></dc:creator>
		<pubDate>Fri, 27 Apr 2018 17:14:53 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[Process]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[Django]]></category>
		<guid isPermaLink="false">https://blog-stg.cheesecakelabs.com/?p=5904/</guid>

					<description><![CDATA[<p>Django built-in migrations were designed as a way of propagating the changes you make on the models to the database. Migrations exist mostly to keep your code in sync with your schema and to provide a good way of versioning it. We just need a couple of commands to get our apps up and running [&#8230;]</p>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/keeping-data-integrity-django-migrations/">Keeping data integrity with Django migrations</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span style="font-weight: 400;"><a href="https://blog-stg.cheesecakelabs.com/blog/django-framework-app-development/">Django</a> built-in migrations were designed as a way of propagating the changes you make on the models to the database. Migrations exist mostly to keep your code in sync with your schema and to provide a good way of versioning it. We just need a couple of commands to get our apps up and running with an updated version of our database, or </span><a href="https://blog-stg.cheesecakelabs.com/blog/really-annoys-django-migrations/"><span style="font-weight: 400;">not</span></a><span style="font-weight: 400;">.</span></p>
<p><span id="more-5904"></span></p>
<p><span style="font-weight: 400;">Unfortunately, there are some situations when applying a migration by itself is not enough. What would you do if you needed to add a required field to an existing table? How about changing a many-to-many relationship to just a foreign key without losing pre-existing data? It may be painful and critical to make these changes without the right tool; that&#8217;s why we have <strong>Data Migrations</strong>! In this post I&#8217;ll use data migrations to approach these two scenarios.</span></p>
<h1><b>First Scenario</b></h1>
<p><span style="font-weight: 400;">Let&#8217;s say you have to design a tracking system for a company that sells computers. This system should register the computers bought by each customer. We can migrate the following models:</span></p>
<p><a href="https://github.com/murilocamargos/data-migrations-blog/blob/6c38dde2f15e569dc8d03df3743e7be331b61147/store/models.py"><span style="font-weight: 400; font-size: 12px;">GitHub</span></a><br />
<!-- HTML generated using hilite.me --></p>
<div style="background: #fbfbfb; overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px;">
<pre style="margin: 0; line-height: 125%;"><span style="color: #008000; font-weight: bold;">from</span> <span style="color: #0000ff; font-weight: bold;">django.db</span> <span style="color: #008000; font-weight: bold;">import</span> models

<span style="color: #408080; font-style: italic;"># Create your models here.</span>
<span style="color: #008000; font-weight: bold;">class</span> <span style="color: #0000ff; font-weight: bold;">Client</span>(models<span style="color: #666666;">.</span>Model):
    name <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>CharField(max_length<span style="color: #666666;">=255</span>)

<span style="color: #008000; font-weight: bold;">class</span> <span style="color: #0000ff; font-weight: bold;">Computer</span>(models<span style="color: #666666;">.</span>Model):
    brand <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>CharField(max_length<span style="color: #666666;">=255</span>)
    bought_by <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>ForeignKey(Client, related_name<span style="color: #666666;">=</span><span style="color: #ba2121;">'computers'</span>)
</pre>
</div>
<p><span style="font-weight: 400;">Now, for some reason, we&#8217;ll need to fetch a list with the information of how many computers each customer has bought. Somehow, this is incredibly expensive to compute and your queries would take extra time if you use </span><a href="https://docs.djangoproject.com/en/1.11/topics/db/aggregation/"><span style="font-weight: 400;">annotations</span></a><span style="font-weight: 400;"> with a Count aggregation. One possible solution would be to add a column on the Customer model to keep track of the amount of computers sold to that specific customer. To keep data integrity, we&#8217;ll make this field required for all new customers.</span></p>
<p><span style="font-weight: 400;">To provide the initial data to &nbsp;this new computed required field on your model, you can use a data migration. It basically works by executing a custom function in between schema migrations.</span></p>
<p><b>Step 1.</b><span style="font-weight: 400;"> First we add the field to our model as a non-required field and run the </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">makemigration</span><span style="font-weight: 400;"> and </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">migrate</span><span style="font-weight: 400;"> commands:</span></p>
<p><a href="https://github.com/murilocamargos/data-migrations-blog/blob/master/store/models.py"><span style="font-weight: 400; font-size: 12px;">GitHub</span></a><br />
<!-- HTML generated using hilite.me --></p>
<div style="overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;">
<pre style="margin: 0; line-height: 125%;"><span style="color: #008000; font-weight: bold;">from</span> <span style="color: #0000ff; font-weight: bold;">django.db</span> <span style="color: #008000; font-weight: bold;">import</span> models

<span style="color: #408080; font-style: italic;"># Create your models here.</span>
<span style="color: #008000; font-weight: bold;">class</span> <span style="color: #0000ff; font-weight: bold;">Client</span>(models<span style="color: #666666;">.</span>Model):
    name <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>CharField(max_length<span style="color: #666666;">=255</span>)
    bought <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>IntegerField(null<span style="color: #666666;">=</span><span style="color: #008000;">False</span>)

<span style="color: #008000; font-weight: bold;">class</span> <span style="color: #0000ff; font-weight: bold;">Computer</span>(models<span style="color: #666666;">.</span>Model):
    brand <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>CharField(max_length<span style="color: #666666;">=255</span>)
    bought_by <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>ForeignKey(Client, related_name<span style="color: #666666;">=</span><span style="color: #ba2121;">'computers'</span>)
</pre>
</div>
<p><b>Step 2. </b><span style="font-weight: 400;">Then, we&#8217;ll add a blank migration file; here we&#8217;ll add the custom function to perform the data migration. We use the following command:</span></p>
<p><!-- HTML generated using hilite.me --></p>
<div style="overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;">
<pre style="margin: 0; line-height: 125%;">python manage<span style="color: #666666;">.</span>py makemigrations <span style="color: #666666;">--</span>empty store <span style="color: #666666;">--</span>name prepopulate_bought_field
</pre>
</div>
<p><span style="font-weight: 400;">Note: </span><span style="font-weight: 400;">store</span><span style="font-weight: 400;"> is the Django app you&#8217;re working on and you can use the </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">&#8211;name</span><span style="font-weight: 400;"> parameter to get more informative names for your migrations.</span></p>
<p><b>Step 3. </b><span style="font-weight: 400;">Now you&#8217;ll need to write the function for this migration (this is called the forwards function):</span></p>
<p><a href="https://github.com/murilocamargos/data-migrations-blog/blob/master/store/migrations/0003_data_migration.py"><span style="font-weight: 400; font-size: 12px;">GitHub</span></a><br />
<!-- HTML generated using hilite.me --></p>
<div style="overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;">
<pre style="margin: 0; line-height: 125%;"><span style="color: #408080; font-style: italic;"># -*- coding: utf-8 -*-</span>
<span style="color: #008000; font-weight: bold;">from</span> <span style="color: #0000ff; font-weight: bold;">__future__</span> <span style="color: #008000; font-weight: bold;">import</span> unicode_literals

<span style="color: #008000; font-weight: bold;">from</span> <span style="color: #0000ff; font-weight: bold;">django.db</span> <span style="color: #008000; font-weight: bold;">import</span> migrations

<span style="color: #008000; font-weight: bold;">def</span> <span style="color: #0000ff;">add_bought</span>(apps, schema_editor):
    Client <span style="color: #666666;">=</span> apps<span style="color: #666666;">.</span>get_model(<span style="color: #ba2121;">'store'</span>, <span style="color: #ba2121;">'Client'</span>)
    <span style="color: #008000; font-weight: bold;">for</span> c <span style="color: #aa22ff; font-weight: bold;">in</span> Client<span style="color: #666666;">.</span>objects<span style="color: #666666;">.</span>all():
        c<span style="color: #666666;">.</span>bought <span style="color: #666666;">=</span> c<span style="color: #666666;">.</span>computers<span style="color: #666666;">.</span>count()
        c<span style="color: #666666;">.</span>save()

<span style="color: #008000; font-weight: bold;">class</span> <span style="color: #0000ff; font-weight: bold;">Migration</span>(migrations<span style="color: #666666;">.</span>Migration):
    dependencies <span style="color: #666666;">=</span> [
        (<span style="color: #ba2121;">'store'</span>, <span style="color: #ba2121;">'0002_client_bought'</span>),
    ]

    operations <span style="color: #666666;">=</span> [
        migrations<span style="color: #666666;">.</span>RunPython(add_bought, reverse_code<span style="color: #666666;">=</span>migrations<span style="color: #666666;">.</span>RunPython<span style="color: #666666;">.</span>noop)
    ]
</pre>
</div>
<p><span style="font-weight: 400;">Note that for using our </span><span style="font-weight: 400;">Customer</span><span style="font-weight: 400;"> model, we can&#8217;t just simply import it; this would get the most recent model that could be already changed by someone else (e.g. adding a field). To avoid this, we use </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">apps.get_model</span><span style="font-weight: 400;"> to fetch the current migration version.</span></p>
<p><span style="font-weight: 400;">This operation can also have a rollback (or reverse function) if you want or need to, simply add it as the </span><span style="font-weight: 400;">RunPython&#8217;s</span><span style="font-weight: 400;"> parameter </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">reverse_code</span><span style="font-weight: 400;"> &#8211; see more </span><a href="https://docs.djangoproject.com/en/2.0/ref/migration-operations/#runpython"><span style="font-weight: 400;">here</span></a><span style="font-weight: 400;">. In this example, we use </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">migrations.RunPython.noop</span><span style="font-weight: 400;"> to make the migration reversible without executing any code on the rollback.</span></p>
<p><b>Step 4. </b><span style="font-weight: 400;">After computing and storing all data, we can change the </span><span style="font-weight: 400;">bought</span><span style="font-weight: 400;"> field to </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">required</span><span style="font-weight: 400;"> in our model by setting its </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">null</span><span style="font-weight: 400;"> property to </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">False</span><span style="font-weight: 400;"> (it&#8217;s also possible to &nbsp;do this change on the data migration file if you want to save a migration). This step will generate another migration and you may see something like this in your screen after running </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">makemigrations</span><span style="font-weight: 400;"> command:</span></p>
<p><!-- HTML generated using hilite.me --></p>
<div style="overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;">
<pre style="margin: 0; line-height: 125%;"><span style="font-weight: 400;">You are trying to change the nullable field 'bought' on customer to non-nullable without a default; we can't do that (the database needs something to populate existing rows).</span>
<span style="font-weight: 400;">Please select a fix:</span>
<span style="font-weight: 400;">1) Provide a one-off default now (will be set on all existing rows with a null value for this column)</span>
<span style="font-weight: 400;">2) Ignore for now, and let me handle existing rows with NULL myself (e.g. because you added a RunPython or RunSQL operation to handle NULL values in a previous data migration)</span>
<span style="font-weight: 400;">3) Quit, and let me add a default in models.py</span>
<span style="font-weight: 400;">Select an option:</span></pre>
</div>
<p><span style="font-weight: 400;">You only need to select </span><span style="font-weight: 400;">2</span><span style="font-weight: 400;"> because that&#8217;s exactly what you did: you added a RunPython operation to handle <span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">null</span> values in a previous data migration.</span></p>
<h1><b>Second Scenario</b></h1>
<p><span style="font-weight: 400;">Now, say we have an address list and we thought it would be nice to have a many-to-many relationship so we wouldn&#8217;t need to repeat rows in address table. A few days later you realize that when users change their addresses, it changes for other users with the same address too. You now want to store a full address for each customer, even if it comes with some cost. </span><span style="font-weight: 400;"><br />
</span><span style="font-weight: 400;">The current state of our models looks like this:</span></p>
<p><a href="https://github.com/murilocamargos/data-migrations-blog/blob/4382ef2855328ee27e71d1380bcb1995083fc40c/address_book/models.py"><span style="font-weight: 400; font-size: 12px;">GitHub</span></a><br />
<!-- HTML generated using hilite.me --></p>
<div style="overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;">
<pre style="margin: 0; line-height: 125%;"><span style="color: #008000; font-weight: bold;">from</span> <span style="color: #0000ff; font-weight: bold;">django.db</span> <span style="color: #008000; font-weight: bold;">import</span> models

<span style="color: #408080; font-style: italic;"># Create your models here.</span>
<span style="color: #008000; font-weight: bold;">class</span> <span style="color: #0000ff; font-weight: bold;">Address</span>(models<span style="color: #666666;">.</span>Model):
    street_name <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>CharField(max_length<span style="color: #666666;">=255</span>)

<span style="color: #008000; font-weight: bold;">class</span> <span style="color: #0000ff; font-weight: bold;">Client</span>(models<span style="color: #666666;">.</span>Model):
    name <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>CharField(max_length<span style="color: #666666;">=255</span>)
    addresses <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>ManyToManyField(Address)
</pre>
</div>
<p><span style="font-weight: 400;">For this data migration, we&#8217;ll need an intermediary model to store addresses data before deleting it! We change our models to something like this:</span></p>
<p><a href="https://github.com/murilocamargos/data-migrations-blog/blob/38e4da9f5810510ed4a5e0099252aa651f89fb90/address_book/models.py"><span style="font-weight: 400; font-size: 12px;">GitHub</span></a><br />
<!-- HTML generated using hilite.me --></p>
<div style="overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;">
<pre style="margin: 0; line-height: 125%;"><span style="color: #008000; font-weight: bold;">from</span> <span style="color: #0000ff; font-weight: bold;">django.db</span> <span style="color: #008000; font-weight: bold;">import</span> models

<span style="color: #408080; font-style: italic;"># Create your models here.</span>
<span style="color: #008000; font-weight: bold;">class</span> <span style="color: #0000ff; font-weight: bold;">Address</span>(models<span style="color: #666666;">.</span>Model):
    street_name <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>CharField(max_length<span style="color: #666666;">=255</span>)

<span style="color: #008000; font-weight: bold;">class</span> <span style="color: #0000ff; font-weight: bold;">Client</span>(models<span style="color: #666666;">.</span>Model):
    name <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>CharField(max_length<span style="color: #666666;">=255</span>)
    addresses <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>ManyToManyField(Address)

<span style="color: #008000; font-weight: bold;">class</span> <span style="color: #0000ff; font-weight: bold;">NewAddress</span>(models<span style="color: #666666;">.</span>Model):
    street_name <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>CharField(max_length<span style="color: #666666;">=255</span>)
    client <span style="color: #666666;">=</span> models<span style="color: #666666;">.</span>ForeignKey(Client)
</pre>
</div>
<p><span style="font-weight: 400;">Similarly to what we&#8217;ve done in the previous scenario, we create a migration and write write a custom function (or </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">forwards_func</span><span style="font-weight: 400;">) to move all data that was store on </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">Address</span><span style="font-weight: 400;"> table to </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">NewAddress</span><span style="font-weight: 400;"> table. It looks like this:</span></p>
<p><a href="https://github.com/murilocamargos/data-migrations-blog/blob/master/address_book/migrations/0002_newaddress_data_migration.py"><span style="font-weight: 400; font-size: 12px;">GitHub</span></a><br />
<!-- HTML generated using hilite.me --></p>
<div style="overflow: auto; width: auto; padding: .6em; font-size: .85em; margin-top: -10px; background: #fbfbfb;">
<pre style="margin: 0; line-height: 125%;"><span style="color: #408080; font-style: italic;"># -*- coding: utf-8 -*-</span>
<span style="color: #008000; font-weight: bold;">from</span> <span style="color: #0000ff; font-weight: bold;">__future__</span> <span style="color: #008000; font-weight: bold;">import</span> unicode_literals

<span style="color: #008000; font-weight: bold;">from</span> <span style="color: #0000ff; font-weight: bold;">django.db</span> <span style="color: #008000; font-weight: bold;">import</span> migrations, models
<span style="color: #008000; font-weight: bold;">import</span> <span style="color: #0000ff; font-weight: bold;">django.db.models.deletion</span>

<span style="color: #008000; font-weight: bold;">def</span> <span style="color: #0000ff;">migrate_data</span>(apps, schema_editor):
    Client <span style="color: #666666;">=</span> apps<span style="color: #666666;">.</span>get_model(<span style="color: #ba2121;">'address_book'</span>, <span style="color: #ba2121;">'Client'</span>)
    NewAddress <span style="color: #666666;">=</span> apps<span style="color: #666666;">.</span>get_model(<span style="color: #ba2121;">'address_book'</span>, <span style="color: #ba2121;">'NewAddress'</span>)

    <span style="color: #008000; font-weight: bold;">for</span> c <span style="color: #aa22ff; font-weight: bold;">in</span> Client<span style="color: #666666;">.</span>objects<span style="color: #666666;">.</span>all():
        <span style="color: #008000; font-weight: bold;">for</span> a <span style="color: #aa22ff; font-weight: bold;">in</span> c<span style="color: #666666;">.</span>addresses<span style="color: #666666;">.</span>all():
            NewAddress<span style="color: #666666;">.</span>objects<span style="color: #666666;">.</span>create(street_name<span style="color: #666666;">=</span>a<span style="color: #666666;">.</span>street_name, client<span style="color: #666666;">=</span>c)

<span style="color: #008000; font-weight: bold;">class</span> <span style="color: #0000ff; font-weight: bold;">Migration</span>(migrations<span style="color: #666666;">.</span>Migration):

    dependencies <span style="color: #666666;">=</span> [
        (<span style="color: #ba2121;">'address_book'</span>, <span style="color: #ba2121;">'0001_initial'</span>),
    ]

    operations <span style="color: #666666;">=</span> [
        migrations<span style="color: #666666;">.</span>CreateModel(
            name<span style="color: #666666;">=</span><span style="color: #ba2121;">'NewAddress'</span>,
            fields<span style="color: #666666;">=</span>[
                (<span style="color: #ba2121;">'id'</span>, models<span style="color: #666666;">.</span>AutoField(auto_created<span style="color: #666666;">=</span><span style="color: #008000;">True</span>, primary_key<span style="color: #666666;">=</span><span style="color: #008000;">True</span>, serialize<span style="color: #666666;">=</span><span style="color: #008000;">False</span>, verbose_name<span style="color: #666666;">=</span><span style="color: #ba2121;">'ID'</span>)),
                (<span style="color: #ba2121;">'street_name'</span>, models<span style="color: #666666;">.</span>CharField(max_length<span style="color: #666666;">=255</span>)),
                (<span style="color: #ba2121;">'client'</span>, models<span style="color: #666666;">.</span>ForeignKey(on_delete<span style="color: #666666;">=</span>django<span style="color: #666666;">.</span>db<span style="color: #666666;">.</span>models<span style="color: #666666;">.</span>deletion<span style="color: #666666;">.</span>CASCADE, to<span style="color: #666666;">=</span><span style="color: #ba2121;">'address_book.Client'</span>)),
            ],
        ),
        migrations<span style="color: #666666;">.</span>RunPython(migrate_data, reverse_code<span style="color: #666666;">=</span>migrations<span style="color: #666666;">.</span>RunPython<span style="color: #666666;">.</span>noop)
    ]
</pre>
</div>
<p><span style="font-weight: 400;">We can now remove our old </span><span style="font-weight: 400;">Address</span><span style="font-weight: 400;"> model, then run </span><span style="font-weight: 400;">makemigrations </span><span style="font-weight: 400;">and rename your </span><span style="font-weight: 400;">NewAddress</span><span style="font-weight: 400;"> model to </span><span style="font-weight: 400;">Address</span><span style="font-weight: 400;">. It&#8217;s important to run </span><span style="font-weight: 400;">makemigrations</span><span style="font-weight: 400;"> in between these two operations, otherwise Django will treat </span><span style="font-weight: 400;">NewAddress</span><span style="font-weight: 400;"> as if it was the old </span><span style="font-weight: 400;">Address</span><span style="font-weight: 400;">.</span></p>
<p><span style="font-weight: 400;">Note that even using </span><span style="font-weight: 400; font-family: Consolas, Monaco, monospace; font-size: .85em; background-color: #fff0f0;">migrations.RunPython.noop</span><span style="font-weight: 400;">, this migration is not reversible because we&#8217;re deleting and renaming models. If you need it to be reversible, you should write another custom function that does the rollback.</span></p>
<h1><b>Conclusions</b></h1>
<p><span style="font-weight: 400;">These operations can be very harmful to your data if used improperly, so it&#8217;s always a good idea to have a database dump before doing something like this in production. These scenarios we used as example are a bit silly, but it&#8217;s enough to get the idea of how to apply data migrations to solve data consistency issues.</span></p>
<p><span style="font-weight: 400;">You can also make </span><a href="https://docs.djangoproject.com/pt-br/1.11/howto/initial-data/"><span style="font-weight: 400;">fixtures</span></a><span style="font-weight: 400;"> for loading some initial data to your apps or just importing a text file on any of your data migrations and running a forwards function to get them in your database.</span></p>
<p><span style="font-weight: 400;">As Sir Oliver Wendell Holmes would say, </span><span style="font-weight: 400;">The young man knows the rules, but the old man knows the exceptions</span><span style="font-weight: 400;">. So if you know any exceptions, please let us know, help is very much appreciated.</span></p>
<p><span style="font-weight: 400;">The code used in this blogpost is available on </span><a href="https://github.com/murilocamargos/data-migrations-blog"><span style="font-weight: 400;">GitHub</span></a><span style="font-weight: 400;">.</span></p>
<h3><b>Good references</b></h3>
<ul>
<li><a href="https://realpython.com/blog/python/data-migrations/"><span style="font-weight: 400;">https://realpython.com/blog/python/data-migrations/</span></a></li>
<li><a href="https://docs.djangoproject.com/en/2.0/topics/migrations/#data-migrations"><span style="font-weight: 400;">https://docs.djangoproject.com/en/2.0/topics/migrations/#data-migrations</span></a></li>
<li><a href="https://simpleisbetterthancomplex.com/tutorial/2017/09/26/how-to-create-django-data-migrations.html"><span style="font-weight: 400;">https://simpleisbetterthancomplex.com/tutorial/2017/09/26/how-to-create-django-data-migrations.html</span></a></li>
</ul>
<p>The post <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com/keeping-data-integrity-django-migrations/">Keeping data integrity with Django migrations</a> appeared first on <a rel="nofollow" href="https://blog-stg.cheesecakelabs.com">Cheesecake Labs</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog-stg.cheesecakelabs.com/keeping-data-integrity-django-migrations/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
