<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by cxr on Medium]]></title>
        <description><![CDATA[Stories by cxr on Medium]]></description>
        <link>https://medium.com/@netcyrax?source=rss-cae4a883a0f6------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*d16XxaqPwq3uKSJOO4yIUg.jpeg</url>
            <title>Stories by cxr on Medium</title>
            <link>https://medium.com/@netcyrax?source=rss-cae4a883a0f6------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 28 May 2026 00:15:18 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@netcyrax/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[[book review] [ in ]: How to win friends and influence people]]></title>
            <link>https://medium.com/rocknnull/book-review-in-how-to-win-friends-and-influence-people-10cc079a040e?source=rss-cae4a883a0f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/10cc079a040e</guid>
            <category><![CDATA[review]]></category>
            <category><![CDATA[entrepreneurship]]></category>
            <category><![CDATA[communication]]></category>
            <category><![CDATA[public-relations]]></category>
            <category><![CDATA[social-skills]]></category>
            <dc:creator><![CDATA[cxr]]></dc:creator>
            <pubDate>Sat, 13 Apr 2019 13:44:24 GMT</pubDate>
            <atom:updated>2019-04-13T13:44:24.515Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oc8MBE9JlvNnLcZ1M2Yolg.jpeg" /></figure><pre><strong>About the series:</strong> In [📚 in 🏎️] I will try to summarize in super dense notes the gist of a whole book. This is intended as a sneak peak for readers that have not yet read the book and for a reminder trigger for people who did. Enjoy! (P.S. I have links to longer book summaries/reviews at the end of the post.)</pre><p>This <a href="https://smile.amazon.com/How-Win-Friends-Influence-People/">book</a> is about practical tips on how to create a <strong>good impression on people</strong> and <strong>influence them to agree with you</strong>. You probably already doing some of these techniques but it’s great to have these all in one place. The author gives multiple examples of how these principles might apply in real life. Here I am listing the book content table along with the one-line principle. Also, I bold-ify what I consider to be the most important principles.</p><h4>Fundamental techniques in handling people</h4><ol><li>‘If you want to gather honey, don’t kick over the beehive’<br>→ <strong>Don’t criticize, condemn or complain.</strong></li><li>The big secret of dealing with people<br>→ Give honest and sincere appreciation.</li><li>‘He who can do this has the whole world with him. He cannot walks a lonely way’<br>→ Arouse in the other person an eager want.</li></ol><h4>Six ways to make people like you</h4><ol><li>Do this and you’ll be welcome anywhere<br>→ <strong>Become genuinely interested in other people.</strong></li><li>A simple way to make a good first impression<br>→ <strong>Smile.</strong></li><li>If you don’t do this you are headed for trouble<br>→ Remember that a person’s name is to that person the sweetest and most important sound in any language.</li><li>An easy way to become a good conversationalist<br>→ <strong>Be a good listener. Encourage others to talk about themselves.</strong></li><li>How to interest people<br>→ <strong>Talk in terms of the other person’s interests.</strong></li><li>How to make people like you instantly<br>→ Make the other person feel important — and do it sincerely.</li></ol><h4>How to win people in your way of thinking</h4><ol><li>You can’t win an argument<br>→ The only way to get the best of an argument is to avoid it.</li><li>A sure way of making enemies and how to avoid it<br>→ <strong>Show respect for the other person’s opinions. Never say, “You’re wrong.”</strong></li><li>If you wrong, admit it<br>→<strong> If you are wrong, admit it quickly and emphatically.</strong></li><li>A drop of honey<br>→ Begin in a friendly way.</li><li>The secret of Socrates<br>→ Get the other person saying “yes, yes” immediately.</li><li>The safety valve in handling complains<br>→ Let the other person do a great deal of the talking.</li><li>How to get cooperation<br>→ Let the other person feel that the idea is his or hers.</li><li>A formula that will work wonders for you<br>→ <strong>Try honestly to see things from the other person’s point of view.</strong></li><li>What everybody wants<br>→ Be sympathetic with the other person’s ideas and desires.</li><li>An appeal that everybody likes<br>→ Appeal to the nobler motives.</li><li>The movies do it, TV does it, Why don’t you do it?<br>→ <strong>Dramatize your ideas.</strong></li><li>When nothing else works, try this<br>→ Throw down a challenge.</li></ol><h4>Be a leader: How to change people without giving offense or arousing resentment</h4><ol><li>If you must find fault, this is the way to begin<br>→ Begin with praise and honest appreciation.</li><li>How to criticize — and not be hated for it<br>→ Call attention to people’s mistakes indirectly.</li><li>Talk about your own mistakes first<br>→ <strong>Talk about your own mistakes before criticizing the other person.</strong></li><li>No one likes to take orders<br>→ <strong>Ask questions instead of giving direct orders.</strong></li><li>Let the other person save face</li><li>How to spur people on to success<br>→ Praise the slightest improvement and praise every improvement. Be “hearty in your approbation and lavish in your praise.”</li><li>Give a dog a good name<br>→ <strong>Give the other person a fine reputation to live up to.</strong></li><li>Make the fault seem easy to correct<br>→ Use encouragement. Make the fault seem easy to correct.</li><li>Making people glad to do what you want<br>→ Make the other person happy about doing the thing you suggest.</li></ol><blockquote><em>Longer book reviews/summaries: </em><a href="https://fs.blog/2012/07/how-to-win-friends-and-influence-people/"><em>1</em></a><em>, </em><a href="https://www.hubspot.com/sales/how-to-win-friends-and-influence-people-summary"><em>2</em></a><em>, </em><a href="https://www.samuelthomasdavies.com/book-summaries/self-help/how-to-win-friends-and-influence-people/"><em>3</em></a><em>, </em><a href="https://fastertomaster.com/how-to-win-friends-and-influence-people-by-dale-carnegie/"><em>4</em></a></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=10cc079a040e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/rocknnull/book-review-in-how-to-win-friends-and-influence-people-10cc079a040e">[book review] [📚 in 🏎]: How to win friends and influence people</a> was originally published in <a href="https://medium.com/rocknnull">Rock and Null</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A glimpse into how to build an Ethereum DApp]]></title>
            <link>https://medium.com/rocknnull/a-glimpse-into-how-to-build-an-ethereum-dapp-89be65f1e578?source=rss-cae4a883a0f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/89be65f1e578</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[ethereum]]></category>
            <category><![CDATA[dapps]]></category>
            <category><![CDATA[distributed-systems]]></category>
            <category><![CDATA[blockchain]]></category>
            <dc:creator><![CDATA[cxr]]></dc:creator>
            <pubDate>Tue, 26 Jun 2018 21:40:07 GMT</pubDate>
            <atom:updated>2018-06-26T22:26:43.015Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dsLDki8MlcP2W5jaLQhyJw.jpeg" /></figure><p>Blockchain is hot right now. And you know what’s hotter? Ethereum. I have recently experimented with Ethereum by making a simple DApp (Distributed App). I want to contribute back to the community …… by making another (kind of) tutorial on how to create a DApp.</p><p>The objective of this post will <strong>not</strong> be to guide you step-by-step on how to build a DApp. I won’t explain everything here; I will link to a lot of other places that explain each part better. Still, I believe it’s good high-level overview on how / what is needed to start building Ethereum DApps.</p><h3>Glossary</h3><p>If you want to get a <strong>high-level</strong> understanding of what <strong>blockchain</strong> is, dedicate 15 minutes and watch these <a href="https://anders.com/blockchain/">excellent videos</a> (it’s part 1 &amp; 2, and then you can play practically with the introduced concepts).</p><p><a href="https://en.wikipedia.org/wiki/Ethereum"><strong>Ethereum</strong></a> is a “blockchain-based distributed computing platform” that allows you to create distributed programs called <strong>smart contracts</strong>. Now, if you make this contract to act like the back-end of a website, and you put a front-end to interact with this contract you get a <a href="https://www.quora.com/What-is-the-difference-between-smart-contracts-and-dapps"><strong>DApp</strong></a> (distributed app).</p><p>These contracts are written in a language called <a href="https://en.wikipedia.org/wiki/Solidity"><strong>Solidity</strong></a><strong> </strong>that has a C-like syntax (although you can write smart contracts in other languages, this is the most popular). To actually use these smart contracts, you need to deploy them to the Ethereum network by paying some Ether, the native cryptocurrency of Ethereum.</p><h3>Intro</h3><p>You used to have to manually keep track of where you deployed a contract, but new frameworks like <a href="http://truffleframework.com/">Truffle</a> and <a href="https://embark.status.im/">Embark</a> are making developing and deploying smart contracts way easier.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/933/1*fpV9PagLdS7SiP4danb9ig.gif" /></figure><p>To create my sample DApp I used the <a href="http://truffleframework.com/"><strong>Truffle framework</strong></a><strong> </strong>because it seems to be more popular (i.e. more StackOverflow posts) and had better tutorials available. <a href="https://embark.status.im/">Embark</a> seems really decent, but being a complete newbie in the field, I went with the popular choice.</p><p>My sample DApp is called <strong>dWIP (decentralised work in progress)</strong> and you can use it to publicly keep track on the work you are doing for your side-project (partly inspired by <a href="https://wip.chat/">wip.chat</a>). As shown in the GIF, you just enter the task you are working on and it’s added to the list. Then you can share this page with the users of your side-project to keep them updated about the progress :)</p><p>Truffle provides the <a href="http://truffleframework.com/tutorials/pet-shop"><strong>Ethereum Pet Shop</strong></a> tutorial which I highly recommend and I based my sample DApp on.</p><h3>Backend</h3><p>As mentioned earlier, the backend of this web app is the smart contract. To get a taste of Solidity, this how the contract for my sample dapp looks like:</p><pre><strong>pragma </strong>solidity ^0.4.6;  // 1.<br><br><strong>contract </strong>Dwip {<br><br>    <strong>struct </strong>Task {<br>        <strong>string </strong>text;<br>        <strong>uint </strong>timestamp;<br>    }<br><br>    <strong>struct </strong>AddressData {  // 2.<br>        Task[] taskArray;<br>        <strong>string </strong>addressName;<br>    }<br><br>    <strong>mapping</strong>(<strong>address </strong>=&gt; AddressData) addressDataMap;  // 3.<br><br>    <strong>function </strong>appendTask(<strong>string </strong>taskText) <strong>public returns </strong>(<strong>uint </strong>length) {  // 4.<br>        Task <strong>memory </strong>t = Task(taskText, block.timestamp);<br>        <strong>return </strong>addressDataMap[msg.sender].taskArray.push(t);<br>    }<br><br>    <strong>function </strong>getTaskCountAddr(<strong>address </strong>addr) <strong>public constant returns </strong>(<strong>uint </strong>length) {  // 5.<br>        <strong>return </strong>addressDataMap[addr].taskArray.length;<br>    }<br><br>    <strong>function </strong>getTaskCount() <strong>public constant returns </strong>(<strong>uint </strong>length) {<br>        <strong>return </strong>getTaskCountAddr(msg.sender);<br>    }<br><br>    <strong>function </strong>getTaskAtIndexAddr(<strong>address </strong>addr, <strong>uint </strong>index) <strong>public constant returns </strong>(<strong>string </strong>value) {  // 6.<br>        <strong>return </strong>addressDataMap[addr].taskArray[index].text;<br>    }<br><br>    <strong>function </strong>getTaskAtIndex(<strong>uint </strong>index) <strong>public constant returns </strong>(<strong>string </strong>value) {<br>        <strong>return </strong>getTaskAtIndexAddr(msg.sender, index);<br>    }</pre><ol><li>Instruction for the Solidity compiler denoting the language version</li><li>The data that we hold for each address. A different address should be used in this case for every different side-project</li><li>The mapping from address to the data we hold.</li><li>Create a new WIP task (i.e. a new row) calling this function. Notice that the function return type is declared at the end.</li><li>Get how many WIP tasks (i.e. rows) are stored for a specific address. Notice the <strong>constant</strong> keyword that indicates that the function does not make any changes to storage (i.e. saving data). It’s just read-only (and cheaper to call).</li><li>There are 2 versions for each function, one that uses the <strong>msg.sender </strong>address and one that takes the address as a parameter. This for linking to different address (i.e. side-projects) with a GET parameter (e.g. /dwip?addrr=0xABCD)</li></ol><p>(To write a contract and be able to iterate and interact with it, you can use <a href="https://remix.ethereum.org/">Remix</a>, the official online Ethereum IDE.)</p><p>Truffle provides an easy way to write tests in Solidity to call these methods and verify that they work as indented (and that will not break in the future).</p><pre><strong>pragma </strong>solidity ^0.4.17;<br><br><strong>import &quot;truffle/Assert.sol&quot;</strong>;<br><strong>import &quot;truffle/DeployedAddresses.sol&quot;</strong>;<br><strong>import &quot;../contracts/Dwip.sol&quot;</strong>;<br><br><strong>contract </strong>TestDwip {<br>  Dwip dwip = Dwip(DeployedAddresses.Dwip());<br><br>  <strong>function </strong>testAppendTask() <strong>public </strong>{<br>    <strong>uint </strong>returnedLength = dwip.appendTask(<strong>&quot;hello&quot;</strong>);<br><br>    Assert.equal(returnedLength, 1, <strong>&quot;Incorrect task length.&quot;</strong>);<br>  }<br><br>  <strong>function </strong>testGetCount() <strong>public </strong>{<br>    <strong>uint </strong>returnedCount = dwip.getTaskCount();<br><br>    Assert.equal(returnedCount, 1, <strong>&quot;Incorrect task count.&quot;</strong>);<br>  }<br><br>  <strong>function </strong>testGetCountAddr() <strong>public </strong>{<br>    <strong>uint </strong>returnedCount = dwip.getTaskCountAddr(this);<br><br>    Assert.equal(returnedCount, 1, <strong>&quot;Incorrect task count.&quot;</strong>);<br>  }<br><br>  <strong>function </strong>testGetTaskAtIndex() <strong>public </strong>{<br>    <strong>string memory </strong>expected = <strong>&quot;world&quot;</strong>;<br>    dwip.appendTask(expected);<br>    <strong>string memory </strong>returnedTask = dwip.getTaskAtIndex(1);<br><br>    Assert.equal(returnedTask, expected, <strong>&quot;Incorrect task text.&quot;</strong>);<br>  }<br><br>  <strong>function </strong>testGetTaskAtIndexAddr() <strong>public </strong>{<br>    <strong>string memory </strong>expected = <strong>&quot;beyond&quot;</strong>;<br>    dwip.appendTask(expected);<br>    <strong>string memory </strong>returnedTask = dwip.getTaskAtIndexAddr(this, 2);<br><br>    Assert.equal(returnedTask, expected, <strong>&quot;Incorrect task text.&quot;</strong>);<br>  }<br>}</pre><p>These are not the traditional unit tests in the sense that the state is not reset every time. To actually run these test, you can use a local private blockchain with <a href="http://truffleframework.com/ganache/">Ganache</a>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fHVmX6lqvdIwuysTtLSTvw.png" /></figure><h3>Frontend</h3><p>When you are done writing the contract, you will have to call these methods. The frontend of a DApp consists of conventional web technology (i.e. javascipt, html, css). When you deploy a contract on a network (main or test network), you get an address to be able to call it. Truffle makes it really easy to call a smart contract by keeping track of where (i.e. the address) is deployed. For instance, for my sample DApp the code to add a new WIP task is similar to:</p><pre><strong>web3</strong>.<strong>eth</strong>.getAccounts(<strong>function </strong>(error, accounts) {  // 1.<br><br>    <strong>var </strong>account = accounts[0];  // 2.<br><br>    <strong>App</strong>.<strong>contracts</strong>.<strong>Dwip</strong>.deployed().then(<strong>function </strong>(instance) {  // 3.</pre><pre><em>        </em><strong>return </strong>adoptionInstance.appendTask(taskText, {<strong>from</strong>:          account});  // 4.</pre><pre>    }).then(<strong>function </strong>(result) {<br>        <strong>return App</strong>.fetchWips();  // 5.<br>    }).catch(<strong>function </strong>(err) {<br>        <strong><em>console</em></strong>.log(err.<strong>message</strong>);<br>    });<br>});</pre><ol><li><a href="https://web3js.readthedocs.io/en/1.0/">Web3</a> is the javascript library to communicate with Ethereum nodes.</li><li>Select the first available account from the wallet.</li><li>Truffle is keeping track of the address the contract is given when deployed on a network.</li><li>When you have an instance of the deployed contract, you can call methods. Note that the method called here is <strong>not constant</strong> so an account to be charged is provided as an argument.</li><li>The result of the method call is returned. Here is unused.</li></ol><h3>Wallet</h3><p>To make a transaction with an Ethereum smart contract you need a wallet. DApps are just smart-contracts-as-web-backends and an in-browser wallet is needed to perform transactions. The most popular (and the only one I know) in-browser wallet is called <a href="https://metamask.io/">Metamask</a> for Chrome, Firefox and Opera. Extensive instructions <a href="https://metamask.io/">here</a> on how to set it up.</p><h3>Backend deployment</h3><p>When you want to make your DApp available for the world, you need to deploy it to the Ethereum <strong>main net</strong> or a <strong>test net</strong>. Like the names are suggesting, to deploy to the main net real ether (i.e. money) is needed. I have only tried deploying to a test net (there are multiple test nets, like <a href="https://www.rinkeby.io/#stats">Rinkeby</a> and <a href="https://ropsten.etherscan.io/">Ropsten</a>) where no real money is needed (you get fake money from a <a href="https://faucet.rinkeby.io/">fauce</a>t). To deploy to a network you will need to run a client on your machine and download the whole blockchain transaction history on your machine (that means you will need a lot of space, and depending on your connection a lot of time). To deploy to Rinkeby follow the instructions <a href="https://blog.abuiles.com/blog/2017/07/09/deploying-truffle-contracts-to-rinkeby/">here</a>. Note that there is a way to <a href="https://truffleframework.com/tutorials/using-infura-custom-provider">deploy without downloading the whole blockchain on your machine</a>, but I have not tried it.</p><h3>Frontend deployment</h3><p>You can deploy the frontend (i.e. HTML, CSS, Javascript files) to a regular web server (like I did) or go fully decentralised and host your files on a P2P network like <a href="https://ipfs.io/">IPFS</a>. Follow the instructions in the “<a href="https://medium.com/@merunasgrincalaitis/the-ultimate-end-to-end-tutorial-to-create-and-deploy-a-fully-descentralized-dapp-in-ethereum-18f0cf6d7e0e">Deploy the application online with IPFS</a>” section for IPFS hosting.</p><h3>Conclusion</h3><p>Blockchain and the decentralised web revolution in general, is exciting and it evolves really fast. New frameworks, like Truffle, removes the major pain points from Ethereum development, but it’s still early so keep an eye (as I will do) for further developments in the field!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=89be65f1e578" width="1" height="1" alt=""><hr><p><a href="https://medium.com/rocknnull/a-glimpse-into-how-to-build-an-ethereum-dapp-89be65f1e578">A glimpse into how to build an Ethereum DApp</a> was originally published in <a href="https://medium.com/rocknnull">Rock and Null</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[book review] [ in ]: Traction: How Any Startup Can Achieve Explosive Customer Growth]]></title>
            <link>https://medium.com/rocknnull/book-review-in-traction-how-any-startup-can-achieve-explosive-customer-growth-2cd74c2f3dbb?source=rss-cae4a883a0f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/2cd74c2f3dbb</guid>
            <category><![CDATA[review]]></category>
            <category><![CDATA[startup-marketing]]></category>
            <category><![CDATA[marketing]]></category>
            <category><![CDATA[traction]]></category>
            <category><![CDATA[startup]]></category>
            <dc:creator><![CDATA[cxr]]></dc:creator>
            <pubDate>Sat, 21 Apr 2018 16:37:42 GMT</pubDate>
            <atom:updated>2018-04-21T16:42:12.556Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PIM_Lqn1h4foN3XBqoD5PA.jpeg" /></figure><pre><strong>About the series:</strong> In [📚 in 🏎️] I will try to summarize in super dense notes the gist of a whole book. This is intended as a sneak peak for readers that have not yet read the book and for a reminder trigger for people who did. Enjoy! (P.S. I have links to longer book summaries/reviews at the end of the post.)</pre><p>The author believes that most startups fail, not because of a bad product, but because they fail to attract enough customers. Most startups spend all their resources on engineering and building a great product without paying any attention to getting traction. After they build the product, then they seek to get traction which is too late due to exhausted resources.</p><p>The book introduces the following rules:</p><h4>50/50 rule</h4><p>Spend 50% on product development and 50%on marketing/traction <strong>from the beginning.</strong> This is useful for getting feedback for the product from day 1 that will help refine the product along the way. The author suggest that a product is like a leaking bucket that as time goes by and you fill the holes more and more customers will stick around.</p><h4>Bullseye Framework</h4><p>At each stage of a startup a different traction channel (will list them later) is suitable for “moving the needle”. There is no way to predict which one is the correct, so test and decide:</p><ol><li>Brainstorm ideas for traction channels</li><li>Run cheap tests for the best brainstorm ideas</li><li>Focus all your resources on the one most successful test</li><li>Repeat</li></ol><h4>Critical path</h4><p>The most common mistake for a startup is to spend the limited available resources on non-essential stuff. Set a quantifiable traction goal and do not get distracted.</p><h3>Available traction channels</h3><p>The book has a good summary on the following traction channel with a practical tips and testimonials on how to utilize them.</p><ul><li>Targeting blogs</li><li>Traditional publicity (e.g. magazines, TV, etc)</li><li>Unconventional PR (e.g. publicity stunt)</li><li>Search Engine Marketing (SEM)</li><li>Social and Display Ads</li><li>Offline ads</li><li>Search Engine Optimization (SEO)</li><li>Content marketing</li><li>Email marketing</li><li>Viral marketing</li><li>Engineering as marketing</li><li>Business Development (BD)</li><li>Sales</li><li>Affiliate programs</li><li>Existing platforms</li><li>Trade shows</li><li>Offline events</li><li>Speaking engagement</li><li>Community building</li></ul><blockquote><em>Longer book reviews/summaries: </em><a href="https://readingraphics.com/book-summary-traction/"><em>1</em></a><em>, </em><a href="https://www.thorprojects.com/blog/archive/2016/08/22/book-review-traction-how-any-startup-can-achieve-explosive-customer-growth/"><em>2</em></a><em>, </em><a href="https://medium.com/@yegg/the-19-channels-you-can-use-to-get-traction-93c762d19339"><em>3</em></a><em>, </em><a href="http://www.sjoerdjanterwelle.com/book-review-traction-how-any-startup-can-achieve-explosive-customer-growth/?sfw=pass1524325355"><em>4</em></a></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2cd74c2f3dbb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/rocknnull/book-review-in-traction-how-any-startup-can-achieve-explosive-customer-growth-2cd74c2f3dbb">[book review] [📚 in 🏎]: Traction: How Any Startup Can Achieve Explosive Customer Growth</a> was originally published in <a href="https://medium.com/rocknnull">Rock and Null</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[book review] [ in ️]: Influence - The Psychology of Persuasion]]></title>
            <link>https://medium.com/rocknnull/book-review-in-%EF%B8%8F-influence-the-psychology-of-persuasion-e00983948d6f?source=rss-cae4a883a0f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/e00983948d6f</guid>
            <category><![CDATA[review]]></category>
            <category><![CDATA[marketing]]></category>
            <category><![CDATA[psychology]]></category>
            <category><![CDATA[book-review]]></category>
            <category><![CDATA[entrepreneurship]]></category>
            <dc:creator><![CDATA[cxr]]></dc:creator>
            <pubDate>Thu, 05 Apr 2018 22:36:00 GMT</pubDate>
            <atom:updated>2018-04-10T12:24:57.642Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*DQlWoYXIKu6124jBxog6oQ.jpeg" /></figure><pre><strong>About the series:</strong> In [📚 in 🏎️] I will try to summarize in super dense notes the gist of a whole book. This is intended as a sneak peak for readers that have not yet read the book and for a reminder trigger for people who did. Enjoy! (P.S. I have links to longer book summaries/reviews at the end of the post.)</pre><p>The author identified 7 weapons of influence that discovered over his career in Psychology. He justifies each and every one of them with multiple examples to illustrate how these rules are working and can be observed in everyday life.</p><p>The weapons/rules of influence:</p><ul><li><strong>Contrast principle<br></strong>Showing the<em> expensive product first</em>, before showing a cheaper product makes it more attractive because there is an implicit comparison.</li><li><strong>Reciprocation</strong><br>Giving a small gift to someone (<em>without</em> asking for something back), might lead to a bigger return later because people don’t like to be indebted.</li><li><strong>Commitment and Consistency<br></strong>People tend to remain compliant to their commitments, <em>once they made them. </em>Having someone commiting to something small/hypothetical before asking for something bigger but related to the commitment will increase the chance of compliance.</li><li><strong>Social Proof<br></strong>Especially in unknown situations, people are influenced with what other people do. This is exploited in everyday life (e.g. putting people in bars just to make them look popular, tip-jar that is pre-filled with money to show that other people already donated, etc).</li><li><strong>Liking<br></strong>We tend to comply more when we the compliance request comes from someone we like. We like people similar to us, attractive people, people that compliment us, etc.</li><li><strong>Authority<br></strong>Authority affects how we interact and perceive people. The higher the authority, the more cautious we are in our conversation and more likely to comply with no questions asked.</li><li><strong>Scarcity<br></strong>People tend to appreciate more something that might <em>lose</em> than something that might <em>win</em>. This is be exploited in auctions, phrasing of offers (e.g. “You are losing $50 per month ….”), etc.</li></ul><blockquote>Longer book reviews/summaries: <a href="https://slooowdown.wordpress.com/2012/09/02/summary-of-influence-the-psychology-of-persuasion-by-robert-b-cialdini/">1</a>, <a href="http://www.georgeambler.com/book-review-influence-the-psychology-of-persuasion/">2</a>, <a href="https://medium.com/@mappmechanic/influence-the-psychology-of-persuasion-book-review-571f8588fd05">3</a></blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e00983948d6f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/rocknnull/book-review-in-%EF%B8%8F-influence-the-psychology-of-persuasion-e00983948d6f">[book review] [📚 in 🏎️]: Influence - The Psychology of Persuasion</a> was originally published in <a href="https://medium.com/rocknnull">Rock and Null</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Setup Android Continuous Integration (CI) for Bitbucket in 1 minute.]]></title>
            <link>https://medium.com/rocknnull/setup-android-continuous-integration-ci-for-bitbucket-in-1-minute-9b72a4f1d745?source=rss-cae4a883a0f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/9b72a4f1d745</guid>
            <category><![CDATA[continuous-integration]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[bitbucket]]></category>
            <dc:creator><![CDATA[cxr]]></dc:creator>
            <pubDate>Sun, 25 Mar 2018 13:45:00 GMT</pubDate>
            <atom:updated>2020-04-20T18:36:08.066Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*cUwjlFY_GE1JM-iGw08Ftg.jpeg" /></figure><p><a href="https://www.rockandnull.com/android-continuous-integration-bitbucket/"><strong>We’ve moved to our own blog :) Read from there!</strong></a></p><h3>Intro</h3><pre><a href="https://www.visualstudio.com/learn/what-is-continuous-integration/">Continuous Integration (CI)</a> is the process of automating the build and testing of code every time a team member commits changes to version control.</pre><p>CI brings benefits for every team, from one-(hu)man-teams to big teams, by <strong>detecting integration errors as quickly as possible</strong>. Individual developers can ensure that the “minor change” they submit without hitting “Run” in Android Studio doesn’t break anything and big teams contributors can ensure that the feature they worked in isolation for the last week doesn’t introduce a regression.</p><p>Atlassian’s <a href="https://bitbucket.org/">Bitbucket</a> is a great version control hosting provider for indie developers, offering not only unlimited private Git repositories but also free (limited amount) CI/CD using their <a href="https://bitbucket.org/product/features/pipelines">Pipelines</a> feature! I have been using Bitbucket for <a href="https://play.google.com/store/apps/details?id=net.miksoft.microtasks&amp;referrer=utm_source%3Dwww.medium.com"><strong>microtasks project</strong></a> but never bothered with setting up CI because I considered it too hard. As it turns out, it’s a <strong>1-minute setup</strong>!</p><h3>1-minute setup</h3><p>All the credit goes to <a href="https://stackoverflow.com/a/40294677/2456568">Ming C from this StackOverflow post</a>. And it’s just <strong>2 easy steps</strong> (actually the “1 minute” estimation might be an overestimation if everything goes right :)</p><h4>Select Pipelines in Bitbucket</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6uJDgQWOnsGDWAneocTdOA.png" /></figure><p>From the side navigation bar in your Bitbucket project, select <strong>Pipelines</strong> and then <strong>Java</strong> (not really necessary, it’s just pre-filling the editor).</p><h4>Commit the Pipeline configuration</h4><p>In the online editor, fill the content of <strong>bitbucker-pipelines.yml:</strong></p><pre>image: <strong>mingc/android-build-box:latest</strong></pre><pre>pipelines:<br>  default:<br>    - step:<br>        script:<br>          <strong>- chmod +x gradlew<br>          - ./gradlew assembleDebug</strong></pre><p><strong>Commit</strong> and that’s all! Now everytime you commit to the main branch, assembleDebug<em> </em>Gradle task will be executed to verify that the app builds just fine. To run your <strong>unit tests</strong> instead of just building, replace assembleDebug with <a href="https://developer.android.com/studio/test/command-line.html#RunTestsGradle">test</a>.</p><h3>(Optionally) Going deeper</h3><h4>Brief Pipelines explanation</h4><p>Pipelines are basically running a <a href="https://www.docker.com/">Docker</a> image and then execute the commands in the <em>scripts </em>section. The <a href="https://github.com/mingchen/docker-android-build-box"><strong>android-build-box image</strong></a> I think contains everything (SDK 16–26, Support Library, Play Services, etc) that a typical modern Android app might need (and more). For more specific needs, you will need to <a href="https://community.atlassian.com/t5/Bitbucket-questions/How-do-I-create-a-docker-image-for-Bitbucket-Pipelines/qaq-p/334724">build your own Docker image</a>.</p><h4>Gradle task(s)</h4><p>You can select to run more than one Gradle task from your Android project by appending more lines to the <em>scripts</em> section (to see all Gradle tasks from Android Studio, <em>View</em> -&gt; <em>Tool Windows</em> -&gt; <em>Gradle</em>). A real CI system will run <strong>tests</strong> to ensure that a new commit does not introduce a regression (i.e. re-introduce an old bug). Be cautious of the time limit the free Bitbucket plan provides, <strong>50 minutes per month</strong>. Running too many tasks/tests might consume this limit pretty quickly.</p><h4>Periodic integration</h4><p>You can also configure the Pipeline to run periodically, like every hour/day/week. If you have a bigger project with multiple contributors, this is probably needed. Just select <strong>Schedules </strong>button from the Pipelines view in Bitbucket.</p><h4>Local Pipelines debug</h4><p>At some point, something in the Docker image, Pipelines, or your project will stop working and you might need to emulate what Pipelines are doing locally to debug the issue. To do this follow the <a href="https://confluence.atlassian.com/bitbucket/debug-your-pipelines-locally-with-docker-838273569.html">instructions in Bitbucket website</a>, or for this specific image:</p><ol><li><a href="https://www.docker.com/">Get Docker</a> and download the <em>android-build-box</em> image (<strong>Warning</strong>: It’s a ~5GB image):</li></ol><pre>docker pull mingc/android-build-box:latest</pre><p>2. Get an interactive shell into the Docker image, with the same restrictions (i.e. RAM, swap memory, etc):</p><pre>docker run -it --volume=/PATH/TO/YOUR/SRC:/localDebugRepo --workdir=&quot;/localDebugRepo&quot; --memory=4g --memory-swap=4g --memory-swappiness=0 --entrypoint=/bin/bash mingc/android-build-box:latest</pre><p>3. Run the commands in the <em>scripts </em>section and debug the issue(s).</p><h3>Conclusion</h3><p>I think that CI is extremely useful for detecting issues early on and since it’s that easy (and free) to set it up, everyone using Bitbucket for version control should have it enabled!</p><p><em>P.S. If you are like me and enjoy being productive throughout the day, check out </em><a href="https://play.google.com/store/apps/details?id=net.miksoft.microtasks&amp;referrer=utm_source%3Dwww.medium.com"><em>microtasks</em></a><em>, a task-as-undismissable-notification manager that helps you remember the small things that matter :)</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=9b72a4f1d745" width="1" height="1" alt=""><hr><p><a href="https://medium.com/rocknnull/setup-android-continuous-integration-ci-for-bitbucket-in-1-minute-9b72a4f1d745">Setup Android Continuous Integration (CI) for Bitbucket in 1 minute.</a> was originally published in <a href="https://medium.com/rocknnull">Rock and Null</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exploring Kotlin using Android Architecture Components (and vice versa)]]></title>
            <link>https://medium.com/rocknnull/exploring-kotlin-using-android-architecture-components-and-vice-versa-aa16e600041a?source=rss-cae4a883a0f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/aa16e600041a</guid>
            <category><![CDATA[android-architecture]]></category>
            <category><![CDATA[app-development]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[kotlin]]></category>
            <category><![CDATA[android]]></category>
            <dc:creator><![CDATA[cxr]]></dc:creator>
            <pubDate>Sat, 13 Jan 2018 22:27:38 GMT</pubDate>
            <atom:updated>2019-02-22T22:29:28.255Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rK0jwo0-Zx4dectQ2uzZJg.jpeg" /></figure><p>Recently, after all this time listening and reading about Kotlin I decided that it was time to give it a try. The best way to do it, I thought, was to write a new Android app from the beginning. Sure, <a href="https://kotlinlang.org/"><strong>Kotlin</strong></a> was designed to be “multi-platform” from the beginning (JVM, Server, JS, Native) but currently, it shines in the Android dev world.</p><p>The only issue was that since my last involvement with Android the new <a href="https://developer.android.com/topic/libraries/architecture/index.html"><strong>Android Architecture Components (AAC)</strong></a> had been introduced by Google and I didn’t have the chance to give them a try either.</p><p>Now, I had 2 new shiny things to try out and to be honest it seemed to be a bit overwhelming at first. If you are in a similar position, I urge you to fear not. These are <strong>not just “shiny things”</strong> but will actually make you <strong>more</strong> <strong>productive</strong> if you have them in your toolkit.</p><p>I will not repeat what you might have already <a href="https://www.google.com/search?q=why+kotlin+for+android">read/heard</a> about the merits of Kotlin. I will try to guide you through AAC using Kotlin and explain as much Kotlin features/syntax as possible in the way. I don’t expect to fully understand Kotlin or AAC by the end of this post, but you will have a taste of what Kotlin and AAC are so when you have the time to take a deeper look.</p><p>Stick to the end that I have some useful links for diving deeper into <strong>Kotlin</strong> and <strong>AAC</strong>.</p><h3><a href="https://developer.android.com/topic/libraries/architecture/lifecycle.html">Lifecycle</a></h3><p>The Android System can <strong>destroy and recreate</strong> an app’s components (e.g. Activity, Fragment) due to memory constraints (e.g. low on RAM) or configuration changes (e.g. switch from Portrait -&gt; Landscape). You might know that Android components have <strong>complicated life cycles</strong>. Each component has its own different lifecycle (e.g. <a href="https://developer.android.com/guide/components/fragments.html#Creating">fragments</a>, <a href="https://developer.android.com/guide/components/activities/activity-lifecycle.html#alc">activities</a>) and this makes things even more complicated to reason about.</p><p>These complicated lifecycles make lives of developers difficult because you might start an operation on an Activity (e.g. network request) and while in progress the Activity can be destroyed and another will be recreated. You will need to show the results of the operation in the new Activity. AAC introduced components (i.e. Activities, Fragments) that are <a href="https://developer.android.com/topic/libraries/architecture/lifecycle.html"><strong>Lifecycle aware</strong></a>. This makes it <strong>easier to reason about </strong>and not having to manually keep track in which lifecycle state each component is.</p><h3><a href="https://developer.android.com/topic/libraries/architecture/livedata.html">LiveData</a></h3><p>This provides an <strong>async mechanism</strong> to provide data changes using the <a href="https://en.wikipedia.org/wiki/Observer_pattern"><strong>Observer pattern</strong></a>. It’s a very similar, yet way simplified version, of the popular and very powerful <a href="https://github.com/ReactiveX/RxJava">RxJava</a>. The big difference is that LiveData is <strong>respecting the Lifecycle of the Android component that is attached to</strong> and delivers data changes only when the component is in “active” state (e.g. when the activity is stopped/destroyed will not try to deliver changes). This avoids memory leaks, crashes due to stopped activities and other <a href="https://developer.android.com/topic/libraries/architecture/livedata.html#the_advantages_of_using_livedata">issues</a>. Too much talk, let’s see a code example:</p><pre><strong><br>private val username </strong>= MutableLiveData&lt;String&gt;()<br><br><em>/* Called on app launch */<br></em><strong>fun </strong>initNetworkRequest() {<br>    <em>/* expensive operation, e.g. network request */<br>    </em><strong>username</strong>.<em>value </em>= <strong>&quot;Peter&quot;<br></strong>}</pre><pre><strong>fun </strong>getUsername(): LiveData&lt;String&gt; {<br>    <strong>return username<br></strong>}</pre><pre><em>// --------------------------------------------------------</em></pre><pre><em>/* Called on Activity creation */<br></em>getUsername().observe(<strong>this</strong>, <em>Observer </em><strong>{ </strong>user <strong>-&gt; </strong>Log.d(TAG, user) <strong>}</strong>)</pre><p>With this approach, even if the Activity is destroyed by the system and another one is created before the request finishes, the correct one will observe and show the results.</p><h4>Kotlin</h4><pre><strong>private val username </strong>= MutableLiveData&lt;String&gt;()</pre><ul><li>New instances are constructed without the <strong>new</strong> keyword, just their class name.</li><li><strong>val</strong> means final. This variable cannot be reassigned.</li><li><strong>var</strong> for a variable that can be reassigned.</li><li>Kotlin is strongly typed, i.e. each variable has an explicit type. If it can be inferred then you can avoid writing it, like in this case. Otherwise, you can also write:<br><strong>val username: </strong>MutableLiveData&lt;String&gt;<strong> </strong>= MutableLiveData&lt;String&gt;</li><li>Visibility modifier <strong>private </strong>means the same thing as in Java, only visible within this class. Most of the <a href="https://kotlinlang.org/docs/reference/visibility-modifiers.html#visibility-modifiers">other modifiers</a> are the same. The default visibility, if there is no modifier specified, is <strong>public</strong>.</li></ul><pre><strong>fun </strong>getUsername(): LiveData&lt;String&gt; {</pre><ul><li>Use <strong>fun </strong>keyword for method declaration.</li><li>The return type comes at the end of the signature.</li><li>There is no <strong>void</strong> in Kotlin (it’s <a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-unit/index.html">Unit</a>), just omit the type to return nothing like in:<br><strong>fun </strong>initNetworkRequest()</li></ul><pre><strong>username</strong>.<em>value </em>= <strong>&quot;Peter&quot;</strong></pre><ul><li>Kotlin is smart enough to convert Java <strong>getValue/setValue</strong> to properties like this (i.e. when running this code you are calling username.setValue() behind the scenes).</li></ul><pre>getUsername().observe(<strong>this</strong>, <em>Observer </em><strong>{ </strong>user <strong>-&gt; </strong>Log.d(TAG, user) <strong>}</strong>)</pre><ul><li>Here an anonymous Observer class is used and Kotlin is automatically doing the work of figuring out which method to override (take a look at the <a href="https://developer.android.com/topic/libraries/architecture/livedata.html#observe_livedata_objects">Java code</a> to help you understand what Kotlin is doing).</li></ul><h3><a href="https://developer.android.com/topic/libraries/architecture/viewmodel.html">ViewModel</a></h3><p>The ViewModel is used to <strong>persist configuration changes</strong> (i.e. Portrait -&gt; Landscape). You can save the logical state of the UI in the ViewModel and decouple it from the Android component (i.e. Activity, Fragment) that can be destroyed at any time. If we combine the previous code with this one:</p><pre><strong>class </strong>MainViewModel : ViewModel() {<br><br>    <strong>private val username </strong>= MutableLiveData&lt;String&gt;()<br><br><em>    </em><strong>fun </strong>initNetworkRequest() {<br>        <em>/* expensive operation, e.g. network request */<br>        </em><strong>username</strong>.<em>value </em>= <strong>&quot;Peter&quot;<br>    </strong>}<br><br>    <strong>fun </strong>getUsername(): LiveData&lt;String&gt; {<br>        <strong>return username<br>    </strong>}<br>}</pre><pre><em>// --------------------------------------------------------</em></pre><pre><em>/* Called on Activity onCreate() */<br></em><strong>viewModel </strong>= ViewModelProviders.of(<strong>this</strong>).get(MainViewModel::<strong>class</strong>.<em>java</em>)<br>getUsername().observe(<strong>this</strong>, <em>Observer </em><strong>{ </strong>text <strong>-&gt; </strong>Log.d(TAG, text) <strong>}</strong>)<br><br><em>/*  Called if there is no active network request */<br></em><strong>viewModel</strong>.initNetworkRequest()</pre><p>No matter how many times the Activity will be destroyed and recreated, the <strong>same ViewModel instance will be used</strong>. Take a look at the <a href="https://developer.android.com/topic/libraries/architecture/viewmodel.html#lifecycle">ViewModel lifecycle</a>. Therefore, you can safely store the state of your UI and on recreation the new Activity will get the latest values.</p><h3><a href="https://developer.android.com/training/data-storage/room/index.html">Room</a></h3><p>Room library provides an easy way to <strong>convert objects</strong> to data stored in a local <strong>SQLite database</strong> on the device. This is useful for persisting data across different app sessions and also for offline usage. Room has 3 main components that you need to define to use it:</p><pre>@Entity<br><strong>data class </strong>User(<br>    @PrimaryKey(autoGenerate = <strong>true</strong>) <strong>val id</strong>: Int? = <strong>null</strong>,<br>    @ColumnInfo(name = <strong>&quot;username&quot;</strong>) <strong>val username</strong>: String) {<em><br></em>}</pre><p>This class <strong>describes the data format </strong>(and how the underline SQL table is defined). This is what you will fill in order to <strong>save</strong> a new row in the database and how the data that are <strong>retrieved</strong> from the database will be returned to you.</p><pre>@Dao<br><strong>interface </strong>UserDao {<br><br>    @Query(<strong>&quot;SELECT * FROM user&quot;</strong>)<br>    <strong>fun </strong>all(): List&lt;User&gt;<br><br>    @Insert<br>    <strong>fun </strong>insertAll(users: List&lt;User&gt;): List&lt;User&gt;<br><br>    @Insert<br>    <strong>fun </strong>insert(user: User): Long<br><br>    @Update<br>    <strong>fun </strong>update(user: User)<br><br>    @Delete<br>    <strong>fun </strong>delete(user: User)<br>}</pre><p>The <strong>Data Access Object </strong>defines how you access your data. Notice that this is just an interface with some annotated methods. Room will create the implementations based on what you provide in the annotated methods.</p><pre>@Database(entities = <em>arrayOf</em>(User::<strong>class</strong>), version = 1)<br><strong>abstract class </strong>Database : RoomDatabase() {<br><br>    <strong>companion object </strong>{<br><br>        <strong>private val DB_NAME </strong>= <strong>&quot;UsersDatabase&quot;<br><br>        </strong>@Volatile <strong>private var INSTANCE</strong>: Database? = <strong>null<br><br>        fun </strong>getInstance(context: Context): Database =<br>                <strong>INSTANCE </strong>?: <em>synchronized</em>(<strong>this</strong>) <strong>{<br>                    INSTANCE </strong>?: buildDatabase(context).<em>also                     <br>                        </em><strong>{ INSTANCE </strong>= <strong>it }<br>                }<br><br>        private fun </strong>buildDatabase(context: Context) =<br>                Room.databaseBuilder(context.<em>applicationContext</em>,<br>                        Database::<strong>class</strong>.<em>java</em>, <strong>DB_NAME</strong>)<br>                        .build()<br>    }<br>}</pre><p>This the main access point for the database. It looks complicated because it was taken from a <a href="https://github.com/googlesamples/android-architecture-components/blob/master/BasicRxJavaSampleKotlin/app/src/main/java/com/example/android/observability/persistence/UsersDatabase.kt">sample app</a> from Google, but I find it more robust than the one provided the docs.</p><h4>Kotlin</h4><pre><strong>data class </strong>User(<strong>val id</strong>: Int? = <strong>null</strong>, <strong>val username</strong>: String)</pre><ul><li><a href="https://kotlinlang.org/docs/reference/data-classes.html"><strong>data</strong></a> keyword is used for value classes that their aim is just to hold data. All the methods such equals()/hashCode()/toString()/copy() are created automatically.</li><li>Using the variables after the class name you declare them as (public) member variables. Since <strong>val </strong>is used these are <strong>immutable</strong> member variables.</li><li><strong>Int?</strong> means that this variable is allowed to take <strong>null </strong>as its value. Without ‘<strong>?</strong>’ at the end of the variable type, null is not allowed.</li></ul><pre><strong>companion object </strong>{ </pre><ul><li>This is similar to Java <strong>static</strong>. Of course, <a href="https://kotlinlang.org/docs/reference/object-declarations.html#companion-objects">there are differences</a>, such as that you can pass this object around and it can implement interfaces.</li></ul><pre><strong>INSTANCE </strong>?: <em>synchronized</em>(<strong>this</strong>) <strong>{</strong></pre><ul><li>The <a href="https://kotlinlang.org/docs/reference/null-safety.html#elvis-operator"><strong>?: operator</strong></a> can be used to return a value if it’s not null, otherwise to return what is right of the operator. It replaces all the <strong>null-safe if statements</strong> in Java.</li></ul><h3>Afterword / Further reading</h3><p>In case you are curious, the app I created is <a href="https://play.google.com/store/apps/details?id=net.miksoft.microtasks&amp;hl=en"><strong>microtasks</strong></a> and I would be delighted to try it and give feedback (using the in-app “Send feedback” option :). Also, if you are looking to promote your apps using promo codes take a look at <a href="https://www.promies.net/developers/"><strong>Promies</strong></a>!</p><p>For <strong>Kotlin, </strong>I had great fun using <a href="https://kotlinlang.org/docs/tutorials/koans.html">Kotlin Koans</a> (available <a href="https://try.kotlinlang.org/#/Kotlin%20Koans/Introduction/Hello,%20world!/Task.kt">in-browser</a> as well!) to learn the syntax and features interactively. Also, as a cheatsheet, I used the <a href="https://learnxinyminutes.com/docs/kotlin/">Learn X in Y minutes</a>. Kotlin is a modern language with a lot of features. I did learn the basics but there are so many advanced features that I will be in learning mode for a while.</p><p>For <strong>Android Architecture Components</strong>, I relied mainly on the <a href="https://developer.android.com/topic/libraries/architecture/index.html">official documentation</a>. I found it easy to follow and with good examples. Also, I found this <a href="https://developer.android.com/topic/libraries/architecture/guide.html#addendum">Guide to App Architecture</a> to be really good at giving you a high-level overview on how to structure your app.</p><p>I hope you found this useful! Happy coding using Kotlin and AAC! :)</p><p><em>P.S. If you are like me and enjoy being productive throughout the day, check out </em><a href="https://play.google.com/store/apps/details?id=net.miksoft.microtasks&amp;referrer=utm_source%3Dwww.medium.com"><em>microtasks</em></a><em>, a task-as-undismissable-notification manager that helps you remember the small things that matter :)</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aa16e600041a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/rocknnull/exploring-kotlin-using-android-architecture-components-and-vice-versa-aa16e600041a">Exploring Kotlin using Android Architecture Components (and vice versa)</a> was originally published in <a href="https://medium.com/rocknnull">Rock and Null</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[[book review] The mythical “viral post”.]]></title>
            <link>https://medium.com/rocknnull/the-mythical-viral-post-d5c17e6fa451?source=rss-cae4a883a0f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/d5c17e6fa451</guid>
            <category><![CDATA[marketing]]></category>
            <category><![CDATA[review]]></category>
            <category><![CDATA[promotion]]></category>
            <category><![CDATA[social-media]]></category>
            <category><![CDATA[viral-marketing]]></category>
            <dc:creator><![CDATA[cxr]]></dc:creator>
            <pubDate>Sat, 23 Sep 2017 20:11:25 GMT</pubDate>
            <atom:updated>2018-04-10T12:25:24.221Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*op6K4uOBEmi6bb6Np8ZSZg.png" /></figure><p>You’ve probably heard that you need to split the time working on your project <a href="https://www.amazon.com/dp/B00TY3ZOMS/">50/50 on development and traction/promotion</a>. If you are like me, you’ve probably never done it.</p><p>Because it’s hard. I mean, you know that Google, Facebook, and others are offering ads that you can purchase to promote your app. You know that there are forums, communities and other places that you can post. But <strong>the most important part</strong> is that you are not just aiming for the people that see the post. You are aiming for people to find your app and <strong>then spread it</strong>. But, what should you write to those ads? What is the right content for the post in the forum to accomplish this mythical “viral post”? I don’t have the answer yet but I think that I have some guidelines after reading “<a href="https://www.amazon.com/Contagious-Build-Word-Mouth-Digital-ebook/dp/B008J3ZNLQ/ref=sr_1_1?ie=UTF8&amp;qid=1506173508&amp;sr=8-1&amp;keywords=Contagious%3A+How+to+Build+Word+of+Mouth+in+the+Digital+Age">Contagious: How to Build Word of Mouth in the Digital Age</a>”. If you enjoy this post, I strongly advise you to go and read the full book since I only talk about <strong>some of the principles</strong> that I find most important in my case.</p><h4>Triggers</h4><p>How many times you’ve thought of “having a break” and the KitKat’s slogan of “have a break, have a KitKat” jumped into your head? It happens to me all the time. Also, it happens to everyone else and most of the times not even consciously. If you choose your wording carefully, you can hopefully <strong>associate an everyday trigger</strong> with your app to make it come to mind more often.</p><h4>Practical value</h4><p>Does your app have a practical value that can help people solve a problem? If yes, talk directly about it with the aim to package your knowledge into a shareable bit that people can spread when they or someone they know <strong>face the problem you are solving</strong>. Do not fall into the <a href="https://hackernoon.com/for-the-love-of-god-please-tell-me-what-your-company-does-c2f0b835ab92">typical mistake </a>of over-decorating your description to the point that no one understands what you are actually doing.</p><h4>Emotion</h4><p>If your product does not have a strong practical value, make sure that your post, ad or video <strong>emits emotion</strong>. Nowadays, creating a video promo for your app/game is quite common. If after viewing your video the users have shed a tear, for instance, is highly probable that they are going to share it forward. Emotional posts, and not necessarily posts that emit positive emotions (anger is quite shareable), tend to make people share things more.</p><h4>Stories</h4><p>In case you have a lot of real-estate to write, e.g. in a forum post, you can use a story to embed your message. Nothing is more shareable than <strong>a good story to tell your friends</strong>. But do not forget that your app/game must be a crucial part of the story, not just a detail or a “secondary character”. Otherwise, the story might be shared but without the details. I believe this is the hardest guideline to follow, but still, there are some cases that might apply.</p><h4>Various useful tips</h4><ul><li><strong>Exclusivity</strong>: People love to feel special. It might be counter-intuitive but in some cases restricting access to your product (e.g. waitlist, refer only) might bring more traction.</li><li><strong>Strike-through sales</strong>: When seeing a strike-through price you automatically compare the price to the original. So having a significant (but reasonable) higher price as the original might make your offering look like a better deal.</li></ul><h3>Conclusion</h3><p>This is by no means a complete list of what is offered in the <a href="https://www.amazon.com/Contagious-Build-Word-Mouth-Digital-ebook/dp/B008J3ZNLQ/ref=sr_1_1?ie=UTF8&amp;qid=1506173508&amp;sr=8-1&amp;keywords=Contagious%3A+How+to+Build+Word+of+Mouth+in+the+Digital+Age">book</a>. If you enjoyed what you’ve read you should definitely take a look at the book. Nevertheless, I hope that these short guidelines will help you write those posts that will become viral, or at least more shareable.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d5c17e6fa451" width="1" height="1" alt=""><hr><p><a href="https://medium.com/rocknnull/the-mythical-viral-post-d5c17e6fa451">[book review] The mythical “viral post”.</a> was originally published in <a href="https://medium.com/rocknnull">Rock and Null</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Playing with machine learning: An introduction using Keras + TensorFlow.]]></title>
            <link>https://medium.com/rocknnull/playing-with-machine-learning-a-practical-example-using-keras-tensorflow-790375cd1abb?source=rss-cae4a883a0f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/790375cd1abb</guid>
            <category><![CDATA[introduction]]></category>
            <category><![CDATA[machine-learning]]></category>
            <category><![CDATA[neural-networks]]></category>
            <category><![CDATA[keras]]></category>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[cxr]]></dc:creator>
            <pubDate>Sun, 14 May 2017 23:18:49 GMT</pubDate>
            <atom:updated>2017-05-14T23:20:29.889Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8nZMB35UGT6GWBmCtjW49Q.jpeg" /></figure><p>I did some artificial intelligence (AI) courses while I was studying but I never did anything outside the classroom. Machine learning (ML), and AI in general is the most trending subject in the tech scene right now.</p><p>And for a good reason. We are in the “democratizing” era of AI. Tools are being developed and popularized that are aimed to be used by everyone, not just the small academic community. If you want an introduction to the inner workings of Machine Learning and get an intuition on how things work, I cannot recommend enough the <a href="https://www.coursera.org/learn/machine-learning/home/welcome">Machine Learning course</a> by <a href="http://www.andrewng.org/">Andrew Ng</a>. I will try to explain some basic theory here, but I am just exploring/learning, so follow with caution :)</p><h3>A bit of theory</h3><p><em>Artificial Intelligence</em> (AI) is a “superset” of <em>Machine Learning</em> (ML) and <em>Neural Networks</em> (NN) is a computational model used in ML. NN is a <em>Supervised Learning</em> technique which means that a dataset with multiple examples with the “right answers” is needed for the model to “learn”. To get to the NN, we have to define some more stuff along the way.</p><h4>Linear Regression</h4><p>A <em>regression problem</em> means we have to predict a real-valued output. For example, let’s use the (typical) house pricing example where we only have 1 characteristic (feature), the area of the house, and we want to predict the house price. Given a set of area(X)/house-price(Y) pairs (dataset) we can plot the following graph (where each orange dot is an area/house-price pair):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*GSDSvul9MxW7BEXjADhY6g.png" /></figure><p>From basic linear algebra we know that the equation of the line is in the form Y = θ0 + θ1*X. This is called the <em>hypothesis</em> and what we are looking for are the values for θ0 and θ1 (called the <em>parameters</em>). If we find a good set of θ0, θ1 then we will be able to predict a house price given the area of any house. To do that, first we need to define the <em>error/cost</em> which is the difference of our hypothesis from the actual value:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*cV7wto6jIBfGb78ULQRn7Q.png" /></figure><p>There are many ways to calculate the <em>cost function</em> with one of the most popular to be the <a href="https://en.wikipedia.org/wiki/Mean_squared_error"><em>mean squared error</em></a>. Then all we need to do is to start from a (most of the times random) initial assignment of θ0, θ1 and using an <em>iterative optimization algorithm </em>(like <a href="https://en.wikipedia.org/wiki/Gradient_descent"><em>Gradient Descent</em></a>) to minimize the cost of our hypothesis by iterating over our dataset.</p><h4>Logistic Regression</h4><p>But what if we do not want a real-valued output and we would like a probability? We can use Logistic Regression where the hypothesis outputs real-valued numbers from 0 to 1. To do that we can use the <em>Sigmoid function</em> to map any real-valued number of our hypothesis to the (0, 1) interval:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/320/1*rXCCslP_TA2zCVP3FueN3Q.png" /><figcaption>Sigmoid function</figcaption></figure><p>We can then adapt the cost function and use the same optimization algorithms to find a hypothesis that minimizes the cost.</p><h4>Neural Networks</h4><p>But most of the real world problems are not linearly separable. It turns out that connecting small units that do logistic regression between them is one of the most computationally efficient ways to compute non-linear hypothesis:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/392/1*99E-1yB-zmlVykf7qI_Lxw.png" /></figure><p>Every node in the graph, except from input layer, represents simple logistic regression with inputs the incoming edges and outputs the outcoming edges. The rightmost node, the output layer, will give us a final probability given the input characteristics (features).</p><h4>Common problems and validation set</h4><p>The two most common problems are <em>underfitting</em> and <em>overfitting</em> (with the latter to be more popular). Underfitting occurs when your hypothesis does not fit the data well enough, overfitting occurs when the hypothesis is too closely fit the training dataset and does not generalize well to new unseen data. To evaluate our model, we split our dataset into the <em>training and validation set</em>. Then we use the training set to fit our model and test it with the unseen validation set.</p><h3>TensorFlow + Keras</h3><p>If you are following any tech news site, you’ve probably heard of <a href="https://www.tensorflow.org/">TensorFlow</a>. It’s Google’s machine learning framework that was open-sourced in 2015 and met with <a href="https://github.com/blog/2268-top-open-source-launches-on-github">huge success</a> from the open-source community. Unfortunately, the framework although powerful is highly technical and difficult to use by a data analyst/machine learning “outsider”. This is where <a href="https://keras.io/">Keras</a> comes in, a higher level (= user friendlier) layer on top of TensorFlow (and other ML frameworks) that allows you to make ML and more specifically Neural Networks (NN) faster and easier.</p><h3>Setup</h3><p>I used the <a href="https://www.continuum.io/downloads">Anaconda Python distribution</a> and found the setup of the development environment relatively easy. After installing Anaconda for your platform (you can also try <a href="https://conda.io/miniconda.html">Minicoda</a> for a lighter version if you are short on space), <em>CD</em> to the <em>bin</em> directory of the distribution and run (Linux &amp; MacOS):</p><blockquote>./pip install tensorflow<br>./pip install keras<br>./pip install pandas</blockquote><p>That’s it, if everything works fine, you are all set. You can try the excellent <a href="https://www.jetbrains.com/pycharm/download/">PyCharm Community Edition</a> if you are a fan of the JetBrains’ family of IDEs.</p><h4>Learn Python</h4><p>“But I don’t know python!” I hear you saying. Neither did I. I just learned the basics and I keep learning. For my introduction to the language, I used the interactive <a href="https://www.jetbrains.com/pycharm-edu/download/">PyCharm Edu</a> which is a desktop app with an IDE and a Python interpreter with the only aim in life to educate you about Python. The basic tutorial consists of a set of unit tests that you have to complete a small part for them to run successfully. I found Python in general to be a very pleasant to use language.</p><h3>The dataset</h3><p>Let’s start with the actual script. I used the <a href="https://www.kaggle.com/joniarroba/noshowappointments">“Medical Appointments No Show”</a> from <a href="https://www.kaggle.com">Kaggle</a> as my dataset for this experiment. This is a dataset that contains 300k medical appointments with characteristics (features) of the patients and whether the patient showed up in the appointment or not. We will try to create a Neural Network that given the characteristics of a patient will predict the probability of that patient showing up.</p><h4>Preprocess the dataset</h4><p>The first step is to prepare our data before training our model. We read our data and separate them into X and Y; X are the patient’s characteristics (features) and Y is whether the patient shows up or not. Use the following to have a glimpse at the structure of our dataset:</p><pre><strong>import </strong>pandas <strong>as </strong>pds<br><br>dataframeX = pds.read_csv(<strong>&#39;No-show-Issue-Comma-300k.csv&#39;</strong>, usecols=[0, 1, 4, 6, 7, 8, 9, 10, 11, 12, 13])<br>dataframeY = pds.read_csv(<strong>&#39;No-show-Issue-Comma-300k.csv&#39;</strong>, usecols=[5])<br><br>print(dataframeX.head())<br>print(dataframeY.head())</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1008/1*Y7DzB_zz_irzRikmd5xF6Q.png" /></figure><p>As you can see, some of the features are not represented as numeric values. We can change this using the powerful <a href="http://pandas.pydata.org/">Pandas</a> library:</p><pre><strong>def </strong>weekdayToInt(weekday):<br>    <strong>return </strong>{<br>        <strong>&#39;Monday&#39;</strong>: 0,<br>        <strong>&#39;Tuesday&#39;</strong>: 1,<br>        <strong>&#39;Wednesday&#39;</strong>: 2,<br>        <strong>&#39;Thursday&#39;</strong>: 3,<br>        <strong>&#39;Friday&#39;</strong>: 4,<br>        <strong>&#39;Saturday&#39;</strong>: 5,<br>        <strong>&#39;Sunday&#39;</strong>: 6<br>    }[weekday]<br><br><strong>def </strong>genderToInt(gender):<br>    <strong>if </strong>gender == <strong>&#39;M&#39;</strong>:<br>        <strong>return </strong>0<br>    <strong>else</strong>:<br>        <strong>return </strong>1<br><br><strong>def </strong>statusToInt(status):<br>    <strong>if </strong>status == <strong>&#39;Show-Up&#39;</strong>:<br>        <strong>return </strong>1<br>    <strong>else</strong>:<br>        <strong>return </strong>0<br><br>dataframeX.DayOfTheWeek = dataframeX.DayOfTheWeek.apply(weekdayToInt)<br>dataframeX.Gender = dataframeX.Gender.apply(genderToInt)<br>dataframeY.Status = dataframeY.Status.apply(statusToInt)<br><br>print(dataframeX.head())<br>print(dataframeY.head())</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*HYAUYTeTO2IwTcSekXcI_g.png" /></figure><p>Now we have replaced the values for each feature with a unique numeric value. We do the same for the target dataframeY.</p><h3>The Neural Network</h3><p>Time to create our Neural Network. Creating and training a NN in Keras is really easy. You describe the model as sequential layers that data flow through. Then you feed it the dataset we prepared in the earlier section and train the model:</p><pre><em># 1<br></em><strong>import </strong>numpy <strong>as </strong>np<br>seed = 7<br>np.random.seed(seed)<br><br><em># 2<br></em><strong>from </strong>keras.models <strong>import </strong>Sequential<br><strong>from </strong>keras.layers <strong>import </strong>Dense<br>model = Sequential()<br>model.add(Dense(12, input_shape=(11,), init=<strong>&#39;uniform&#39;</strong>, activation=<strong>&#39;sigmoid&#39;</strong>))<br>model.add(Dense(12, init=<strong>&#39;uniform&#39;</strong>, activation=<strong>&#39;sigmoid&#39;</strong>))<br>model.add(Dense(12, init=<strong>&#39;uniform&#39;</strong>, activation=<strong>&#39;sigmoid&#39;</strong>))<br>model.add(Dense(1, init=<strong>&#39;uniform&#39;</strong>, activation=<strong>&#39;sigmoid&#39;</strong>))<br>model.summary()<br><br><em># 3<br></em><strong>import </strong>keras<br>tbCallBack = keras.callbacks.TensorBoard(log_dir=<strong>&#39;/tmp/keras_logs&#39;</strong>, write_graph=<strong>True</strong>)<br><br><em># 4<br></em>model.compile(loss=<strong>&#39;mean_squared_error&#39;</strong>, optimizer=<strong>&#39;adam&#39;</strong>, metrics=[<strong>&#39;accuracy&#39;</strong>])<br>model.fit(dataframeX.values, dataframeY.values, epochs=9, batch_size=50,  verbose=1, validation_split=0.3, callbacks=[tbCallBack])</pre><p>Let’s take it step by step and I will do my best to explain concisely what is happening.</p><p><strong>#1</strong>: We use a constant seed for our random number generator to create the same pseudo-random numbers each time. This comes handy when we want to try different models and to compare their performances.<br><strong>#2</strong>: Define the NN as with fully connected layers with 12 nodes each that are using the <em>sigmoid</em> function.<br><strong>#3</strong>: Needed to use the TensorBoard tool to visualize the model training.<br><strong>#4</strong>: Train our model using the defined optimizer and loss function. <em>Epoch</em> is the number of times (iterations) the whole data set will go through the network, <em>validation_split</em> is how much data from the dataset to hold back just to validate the performance of the model.</p><p>We can now make predictions using our trained model using the model.predict() function.</p><h4>TensorBoard</h4><p>We can use the TensorBoard tool to visualize the training of our model by running the following inside the Anaconda bin folder (we defined the path in #3 of the previous section):</p><blockquote>./tensorboard — logdir=’/tmp/keras_logs’</blockquote><h3>Conclusion</h3><p>Machine Learning and Neural Networks are powerful and using TensorFlow+Keras can become fun as well. I have just scratched the surface of the subject in this post but I hope that I gave you a glimpse on what you can do with a few lines of code. I will keep learning about the subject and maybe come back with something more advanced (and useful)!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=790375cd1abb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/rocknnull/playing-with-machine-learning-a-practical-example-using-keras-tensorflow-790375cd1abb">Playing with machine learning: An introduction using Keras + TensorFlow.</a> was originally published in <a href="https://medium.com/rocknnull">Rock and Null</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The lost droid and the magic Dagger: an intro to dependency injection for Android.]]></title>
            <link>https://medium.com/rocknnull/the-lost-droid-and-the-magic-dagger-an-intro-to-dependency-injection-for-android-c686f4399117?source=rss-cae4a883a0f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/c686f4399117</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[android-app-development]]></category>
            <category><![CDATA[dagger-2]]></category>
            <category><![CDATA[android]]></category>
            <category><![CDATA[dependency-injection]]></category>
            <dc:creator><![CDATA[cxr]]></dc:creator>
            <pubDate>Tue, 14 Feb 2017 21:20:53 GMT</pubDate>
            <atom:updated>2018-04-04T22:42:06.064Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vTbuinOw6XYvuqGmvMmo1w.png" /></figure><h3>Definitions and advantages</h3><p>You might have heard the term <a href="https://en.m.wikipedia.org/wiki/Dependency_injection">dependency injection</a> before. You might have even tried to Google it and stumbled upon a definition that introduced 2 new unknown terms (i<a href="https://en.m.wikipedia.org/wiki/Inversion_of_control">nversion of control</a>, <a href="https://en.m.wikipedia.org/wiki/Dependency_injection">dependency injection pattern</a>). Personally, I find the following definition to be the most descriptive:</p><blockquote>Dependency injection for five-year-olds:</blockquote><blockquote>When you go and get things out of the refrigerator for yourself, you can cause problems. You might leave the door open, you might get something Mommy or Daddy doesn’t want you to have. You might even be looking for something we don’t even have or which has expired.</blockquote><blockquote>What you should be doing is stating a need, &quot;I need something to drink with lunch,&quot; and then we will make sure you have something when you sit down to eat.</blockquote><blockquote>- <a href="http://stackoverflow.com/a/1638961">StackOverflow answer</a></blockquote><p>In my own words, instead of being responsible <strong>for creating and providing</strong> all the dependencies an object needs, a magic <strong>“framework” takes this responsibility</strong>. This approach has many advantages, with the most important being:</p><ul><li>Since the framework is responsible for providing the dependencies, we can easily change an implementation of an abstraction without making a lot of changes.</li><li>When testing, we can easily replace the real dependencies with fake/mock implementations.</li><li>Dependency fulfilling for complex objects (i.e. objects that depend on objects that depend on other objects, multiple levels of dependencies) becomes easy since the framework takes care to figure it out.</li></ul><h3>Dagger 2</h3><p><a href="https://google.github.io/dagger/">Dagger 2</a> is a popular dependency injection (DI) framework for Java and especially popular in Android. The main reason is that it <strong>generates all the required code</strong> and does not use any reflection, which is slow in general but especially heavy in mobile. This generate-all-the-code approach has the advantage that any mistake regarding the dependency graph will be caught during <strong>compile-time</strong> instead of run-time. The downside is that Dagger is considered less flexible than other DI frameworks out there, but the speed and compile-time safety that offers make up for its rigidness.</p><h3>Concepts</h3><p>Like every framework, Dagger has its own “<strong>vocabulary</strong>” that you need to learn in order to use it. If you used another DI framework before, you will surely find familiar terms.</p><h4>Module</h4><p>A class annotated with <strong>@Module</strong> that specifies what and how you provide a dependency. The what is defined by the return type of a <strong>@Provides </strong>annotated method. The method name does not matter.</p><p>The following example is fairly simple. Let’s suppose that <em>MovieDbHelper</em> is an interface and <em>MovieDbHelperImpl</em> is a respective concrete implementation. Every time some part of the app requests a <em>MovieDbHelper</em>, the provideMovieDbHelper() will execute and provide the dependency with an implementation of the requested interface.</p><pre><strong>@Module<br></strong>class ApplicationModule {<br><br>    <strong>@Provides</strong><br>    MovieDbHelper provideMovieDbHelper() {<br>        return new MovieDbHelperImpl();<br>    }<br>}</pre><p>What if the <em>MovieDbHelperImpl</em> needed its own dependencies in order to be instantiated? Adding the dependencies as parameters in the provideMovieDbHelper(..) will make Dagger look for another @Provides method to fulfill the dependencies.</p><p>Creating Singletons is easy with Dagger; just annotate the @Provide annotated method with <strong>@Singleton</strong> to ensure that only a single instance will be returned when requested.</p><pre>@Module<br>class ApplicationModule {<br><br>    private Context context;<br><br>    ApplicationModule(Context context) {<br>        this.context = context;<br>    }<br><br>    <strong>@Provides</strong><br>    <strong>Context</strong> providesContext() {<br>        return context;<br>    }<br><br>    @Provides<br>    <strong>@Singleton</strong><br>    MovieDbHelper provideMovieDbHelper(<strong>Context context</strong>) {<br>        return new MovieDbHelperImpl(context);<br>    }<br>}</pre><h4>Inject</h4><p>A class can request its dependencies from the DI framework by annotating with @Inject its <strong>constructor</strong>, <strong>functions</strong> or <strong>member variables</strong>.</p><pre>class MovieDbHelperImpl {</pre><pre>    <strong>@Inject</strong><br>    MovieDbHelperImpl(Context context) {<br>        this.context = context;<br>    }</pre><pre>    [...]<br>}</pre><p>Annotating a <strong>constructor with @Inject</strong> makes it discoverable to Dagger. After the above example, any other class that requests a <em>MovieDbHelperImpl</em> will get an instance, without requiring a @Provides method in a Module.</p><p>Constructor injection works fine for your own classes that you have total control over when to instantiate them. This is not the case for many Android specific objects such as Activities, Fragments, etc that are instantiated and provided by the system. In this case, you have to use injection of functions or member variables.</p><pre>class SearchMoviesActivity extends AppCompatActivity {<br><br>    <strong>@Inject</strong> SearchMoviesPresenter presenter;</pre><pre>    [...]<br>}</pre><pre>class SearchMoviesActivity extends AppCompatActivity {<br><br>    SearchMoviesPresenter presenter;<br><br>    <strong>@Inject</strong><br>    void onInject(SearchMoviesPresenter presenter) {<br>        this.presenter = presenter;<br>    }</pre><pre>    [...]<br>}</pre><h4>Component</h4><p>Components are the glue between <em>Modules</em> and <em>Injection targets</em>. In other DI frameworks, you might find them with the name Injectors, which I find a more descriptive name for their functionality.</p><p>They are interfaces that are annotated with <strong>@Component</strong> and indicate which <strong>@Module</strong>(s) are including (i.e. which dependencies they know about and they can provide) and the injection targets that they can inject (i.e. the objects that request dependencies with the <strong>@Inject</strong> annotation).</p><pre><strong>@Component</strong>(<strong>modules</strong> = {ApplicationModule.class})<br>interface ApplicationComponent {</pre><pre>    void inject(SearchMoviesActivity searchMoviesActivity);</pre><pre>}</pre><p>In order to actually use the Component to inject your injection targets (in the example above the <em>SearchMoviesActivity</em>), Dagger will generate an implementation of this interface prefixed with the word “Dagger” when your project is re-build. For example, to inject the dependencies requested by <em>SearchMoviesActivity </em>(using the @Inject annotated constructors/functions/variables) you need to create the component and inject the activity. If you have Modules that do not have a no-arguments constructor, you need to instantiate the module before creating the component.</p><pre>public class SearchMoviesActivity extends AppCompatActivity {<br><br>    private ApplicationComponent applicationComponent;<br><br>    @Override<br>    public void onCreate() {<br>        super.onCreate();<br><br>        applicationComponent = <strong>DaggerApplicationComponent</strong><br>                .<em>builder</em>()<br>                .<strong>applicationModule</strong>(<br>                   new ApplicationModule(getApplicationContext()))<br>                .build();<br>        <br>        applicationComponent.<strong>inject(this)</strong>;<br>    }</pre><pre>    [...]<br>}</pre><h4>Scopes, Qualifiers, Subcomponents and more</h4><p>This post covered just the tip of the iceberg; Dagger 2 has <a href="https://google.github.io/dagger/users-guide.html">many more features</a> to explore. Maybe I will try to cover them in a future post.</p><h3>Simple sample setup</h3><p>Instead of going on and overwhelm you with even more concepts, I will try to apply what are covered until now to show how you can use DI in a simple Android app. This is not an ideal setup, it’s using only a single component for the whole app but it can work for small apps. Ideally, you would want to have multiple components/subcomponents for each independent unit in your app.</p><h4>Setup Dagger</h4><p>Include the following lines in your app-level gradle file (app/build.gradle).</p><pre>dependencies {<br>    compile &quot;com.google.dagger:dagger:2.9&quot;<br>    annotationProcessor &quot;com.google.dagger:dagger-compiler:2.9&quot;<br>    provided &quot;javax.annotation:jsr250-api:1.0&quot;<br>}</pre><h4>Application Module</h4><p>A module that will provide the application context (and potentially other app-wide dependencies).</p><pre>@Module<br>public class ApplicationModule {<br><br>    private Application app;<br><br>    public ApplicationModule(Application app) {<br>        this.app = app;<br>    }<br><br>    @Provides<br>    @Singleton<br>    Context providesContext() {<br>        return app;<br>    }<br><br>}</pre><h4>Application Component</h4><p>The injector that needs to have a function for all the classes that can be injected. In this simple setup, you need to have an inject function for each Activity in the app.</p><pre>@Component(modules = {ApplicationModule.class})<br>public interface ApplicationComponent {<br><br>    void inject(MainMenuActivity mainMenuActivity);<br>    <br>    void inject(PlayGameActivity playGameActivity);<br>}</pre><p><strong>Custom application<br></strong>The single component that we have, will be instantiated and be accessible from here.</p><pre>public class MyApplication extends Application {<br><br>    private ApplicationComponent applicationComponent;<br><br>    @Override<br>    public void onCreate() {<br>        super.onCreate();<br><br>        applicationComponent = DaggerApplicationComponent<br>                .<em>builder</em>()<br>                .applicationModule(<br>                   new ApplicationModule(getApplicationContext()))<br>                .build();<br>    }<br><br>    public ApplicationComponent getComponent() {<br>        return applicationComponent;<br>    }<br>}</pre><p>Don’t forget that you need to modify the <em>AndroidManifest.xml</em> to declare you custom Application class.</p><pre>&lt;application<br>    android:name=&quot;.application.MyApplication&quot;<br>    [...]</pre><h4>Base Activity</h4><p>All the activities in the app will extend this base class that will provide (a kind of) a convenient way to inject each activity. In onCreate(..), it retrieves the component and calls the abstract method inject(..) that is implemented by each Activity.</p><pre>public abstract class BaseActivity extends AppCompatActivity {<br><br>    @Override<br>    protected void onCreate(Bundle savedInstanceState) {<br>        super.onCreate(savedInstanceState);<br>        inject(((MyApplication) getApplication()).getComponent());<br>    }<br><br>    <em>/**<br>     * Implement and call component.inject(this) for dependency<br>     * injection of this Activity.<br>     */<br>    </em>protected abstract void inject(ApplicationComponent component);<br>}</pre><h4>Every activity</h4><p>The activities have to call the super.onCreate(..) and implement the inject(..).</p><p>The Component needs to have an appropriate inject(..) function that takes as a parameter the current activity. Having only an injection method for the base class (e.g. inject(BaseActivity activity)) will not work.</p><pre>public class MainMenuActivity extends BaseActivity {<br><br>    @Inject MainMenuPresenter presenter;</pre><pre>    @Override<br>    public void onCreate(Bundle savedInstanceState) {<br>        super.onCreate(savedInstanceState);<br>        [...]        <br>    });<br><em><br>    </em>@Override<br>    protected void inject(ApplicationComponent component) {<br>        component.inject(this);<br>    }</pre><pre>    [...]<br>}</pre><h4>Every Presenter or another object that can be injected</h4><p>Don’t forget that for Dagger to be able to know (and inject) an object, the constructor must be annotated with @Inject or it must be included in a Module.</p><pre>public class MainMenuPresenter {<br><br>    @Inject<br>    MainMenuPresenter() {<br>       [...]<br>    }<br>}</pre><h3>Conclusion</h3><p>This was just a taste of what dependency injection looks like and how it can be used in a very very simple Android app using Dagger 2. If you want to use it in a more complex app you should dig a little more and learn concepts such as Scopes and Subcomponents before using it in your app. Dagger 2 is a really powerful, efficient, and actively developed DI framework that I enjoyed working with. I hope you will enjoy learning and working with it as well!</p><p><em>P.S. If you are like me and enjoy being productive throughout the day, check out </em><a href="https://play.google.com/store/apps/details?id=net.miksoft.microtasks&amp;referrer=utm_source%3Dwww.medium.com"><em>microtasks</em></a><em>, a task-as-undismissable-notification manager that helps you remember the small things that matter :)</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c686f4399117" width="1" height="1" alt=""><hr><p><a href="https://medium.com/rocknnull/the-lost-droid-and-the-magic-dagger-an-intro-to-dependency-injection-for-android-c686f4399117">The lost droid and the magic Dagger: an intro to dependency injection for Android.</a> was originally published in <a href="https://medium.com/rocknnull">Rock and Null</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[An adventure with Alexa in Java land.]]></title>
            <link>https://medium.com/rocknnull/an-adventure-with-alexa-in-java-land-2a2b5dbe127f?source=rss-cae4a883a0f6------2</link>
            <guid isPermaLink="false">https://medium.com/p/2a2b5dbe127f</guid>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[amazon-echo]]></category>
            <category><![CDATA[alexa]]></category>
            <category><![CDATA[java-development]]></category>
            <dc:creator><![CDATA[cxr]]></dc:creator>
            <pubDate>Mon, 19 Dec 2016 22:52:30 GMT</pubDate>
            <atom:updated>2016-12-22T09:59:32.538Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Y0gu7BC1nNenwqi2GMFY1g.png" /></figure><p>Alexa and the Amazon Echo, in general, seem to be a hot toy in (the tech) town. Recently, I got my hands on an <a href="https://www.amazon.com/All-New-Amazon-Echo-Dot-Add-Alexa-To-Any-Room/dp/B01DFKC2SO">Echo Dot</a> (2nd edition) and I found it a great device, especially for listening to music. Nevertheless, I believe that its <strong>voice recognition</strong> capabilities (you might need to say things more than once) and its “<strong>intelligence</strong>” (it doesn’t seem to understand natural language very well) still need work. I might not be fully convinced yet that voice controlled devices will be the next big thing (in their current form) but that doesn’t mean that playing and developing on them is not fun.</p><p>In this post, I will attempt to guide you through the <strong>basics</strong> of how an <strong>Alexa skill</strong> (this is how “apps” are called) can be created using <strong>Java</strong>. I might not get deep into technical details or provide step-by-step instructions. My aim is to give you a higher level overview of how a skill works. You can get more technical by looking into the excellent <a href="https://github.com/amzn/alexa-skills-kit-java">samples repository</a> that Amazon offers.</p><h3>Skill description</h3><p>Let’s say we want a skill that will be able to accept a <strong>specific movie genre</strong> and return back some <strong>movies matching this criterion</strong>. For each movie, you will be able to ask for more details like rating and/or plot. Cards that contain the spoken information will appear in the Alexa app at the same time. Let’s call this skill “<a href="https://www.amazon.co.uk/SG-Movie-Genius/dp/B01N8ZFV08"><strong>Movie Genius</strong></a>”.</p><h3>Basic skill lifetime</h3><pre>@Override<br>public SpeechletResponse <strong>onLaunch</strong>(LaunchRequest request, Session session) throws SpeechletException {<br>    [...]<br>}</pre><p>This will be called if you launch your skill with <strong>no intent</strong>. For example saying “<strong>Alexa open Movie Genius</strong><em>” </em>would call the above function.</p><pre>@Override<br>public SpeechletResponse <strong>onIntent</strong>(IntentRequest request, Session session) throws SpeechletException {<br>    [...]<br>}</pre><p><strong>Every other time</strong> you interact with Alexa the above function will be called. For example, if you say “<strong>Alexa ask Movie Genius<em> </em>for a comedy</strong><em>” </em>or when you <strong>respond to a question</strong> this will be called.</p><h3>The building blocks</h3><h4>The intents</h4><p>If most of the times the <strong>onIntent(..)</strong> is called, how do you distinguish between what the user wants each time? The skill can set a number of intents that supports in the <strong>Intent Schema</strong><em> (this is a text box in the </em><a href="https://developer.amazon.com"><em>Amazon Developer Console</em></a><em>):</em></p><pre>{<br>  &quot;<strong>intents</strong>&quot;: [<br>    {<br>      &quot;intent&quot;: &quot;FirstResultIntent&quot;,<br>      &quot;<strong>slots</strong>&quot;:[<br>        {<br>          &quot;name&quot;: &quot;genre&quot;,<br>          &quot;type&quot;: &quot;LIST_OF_MOVIE_GENRE&quot;<br>        }<br>      ]<br>    },<br>    [...]<br>    {<br>      &quot;intent&quot;: &quot;AMAZON.HelpIntent&quot;<br>    }<br>  ]<br>}</pre><p>In this example there is 1 <strong>custom intent</strong> (FirstResultIntent) and 1 <a href="https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/implementing-the-built-in-intents"><strong>built-in intent</strong></a> (AMAZON.HelpIntent). The <strong>slots</strong> are a mechanism to pass additional parameters to the intent. For example in the phrase “<strong>Alexa ask Movie Genius<em> </em>for a <em>comedy</em></strong><em>”, </em>the “<strong><em>comedy</em></strong>” will be mapped to the “<strong>genre</strong>” slot. The LIST_OF_MOVIE_GENRE is just a list of possible values for the slot. Now, the onIntent(..) would look like this:</p><pre>@Override<br>public SpeechletResponse onIntent(IntentRequest request, Session session) throws SpeechletException {<br>    Intent intent = request.getIntent();<br>    String <strong>intentName</strong> = (intent != null) ? intent.getName() : null;<br>    [...]<br>    if (&quot;<strong>FirstResultIntent</strong>&quot;.equals(intentName)) {<br>        [...]<br>    }<br>    else if (&quot;<strong>AMAZON.HelpIntent</strong>&quot;.equals(intentName)) {<br>        [...]<br>    } else {<br>        throw new SpeechletException(&quot;Invalid Intent&quot;);<br>    }<br>}</pre><h4>The speech sample</h4><p>OK, and how do you map actual user’s speech to these intents? Using the <strong>Sample Utterances</strong> <em>(again, this is a text box in the </em><a href="https://developer.amazon.com"><em>Amazon Developer Console</em></a><em>).</em></p><pre>FirstResultIntent I want a {genre}<br>FirstResultIntent find me {genre}<br>FirstResultIntent for a {genre}<br>FirstResultIntent a {genre}</pre><p>This shows Alexa how to map the phrase “<strong>Alexa ask Movie Genius<em> </em>for a comedy</strong><em>” </em>to the <strong>FirstResultIntent </strong>and the “<strong>comedy</strong>” to the “<strong>genre</strong>” slot.<strong> </strong>For the <a href="https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/implementing-the-built-in-intents"><strong>built-in intents</strong></a><strong>,</strong> you do not need to provide sample utterances.</p><h4>Asking for an input</h4><pre>SpeechletResponse askResponse(String <strong>speechText</strong>) {<br><br>    // Create the reprompt<br>    String repromptText = &quot;Can you say that again?&quot;;<br>    Reprompt reprompt = new Reprompt();<br>    PlainTextOutputSpeech repromptSpeech =<br>            new PlainTextOutputSpeech();<br>    repromptSpeech.setText(repromptText);<br>    reprompt.setOutputSpeech(repromptSpeech);<br><br>    // Create the question<br>    PlainTextOutputSpeech speech =<br>            new PlainTextOutputSpeech();<br>    speech.setText(<strong>speechText</strong>);<br><br>    return SpeechletResponse.<strong><em>newAskResponse</em></strong>(<br>            speech,<br>            reprompt);<br>}<br><br>// Make Alexa ask a question<br>askResponse(&quot;Hello! What kind of movie do you want?&quot;);</pre><p>The SpeechletResponse object is what you return from the onIntent(..) and what Alexa will transform to speech to communicate with the user. Using the above snippet you can make Alexa ask the user a question to <strong>request an input</strong>. After Alexa playbacks your question, it will start listening for the user’s input. The reprompt text will be used in case it is not sure about the user’s input and wants the user to say it again. This is how you make a <strong>conversational skill</strong>.</p><p><strong>Responding</strong></p><pre>SpeechletResponse tellResponse(String <strong>speechText</strong>) {<br><br>    PlainTextOutputSpeech speech = new PlainTextOutputSpeech();<br>    speech.setText(<strong>speechText</strong>);<br><br>    SpeechletResponse response = <br>            SpeechletResponse.<strong><em>newTellResponse</em></strong>(speech);<br>    return response;<br>}</pre><p>This can be used when you want to output your results without expecting the user’s input. You will be <strong>finishing a conversation</strong> with this response.</p><h4>Cards in app</h4><pre>SimpleCard card = new SimpleCard();<br>card.setTitle(&quot;Movie Genius&quot;);<br>card.setContent(<strong>cardText</strong>);<br>[...]<br>return SpeechletResponse.<strong><em>newAskResponse</em></strong>(speech, reprompt, <strong>card</strong>);</pre><p>Alexa comes with a companion app for iOS and Android that it’s used to set it up. The app can also be used to view Alexa’s activities. Your skill can send to the app useful information that the user might want to see in written form in addition to the speech.</p><h4>Retaining state</h4><p>You might want to retain state between responses so you can remember what the user told you in the previous questions. To do this use the <strong>Session</strong> object that is provided in onIntent(..) and onLaunch(..).</p><pre>// Retain a movie so you can access it when the user<br>// asks for more info about it in the next interaction<br>session.setAttribute(&quot;ATTR_MOVIE&quot;, theMatrix);<br><br>// Retrieve the movie on the next onIntent() call<br>MovieSet theMatrix = (MovieSet) session.getAttribute(&quot;ATTR_MOVIE&quot;);</pre><p>More complicated objects, such as collections, might not be serialized/deserialized correctly when setting/getting them as attributes. In this case, you can serialize then on your own (maybe using <a href="https://github.com/google/gson">Gson</a> to convert them to JSON).</p><h3>Setup the infrastructure</h3><p>An Alexa skill can be hosted on your own hosting provider or in <a href="https://aws.amazon.com/lambda/">AWS Lambda</a>. The latter is the most popular option for hosting Alexa skills since Amazon offers for <a href="https://aws.amazon.com/lambda/pricing/">free</a> the first 1 million requests every month. If you are not familiar with AWS Lambdas, it’s a cloud hosting service for your code that is billed only when it is called and running. That means that you are not charged for all the idle time that your code is waiting to be called. Also, it does not need any server configuration (except for that the amount of RAM needed that will determine how much time your code is allowed to run).</p><p>To prepare a Java program for deployment you need to <strong>create a JAR file</strong> with all the necessary libraries/dependencies included. This is a sample <a href="https://github.com/netcyrax/MovieGeniusAlexa/blob/master/build.gradle">build.gradle</a> file that creates such a JAR (look for the <em>fatJar</em> task).</p><p>Then you need to <strong>setup the AWS Lambda</strong> to serve your Java JAR. To do this, follow the instructions in the <a href="https://github.com/amzn/alexa-skills-kit-java/blob/master/samples/src/main/java/historybuff/README.md#aws-lambda-setup">README.md</a> of an Amazon’s java sample.(look for the <em>AWS Lambda Setup</em> section).</p><p>Finally, you need to <strong>setup the Alexa Skill</strong> in <a href="https://developer.amazon.com/edw/home.html">Amazon Developer Console</a>. Again, follow the instructions in the <a href="https://github.com/amzn/alexa-skills-kit-java/blob/master/samples/src/main/java/historybuff/README.md#alexa-skill-setup">README.md</a> (look for the <em>Alexa Skill Setup</em> section).</p><p>Now, you will be able to test your skill on your actual device, from <a href="https://developer.amazon.com/edw/home.html">Amazon Developer Console</a> (look for the <em>Test</em> section) or from the <a href="https://echosim.io/">Echo simulator</a>.</p><h3>Conclusion</h3><p>I know that this was not a complete tutorial but I hope that I did give you a glimpse/intro on how to make your own skill using Java. The full source code for the skill is on <a href="https://github.com/netcyrax/MovieGeniusAlexa">GitHub</a> and <a href="https://www.amazon.co.uk/SG-Movie-Genius/dp/B01N8ZFV08">live</a> as well if you want to enable it in your Echo. In my opinion, the <a href="https://github.com/amzn/alexa-skills-kit-java">samples</a> are the easiest way to learn how to do things for your Alexa skill. Do not forget that (if you live in the <a href="https://developer.amazon.com/alexa-skills-kit/alexa-developer-skill-promotion">US</a> or the <a href="https://developer.amazon.com/en-gb/alexa-skills-kit/alexa-developer-skill-promotion">UK</a>) you can get something for just playing around with your device! Happy coding :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2a2b5dbe127f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/rocknnull/an-adventure-with-alexa-in-java-land-2a2b5dbe127f">An adventure with Alexa in Java land.</a> was originally published in <a href="https://medium.com/rocknnull">Rock and Null</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>