<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Justin Mancinelli</title>
    <description>The latest articles on DEV Community by Justin Mancinelli (@piannaf).</description>
    <link>https://dev.to/piannaf</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F136122%2F952f7b7a-2a99-4568-bb1e-8dddbe2720f9.jpg</url>
      <title>DEV Community: Justin Mancinelli</title>
      <link>https://dev.to/piannaf</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/piannaf"/>
    <language>en</language>
    <item>
      <title>You Need a Rubric (when evaluating multiplatform solutions)</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Wed, 15 Apr 2020 17:01:08 +0000</pubDate>
      <link>https://dev.to/touchlab/you-need-a-rubric-when-evaluating-multiplatform-solutions-1ii0</link>
      <guid>https://dev.to/touchlab/you-need-a-rubric-when-evaluating-multiplatform-solutions-1ii0</guid>
      <description>&lt;p&gt;Last week, I spoke to an audience about &lt;a href="https://youtu.be/6RquJJM1jaE"&gt;evaluating multiplatform solutions&lt;/a&gt;. Spoiler: you need a rubric, and the criteria you pick will be heavily context-dependent.&lt;/p&gt;

&lt;p&gt;Coincidentally, I got &lt;a href="https://www.youtube.com/watch?v=sA_JIqqj9js&amp;amp;lc=UgwOcrMX_6ClLHIQIRF4AaABAg"&gt;a comment on my Lead Dev NYC 2019 talk&lt;/a&gt; a few days later, bringing up 5 criteria that leads him to choose React Native. &lt;/p&gt;

&lt;p&gt;My response became more of an article, so here we are: his comment, and my response&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Kotlin multiplatform is promising, but when comparing stacks, these key factors rarely get mentioned:&lt;br&gt;
1) does it allow for a shared end to end testing and continuous integration setup between platforms?&lt;br&gt;
2) does it have feature parity by design?&lt;br&gt;
3) can code be shared between web and mobile?&lt;br&gt;
4) availability of experienced developers?&lt;br&gt;
5) shared pull requests between ios, android, and web (and thus converging  knowledge and coding standards)?&lt;/p&gt;

&lt;p&gt;Kotlin MP will likely never check these boxes, which people should be aware of before deciding. E.g. React Native is quite powerful when looking at the overall benefits and teams like shopify seem to agree.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks for raising these questions.&lt;/p&gt;

&lt;p&gt;Before anyone asks questions, they need to know if it is relevant to their business. And, when they ask questions, they need to know how important each one is to their business. There are world-class engineers at Nubank, Shopify, and Square and each of them made different code sharing decisions (&lt;a href="https://medium.com/building-nubank/https-medium-com-freire-why-nubank-chose-flutter-61b80b568772"&gt;Flutter&lt;/a&gt;, &lt;a href="https://engineering.shopify.com/blogs/engineering/react-native-future-mobile-shopify"&gt;React Native&lt;/a&gt;, and &lt;a href="https://developer.squareup.com/blog/developing-on-ios-and-android/"&gt;Kotlin Multiplatform&lt;/a&gt; respectively). And let’s not forget the recent examples of &lt;a href="https://medium.com/airbnb-engineering/react-native-at-airbnb-f95aa460be1c"&gt;Airbnb&lt;/a&gt; and &lt;a href="https://engineering.udacity.com/react-native-a-retrospective-from-the-mobile-engineering-team-at-udacity-89975d6a8102"&gt;Udacity&lt;/a&gt; abandoning React Native after years of investment in using it. Since every business is different, there is no one-size-fits-all evaluation criteria.&lt;/p&gt;

&lt;p&gt;To answer your questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Depends, because the focus is on sharing business logic, not UI, the shared testing is focused on the business logic. If you are building an SDK without UI concerns, then yes, you can E2E test the product under test. If you are building apps that share business logic with KMP, then no, but you can share common tests. &lt;/li&gt;
&lt;li&gt;No, it has optional sharing by design. This allows for greater feature alignment while reducing re-write risk in existing code, and easier, purposeful platform specific integration if the product calls for it. (See &lt;a href="https://dev.to/touchlab/don-t-sacrifice-user-experience-for-a-better-developer-experience-1lci"&gt;my thoughts related to feature-alignment as a goal&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Yes, &lt;a href="https://medium.com/tech-quizlet/shared-code-at-quizlet-kotlin-multiplatform-2ee1b57646c"&gt;Quizlet is doing exactly that&lt;/a&gt;. KotlinJS came before Kotlin/Native and they are now both under the Kotlin Multiplatform umbrella.&lt;/li&gt;
&lt;li&gt;Depends what experience you are looking for. Since React Native has been out longer, there is a larger pool of people with React Native experience. However, React Native is different enough from both React Web and Native Mobile, that both experienced react web devs and native mobile devs have issues with it. And people who have a few years experience with React Native often build within the confines of React Native and libraries available which gives them trouble when the product requires more native platform integration or platform specific look and feel. As for KMP, Kotlin experience is easy to come by and the experience needed to integrate the generated framework into an iOS project is easy to come by as well. The difficulties are in the details which is more about good software development, rather than experience with each technology.&lt;/li&gt;
&lt;li&gt;Yes, Touchlab and other companies adopting KMP recommend shared PRs and ways to enable that like monorepos, bringing together Android and iOS teams into Mobile teams, building tools like our &lt;a href="https://github.com/touchlab/xcode-kotlin"&gt;Kotlin Xcode plugin&lt;/a&gt;, and shared coding standards, especially around architecture and API style, to ease the transition to all platforms working together.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I wouldn’t say “likely never check these boxes”. For 1, the open source community is growing and there are already several concepts around sharing UI with KMP as well. For 2, similar answer as 1, you can already &lt;a href="https://play.kotlinlang.org/hands-on/Building%20Web%20Applications%20with%20React%20and%20Kotlin%20JS/01_Introduction"&gt;build full react web apps in Kotlin&lt;/a&gt; and the community is looking at ways to share everything for feature parity across all supported platforms.&lt;/p&gt;

&lt;p&gt;Again, not everyone’s questions/criteria will be the same and the weight given to each will be different too. The people choosing KMP put more weight on its optionality, native interop, use of Kotlin, and deference to the platform UI and ecosystems. (See &lt;a href="https://youtu.be/6RquJJM1jaE"&gt;my recent webinar on this subject&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Lastly, since my talk, React Native has continued down the path of becoming “more native” with the introduction of JSI and Turbo Modules. Though, so far, those are more native in the C++ sense, rather than the Kotlin/Swift sense and that will bring issues related to &lt;a href="https://dropbox.tech/mobile/the-not-so-hidden-cost-of-sharing-code-between-ios-and-android"&gt;what DropBox encountered&lt;/a&gt;. But again, there’s no one-size-fits-all criteria. &lt;/p&gt;




&lt;p&gt;For more of my thoughts on this topic, please watch my 20 minute webinar&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/6RquJJM1jaE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>kotlinmultiplatform</category>
      <category>reactnative</category>
      <category>android</category>
      <category>ios</category>
    </item>
    <item>
      <title>What do you think the dev.to feed algorithm should be?</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Thu, 23 Jan 2020 15:42:36 +0000</pubDate>
      <link>https://dev.to/piannaf/what-do-you-think-the-dev-to-feed-algorithm-should-be-5ded</link>
      <guid>https://dev.to/piannaf/what-do-you-think-the-dev-to-feed-algorithm-should-be-5ded</guid>
      <description>&lt;p&gt;I dove into the code to find out what it is now.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/piannaf" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4BLLlvb1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/practicaldev/image/fetch/s--Jyv3hoBa--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/136122/952f7b7a-2a99-4568-bb1e-8dddbe2720f9.jpg" alt="piannaf"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/piannaf/the-dev-to-feed-algorithm-5em5" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;The Dev.to Feed Algorithm 🤖&lt;/h2&gt;
      &lt;h3&gt;Justin Mancinelli ・ Jan 23 '20 ・ 7 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#meta&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#rails&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;It's been changed a few times in the past.&lt;/p&gt;

&lt;p&gt;What do you think of it? Do you have suggestions for what would work better for you?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>meta</category>
    </item>
    <item>
      <title>The Dev.to Feed Algorithm 🤖</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Thu, 23 Jan 2020 15:19:24 +0000</pubDate>
      <link>https://dev.to/piannaf/the-dev-to-feed-algorithm-5em5</link>
      <guid>https://dev.to/piannaf/the-dev-to-feed-algorithm-5em5</guid>
      <description>&lt;p&gt;TL;DR👇&lt;/p&gt;

&lt;h1&gt;
  
  
  I used to develop apps. I still do, but I used to, too
&lt;/h1&gt;

&lt;p&gt;Back in 2007/2008, I learned Ruby on Rails and developed two prototype sites that didn't end up in production. Since then, I did extensive work on non-Ruby, non-Rails server applications and learned enough about Android and iOS apps to manage the development of mobile apps in my current role.&lt;/p&gt;

&lt;p&gt;I never touched Ruby on Rails again...until &lt;a class="mentioned-user" href="https://dev.to/anshbansal"&gt;@anshbansal&lt;/a&gt; asked a question that I had asked myself a few times before.&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/anshbansal" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Uto4ksv3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://res.cloudinary.com/practicaldev/image/fetch/s--bvHRqrd---/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/173770/86712786-86f9-41f9-9272-e05f794a1d43.jpeg" alt="anshbansal"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/anshbansal/what-is-the-algorithm-for-dev-to-s-feed-5h1c" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;What is the algorithm for dev.to's feed?&lt;/h2&gt;
      &lt;h3&gt;Aseem Bansal ・ Jan 12 '20 ・ 1 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#discuss&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#help&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;The following is my deep dive into the dev.to codebase to answer this question. There are probably a few things wrong, please point them out in the comments so I can correct them. Thank you.&lt;/p&gt;

&lt;h1&gt;
  
  
  Start at the beginning
&lt;/h1&gt;

&lt;p&gt;And it doesn't get much earlier than &lt;a href="https://github.com/thepracticaldev/dev.to/blob/33d6dca565dc5f544eaecac17612fca448357126/config/routes.rb#L409"&gt;the root route&lt;/a&gt;&lt;br&gt;
&lt;code&gt;root "stories#index"&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Taking control
&lt;/h1&gt;

&lt;p&gt;Rails follows a Model View Controller (MVC) architecture. When you ask dev.to to show you the root page, it will ask the stories controller to run the index action.&lt;/p&gt;

&lt;p&gt;What we see there is it sets up a bunch of state then &lt;a href="https://github.com/thepracticaldev/dev.to/blob/ba6c70c2d2198b84c3117e5d48e311f4cbbc1863/app/controllers/stories_controller.rb#L136"&gt;renders the articles/index template&lt;/a&gt;&lt;br&gt;
&lt;code&gt;render template: "articles/index"&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Show me the stories
&lt;/h1&gt;

&lt;p&gt;If you inspect your dev.to home screen, you'll notice all the articles/stories are listed within an &lt;code&gt;articles-list&lt;/code&gt; div. You can &lt;a href="https://github.com/thepracticaldev/dev.to/blob/7bfb255627a2664d76ed033da4c4ad03898b6bfb/app/views/articles/index.html.erb#L37"&gt;find it in the articles/index view&lt;/a&gt; as expected. &lt;/p&gt;

&lt;p&gt;And here's where we start to see how the feed is populated.&lt;/p&gt;
&lt;h1&gt;
  
  
  OK, first show me the featured story
&lt;/h1&gt;

&lt;p&gt;The first story in the article list is a featured story.&lt;/p&gt;

&lt;p&gt;The algorithm to get the featured story for a logged in user comes from &lt;a href="https://github.com/thepracticaldev/dev.to/blob/ba6c70c2d2198b84c3117e5d48e311f4cbbc1863/app/controllers/stories_controller.rb#L109"&gt;the stories controller&lt;/a&gt; and &lt;a href="https://github.com/thepracticaldev/dev.to/blob/7bfb255627a2664d76ed033da4c4ad03898b6bfb/app/views/articles/index.html.erb#L87"&gt;the articles/index view&lt;/a&gt;. I've simplified it by substituting some variables and reorganizing some statements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="vi"&gt;@stories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;published&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;limited_column_select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;per&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="vi"&gt;@stories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@stories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"score &amp;gt; ? OR featured = ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"hotness_score DESC"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
          &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;sample&lt;/span&gt; &lt;span class="c1"&gt;# random offset, weighted more towards zero&lt;/span&gt;
&lt;span class="vi"&gt;@stories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@stories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="vi"&gt;@featured_story&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@stories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;main_image: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decorate&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In English:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Fetch a collection of stories that score above 9 or are featured&lt;/li&gt;
&lt;li&gt;Order them, starting with the "hottest" one&lt;/li&gt;
&lt;li&gt;Randomly skip the first 0 to 11 stories, weighted more towards 0&lt;/li&gt;
&lt;li&gt;The featured story is the first story that has a main image&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;Leaving how score, featured, and hotness are determined as an exercise for the reader&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Notice the featured article has nothing to do with which people, organizations, or tags you follow.&lt;/p&gt;

&lt;h1&gt;
  
  
  Now show me the rest of the stories?
&lt;/h1&gt;

&lt;p&gt;After rendering the featured story, the article/index view creates a &lt;code&gt;substories&lt;/code&gt; div and then &lt;a href="https://github.com/thepracticaldev/dev.to/blob/7bfb255627a2664d76ed033da4c4ad03898b6bfb/app/views/articles/index.html.erb#L153"&gt;renders the stories/main_stories_feed partial&lt;/a&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;%= render "stories/main_stories_feed" %&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  These are not the divs you are looking for
&lt;/h1&gt;

&lt;p&gt;I was scratching my head while reading through  &lt;a href="https://github.com/thepracticaldev/dev.to/blob/7bfb255627a2664d76ed033da4c4ad03898b6bfb/app/views/stories/_main_stories_feed.html.erb"&gt;the _main_stories_feed partial&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It populates the data attributes of a &lt;code&gt;new-articles-object&lt;/code&gt; div and a &lt;code&gt;home-articles-object&lt;/code&gt; div, then a bunch of other divs that have no contents. And the divs I do see when inspecting the home screen have the &lt;code&gt;single-article single-article-small-pic&lt;/code&gt; class, but don't look like what's in this file.&lt;/p&gt;

&lt;p&gt;Evil action-at-a-distance like this can only mean one thing: JavaScript&lt;/p&gt;
&lt;h1&gt;
  
  
  Nobody expects the Spanish Inquisition
&lt;/h1&gt;

&lt;p&gt;Searching the repo for &lt;code&gt;new-articles-object&lt;/code&gt; and &lt;code&gt;home-articles-object&lt;/code&gt;, we find them both in &lt;a href="https://github.com/thepracticaldev/dev.to/blob/c0a7c17054c027b461280ff9fd641a5e5594ca6a/app/assets/javascripts/initializers/initializeFetchFollowedArticles.js.erb#L34"&gt;initializeFetchFollowed Articles&lt;/a&gt;, called &lt;a href="https://github.com/thepracticaldev/dev.to/blob/c0a7c17054c027b461280ff9fd641a5e5594ca6a/app/assets/javascripts/initializePage.js.erb#L4"&gt;very early&lt;/a&gt; when a page is initialized.&lt;/p&gt;

&lt;p&gt;And there is a lot of logic here which I did not expect.&lt;/p&gt;
&lt;h1&gt;
  
  
  The new stories are not the old stories
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/thepracticaldev/dev.to/blob/ba6c70c2d2198b84c3117e5d48e311f4cbbc1863/app/controllers/stories_controller.rb#L113"&gt;The stories controller&lt;/a&gt; populated the &lt;code&gt;@stories&lt;/code&gt; collection used for the for the featured story. It is also used to populate the the data attributes of the &lt;code&gt;home-articles-object&lt;/code&gt; div. But that comes next, not now. &lt;/p&gt;

&lt;p&gt;Instead, The first stories we see after the feature article are, populated from &lt;a href="https://github.com/thepracticaldev/dev.to/blob/7bfb255627a2664d76ed033da4c4ad03898b6bfb/app/views/stories/_main_stories_feed.html.erb#L3"&gt;a query directly in the view&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="vi"&gt;@new_stories&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;published&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"published_at &amp;gt; ? AND score &amp;gt; ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ago&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="nf"&gt;limited_column_select&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
  &lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"published_at DESC"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;
  &lt;span class="nf"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In English:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Fetch a collection of stories that have been published some time in the last 2 to 6 hours and score above -15&lt;/li&gt;
&lt;li&gt;Order them by most recent first&lt;/li&gt;
&lt;li&gt;Return the first 15 to 80 of them&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then the JavaScript function &lt;a href="https://github.com/thepracticaldev/dev.to/blob/c0a7c17054c027b461280ff9fd641a5e5594ca6a/app/assets/javascripts/initializers/initializeFetchFollowedArticles.js.erb#L33"&gt;&lt;code&gt;insertNewArticles&lt;/code&gt;&lt;/a&gt; takes over:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;articlesJSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;containsUserID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;followed_user_ids&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;containsOrganizationID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;organization_id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;followed_organization_ids&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;intersectedTags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;intersect_arrays&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;followed_tag_names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cached_tag_list_array&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;followedPoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;experienceDifference&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;experience_level_rating&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;experience_level&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;containsPreferredLanguage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preferred_languages_array&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
      &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;followed_tags&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;intersectedTags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;followedPoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;followedPoints&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;points&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;followedPoints&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;positive_reactions_count&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containsUserID&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containsOrganizationID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;containsPreferredLanguage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;rand&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;random&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rand&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mf"&gt;0.6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;articlePoints&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;experienceDifference&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;points&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;articlePoints&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sortedArticles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;articlesJSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;points&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;points&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;sortedArticles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;insertPlace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parentNode&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;points&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;article-link-&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;insertArticle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;insertPlace&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In English:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Give each article 0 points to start off with&lt;/li&gt;
&lt;li&gt;Sum &lt;a href="https://dev.to/dashboard/following_tags"&gt;the weight of each tag&lt;/a&gt; (&lt;a href="https://github.com/thepracticaldev/dev.to/pull/1229"&gt;which can also be negative&lt;/a&gt;) the user follows and this article is tagged with, then double it&lt;/li&gt;
&lt;li&gt;Now add to that, the number of positive reactions the article currently has&lt;/li&gt;
&lt;li&gt;If the user follows the article's author, or is the articles author, add 16 points&lt;/li&gt;
&lt;li&gt;If the user follows the article's organization, add 16 points&lt;/li&gt;
&lt;li&gt;If the article is written in the user's language, add 1 point, otherwise, subtract 10 points&lt;/li&gt;
&lt;li&gt;Randomly (with equal chance) give the article an extra 0, 3, or 6 points.&lt;/li&gt;
&lt;li&gt;Subtract half the difference of this articles experience level vs &lt;a href="https://dev.to/settings/ux"&gt;the user's experience&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Order the articles by most points first&lt;/li&gt;
&lt;li&gt;If the article has more than 12 points, show it to the user&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  What about the rest?
&lt;/h1&gt;

&lt;p&gt;The next batch of initialized articles come from the same batch we got the featured article from and processed by a new (but familiar) algorithm in &lt;a href="https://github.com/thepracticaldev/dev.to/blob/c0a7c17054c027b461280ff9fd641a5e5594ca6a/app/assets/javascripts/initializers/initializeFetchFollowedArticles.js.erb#L84"&gt;&lt;code&gt;insertTopArticles&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;When you get to the bottom of that list, articles are populated from an &lt;a href="https://github.com/thepracticaldev/dev.to/blob/c0a7c17054c027b461280ff9fd641a5e5594ca6a/app/assets/javascripts/initializers/initializeFetchFollowedArticles.js.erb#L148"&gt;algoliasearch index of ordered articles&lt;/a&gt;. The &lt;a href="https://github.com/thepracticaldev/dev.to/blob/4e5dc015b377f922b96d698d4e8da2c46b8ff973/app/models/article.rb#L171"&gt;definition of that index&lt;/a&gt; is found in the Article model.&lt;/p&gt;

&lt;p&gt;Finally, scrolling kicks in which you can find in &lt;a href="https://github.com/thepracticaldev/dev.to/blob/157a6f1ef17948cffcbe4997b85811cbc3be452d/app/assets/javascripts/initializers/initScrolling.js.erb#L203"&gt;initScrolling.js.erb&lt;/a&gt; and populates more articles from the algoliasearch index.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Leaving the details of these as an exercise for the reader&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  TL;DR
&lt;/h1&gt;

&lt;p&gt;For the first article in the list:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Fetch a collection of stories that score above 9 or are featured&lt;/li&gt;
&lt;li&gt;Order them, starting with the "hottest" one&lt;/li&gt;
&lt;li&gt;Randomly skip the first 0 to 11 stories, weighted more towards 0&lt;/li&gt;
&lt;li&gt;The featured story is the first story that has a main image&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;For the next batch of articles:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Fetch a collection of stories that have been published some time in the last 2 to 6 hours and score above -15&lt;/li&gt;
&lt;li&gt;Order them by most recent first&lt;/li&gt;
&lt;li&gt;Return the first 15 to 80 of them&lt;/li&gt;
&lt;li&gt;Give each article 0 points to start off with&lt;/li&gt;
&lt;li&gt;Sum &lt;a href="https://dev.to/dashboard/following_tags"&gt;the weight of each tag&lt;/a&gt; (&lt;a href="https://github.com/thepracticaldev/dev.to/pull/1229"&gt;which can also be negative&lt;/a&gt;) the user follows and this article is tagged with, then double it&lt;/li&gt;
&lt;li&gt;Now add to that, the number of positive reactions the article currently has&lt;/li&gt;
&lt;li&gt;If the user follows the article's author, or is the articles author, add 16 points&lt;/li&gt;
&lt;li&gt;If the user follows the article's organization, add 16 points&lt;/li&gt;
&lt;li&gt;If the article is written in the user's language, add 1 point, otherwise, subtract 10 points&lt;/li&gt;
&lt;li&gt;Randomly (with equal chance) give the article an extra 0, 3, or 6 points.&lt;/li&gt;
&lt;li&gt;Subtract half the difference of this articles experience level vs &lt;a href="https://dev.to/settings/ux"&gt;the user's experience&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Order the articles by most points first&lt;/li&gt;
&lt;li&gt;If the article has more than 12 points, show it to the user&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you've scrolled passed all of those,&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;Using the same collection the featured article came from&lt;/li&gt;
&lt;li&gt;Process with &lt;a href="https://github.com/thepracticaldev/dev.to/blob/c0a7c17054c027b461280ff9fd641a5e5594ca6a/app/assets/javascripts/initializers/initializeFetchFollowedArticles.js.erb#L84"&gt;a similar but different algorithm as the previous batch&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;And, finally&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://github.com/thepracticaldev/dev.to/blob/4e5dc015b377f922b96d698d4e8da2c46b8ff973/app/models/article.rb#L197"&gt;All articles ordered by hotness&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Closing remarks
&lt;/h1&gt;

&lt;p&gt;This could change at any time. For example, on 2019-09-19, &lt;a class="mentioned-user" href="https://dev.to/ben"&gt;@ben&lt;/a&gt; merged a PR to &lt;a href="https://github.com/thepracticaldev/dev.to/pull/4069"&gt;add more variation to home feed&lt;/a&gt;. All links to github are to the commit that I saw which was in &lt;code&gt;master&lt;/code&gt; at the time of writing but, by the time you read this, &lt;code&gt;master&lt;/code&gt; has probably moved on.&lt;/p&gt;

</description>
      <category>meta</category>
      <category>rails</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Don't sacrifice user experience for a better developer experience</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Mon, 13 Jan 2020 14:33:44 +0000</pubDate>
      <link>https://dev.to/touchlab/don-t-sacrifice-user-experience-for-a-better-developer-experience-1lci</link>
      <guid>https://dev.to/touchlab/don-t-sacrifice-user-experience-for-a-better-developer-experience-1lci</guid>
      <description>&lt;p&gt;As a mobile developer, it is understandable to focus on platform fragmentation and writing UI twice as pain points.&lt;/p&gt;

&lt;p&gt;As a web developer, it is understandable to try to leverage your web expertise so that developing for a new platform is less painful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftuujmxx8pv6ehyephse6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Ftuujmxx8pv6ehyephse6.png" alt="Cross-platform is not an excuse to ignore the platform"&gt;&lt;/a&gt;&lt;/p&gt;
Love this slide from Ellen Shapiro's Talk&lt;sup&gt;1&lt;/sup&gt;



&lt;p&gt;From a user perspective, fragmentation is what makes different platforms unique. Games can get away with having the same UI across all platforms because users expect games to be their own world, not confined to platform conventions. And, although platform UI conventions have seen convergence (e.g. material design includes guidance on Bottom navigation now), they are still different. When non-game apps don’t conform, they are perceived as a Linux app running on Windows, or an iOS app running on Android, or somewhere in the uncanny valley.&lt;/p&gt;

&lt;p&gt;Apps shouldn’t conform 100% because they have different branding, use cases, flows, audiences, etc. They require deliberate design both for what elements are shared and what diverge. That is where native UIs become an asset. Yes, there is more for developers to think about and to deal with. Yes, it’s a pain for developers to keep things updated and meet user expectations of different OSs and versions of OSs. But, you can also make the best UI possible for each platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/jaredsinclair/status/1136057545804734465?s=09" rel="noopener noreferrer"&gt;Apple&lt;/a&gt;, &lt;a href="https://twitter.com/ricknout/status/1207943716801073152" rel="noopener noreferrer"&gt;Google&lt;/a&gt;, and &lt;a href="https://github.com/Microsoft/microsoft-ui-xaml" rel="noopener noreferrer"&gt;Microsoft&lt;/a&gt; invest a lot in the standard UI tooling, libraries, and widgets so that when you use an app on iOS, Android, MacOS, or Windows, there is a certain consistency of quality and experience, and, when you develop for them, you are using the best tool for the job. &lt;/p&gt;

&lt;p&gt;It’s possible to make a terrible app no matter what tools you use. Flutter and React Native may make it easier to make a &lt;em&gt;decent&lt;/em&gt; app across platforms, but you need to go native to build an &lt;em&gt;excellent&lt;/em&gt; app across platforms.&lt;/p&gt;

&lt;p&gt;The history of write-once-run-anywhere and shared UI is a volatile one. The history of shared code, below the UI, is a successful one. &lt;a href="https://dev.to/touchlab/kotlin-multiplatform-can-t-do-it-all-which-is-exactly-why-you-should-try-it-1p85"&gt;Kotlin Multiplatform focuses on shared code below the UI&lt;/a&gt; and lets you use the platform provided tooling to their fullest extent. That makes it doubly less risky: less risk of making a poor UI and less risk of being locked into a 3rd party (for now, Flutter is at best 2nd party).&lt;/p&gt;

&lt;p&gt;KMP is still in the relatively early phases, &lt;a href="https://dev.to/touchlab"&gt;@touchlab&lt;/a&gt; is an innovator on the adoption curve and anyone putting KMP into production right now is an early adopter. 2020 may be the start of the early majority phase with &lt;a href="https://www.infoworld.com/article/3509457/jetbrains-bringing-ios-device-support-to-android-studio.html" rel="noopener noreferrer"&gt;iOS support in Android Studio&lt;/a&gt; and &lt;a href="https://dev.to/touchlab/kotlin-native-coroutines-preview-3edc"&gt;multithreaded coroutines in Kotlin Native&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/mCClSS6xbi8us/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/mCClSS6xbi8us/giphy.gif" alt="just because you can, doesn't mean you should"&gt;&lt;/a&gt;&lt;/p&gt;
Just because you can share UI, doesn't mean you should



&lt;p&gt;Coming back to the UI topic. There are already attempts at shared UI libraries built on KMP, and there will be more and there will be ones that gain popularity and maturity. The fact that you can already write &lt;a href="https://github.com/JetBrains/kotlin-native/tree/master/samples/uikit" rel="noopener noreferrer"&gt;UIKit code with Kotlin&lt;/a&gt; makes that easier. &lt;/p&gt;

&lt;p&gt;But again, be careful, be deliberate, know your users. Just because you can share UI, doesn't mean you should. Android, iOS and Web are very different. But we learned from &lt;a href="https://developer.apple.com/mac-catalyst/" rel="noopener noreferrer"&gt;Catalyst&lt;/a&gt; that users even notice the difference between iPad and Mac. The outcry &lt;a href="https://twitter.com/_chuckyc/status/1190626773181976576" rel="noopener noreferrer"&gt;stopped one prominent developer from releasing a quick port to Mac&lt;/a&gt; and it became clear that &lt;a href="https://twitter.com/stroughtonsmith/status/1183219285256298496" rel="noopener noreferrer"&gt;Apple should have provided better guidance on the UI differences expected&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lastly, remember that Apple and Google put a lot of money, time, and effort into their platforms. They want people to buy their devices which means good UX (user experrience) and they need developers to build more apps for each platform which means good DX (developer experience). Jetpack Compose is maturing, Swift UI is maturing. Kotlin Multiplatform doesn't stop you from investing in either. Jetpack Compose is already Kotlin First, and SwiftUI+KMP &lt;a href="https://twitter.com/RunChristinaRun/status/1138987880674521088" rel="noopener noreferrer"&gt;might just be an ideal developer experience&lt;/a&gt; for making ideal user experiences on iOS, too.&lt;/p&gt;




&lt;p&gt;1. &lt;a href="https://speakerdeck.com/designatednerd/native-and-what-maybe-shouldnt-kotlinconf-copenhagen-denmark-december-2019" rel="noopener noreferrer"&gt;I walk the line&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kotlinmultiplatform</category>
      <category>kotlin</category>
      <category>ios</category>
      <category>android</category>
    </item>
    <item>
      <title>Thoughts, Tips, and Observations about speaking at conferences: a thread from Corey Qinn</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Sun, 12 Jan 2020 03:24:26 +0000</pubDate>
      <link>https://dev.to/piannaf/thoughts-tips-and-observations-about-speaking-at-conferences-a-thread-from-corey-qinn-1dd0</link>
      <guid>https://dev.to/piannaf/thoughts-tips-and-observations-about-speaking-at-conferences-a-thread-from-corey-qinn-1dd0</guid>
      <description>&lt;p&gt;I just finished reading this 100+ long, entertaining, and &lt;strong&gt;amazing&lt;/strong&gt; thread:&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--_arZPeIR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://pbs.twimg.com/profile_images/1093667107278147584/rKaSDcaB_normal.jpg" alt="Corey Quinn profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Corey Quinn
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @quinnypig
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kDgU_xDI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Okay. For every retweet this gets (TO A POINT!) I'll add a thought / tip / observation about speaking at conferences.
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      19:02 PM - 10 Jan 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1215710451343904768" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OXOJJiQT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1215710451343904768" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--foTp-unf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1215710451343904768" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SFHqU4bF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;Posting here in case you haven't seen it. Highly recommended. If you've never thought about speaking, it may inspire you. If you have just started (&lt;a href="https://dev.to/touchlab/a-first-time-speaker-s-journey-from-cfp-to-stage-5pk"&gt;like me&lt;/a&gt;), you'll learn a lot. If you are a veteran, I suspect there's interesting tidbits in there for you, too.&lt;/p&gt;

</description>
      <category>speaking</category>
      <category>motivation</category>
      <category>beginners</category>
      <category>techtalks</category>
    </item>
    <item>
      <title>A tale of checksums and client-side security🙀</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Mon, 06 Jan 2020 14:23:08 +0000</pubDate>
      <link>https://dev.to/piannaf/a-tale-of-checksums-and-client-side-security-36dk</link>
      <guid>https://dev.to/piannaf/a-tale-of-checksums-and-client-side-security-36dk</guid>
      <description>&lt;h1&gt;
  
  
  Chapter 1 - When you come to a fork in the road, take it
&lt;/h1&gt;

&lt;p&gt;&lt;sup&gt;📝 As once said by &lt;a href="https://quoteinvestigator.com/2013/07/25/fork-road/" rel="noopener noreferrer"&gt;Yogi Berra&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;I was wandering through the int&lt;strong&gt;ra&lt;/strong&gt;net at a previous job looking at what other similar teams were up to and came across a link to their product's test environment (open to the int&lt;strong&gt;er&lt;/strong&gt;net). Unfortunately, it was password protected:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1xj9en4r4lymo542y6ez.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F1xj9en4r4lymo542y6ez.png" alt="Password prompt"&gt;&lt;/a&gt;&lt;/p&gt;
URL redacted -- it points to a 404 now



&lt;p&gt;At first glance, I thought it was &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication" rel="noopener noreferrer"&gt;basic authentication&lt;/a&gt; because of the alert window. On second glance, it was definitely a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt" rel="noopener noreferrer"&gt;&lt;code&gt;window.prompt()&lt;/code&gt;&lt;/a&gt; box. And the code looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;promptUserForPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;jesChecksum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;9887&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Please enter the passkey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pass&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defaultHref&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;verifyPassword&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;successfulLogin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Since this is client-side authentication, I could just look into &lt;code&gt;successfulLogin&lt;/code&gt; and force success without any password. But what's the fun in that?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It was much for fun to see if I could get &lt;code&gt;jesChecksum(pass)&lt;/code&gt; to equal &lt;code&gt;9887&lt;/code&gt;. The first hint that it was probably fairly easy is that the function hints the algorithm is a checksum.&lt;/p&gt;
&lt;h1&gt;
  
  
  Chapter 2 - Checksums are unsuitable for any kind of security work
&lt;/h1&gt;

&lt;p&gt;&lt;sup&gt;📝 As pointed out by &lt;a href="https://blog.codinghorror.com/checksums-and-hashes/" rel="noopener noreferrer"&gt;Jeff Atwood&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  First, let's consult Wikipedia to find out &lt;a href="https://en.m.wikipedia.org/wiki/Checksum" rel="noopener noreferrer"&gt;what a checksum is&lt;/a&gt;:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A checksum or hash sum is a small-size datum from a block of digital data for the purpose of detecting errors which may have been introduced during its transmission or storage. By themselves checksums are often used to verify data integrity, but should not be relied upon to also verify data authenticity.&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;It's interesting that another name is "hash sum" but, it's very clear from the above quote, the functions you use to hash your passwords aren't the same as a checksum.&lt;/p&gt;
&lt;h3&gt;
  
  
  So &lt;a href="https://en.m.wikipedia.org/wiki/Hash_function" rel="noopener noreferrer"&gt;what's a hash function&lt;/a&gt;? Back to Wikipedia:
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;A hash function is any function that can be used to map digital data of arbitrary size to digital data of fixed size.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fs2d0npjxuwim7q1kozkp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fs2d0npjxuwim7q1kozkp.png" alt="Hash function illustration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok, then checksums are a kind of hash function. There are lots of different kinds of hash functions. They can do lots of different processing to generate the hash. The resulting hash can be of different sizes. Most importantly, different hash functions have different properties: speed, reversibility, number of collisions...&lt;/p&gt;

&lt;p&gt;Collisions and speed are super important for the hashing functions that back &lt;a href="https://www.perl.com/pub/2002/10/01/hashes.html/" rel="noopener noreferrer"&gt;perl hashes&lt;/a&gt;, &lt;a href="https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html" rel="noopener noreferrer"&gt;java hashmaps&lt;/a&gt;, &lt;a href="https://docs.python.org/3/tutorial/datastructures.html#dictionaries" rel="noopener noreferrer"&gt;python dictionaries&lt;/a&gt;, and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects" rel="noopener noreferrer"&gt;javascript objects&lt;/a&gt;. Too slow, and the initial &lt;code&gt;O(1)&lt;/code&gt; lookup is slow; too many collisions, and lookups will need to &lt;code&gt;O(n)&lt;/code&gt; traverse the list in the bucket.&lt;/p&gt;
&lt;h3&gt;
  
  
  What about those password hashes? Enter &lt;a href="https://en.m.wikipedia.org/wiki/Cryptographic_hash_function" rel="noopener noreferrer"&gt;cryptographic hash functions&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Unlike checksums and the hash functions used for associative arrays, Wikipedia tells us:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The ideal cryptographic hash function has four main properties:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;it is easy to compute the hash value for any given message&lt;/li&gt;
&lt;li&gt;it is infeasible to generate a message from its hash&lt;/li&gt;
&lt;li&gt;it is infeasible to modify a message without changing the hash (avalanche effect)&lt;/li&gt;
&lt;li&gt;it is infeasible to find two different messages with the same hash.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;#1 and #2 mean it is much faster to figure out the hash than it is to figure out what the hash came from.&lt;/p&gt;

&lt;p&gt;#3 and #4 make it really hard to triangulate or brute force what the hash came from.&lt;/p&gt;

&lt;p&gt;Unlike cryptographic hashes, it's often easy to find checksum collisions, even for more complex algorithms like CRCs (&lt;a href="https://sar.informatik.hu-berlin.de/research/publications/SAR-PR-2006-05/SAR-PR-2006-05_.pdf" rel="noopener noreferrer"&gt;PDF - Reversing CRC&lt;/a&gt;).&lt;/p&gt;
&lt;h1&gt;
  
  
  Chapter 3 - My crime is that of curiosity
&lt;/h1&gt;

&lt;p&gt;&lt;sup&gt;📝 From &lt;a href="http://www.phrack.org/archives/issues/7/3.txt" rel="noopener noreferrer"&gt;The Conscience of a Hacker&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;How can &lt;code&gt;jesChecksum(pass)&lt;/code&gt; equal &lt;code&gt;9887&lt;/code&gt;? Here it is:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;jesChecksum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;primes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;23&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;29&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;31&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;37&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;43&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;47&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;59&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;67&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="mi"&gt;73&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;79&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;83&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;89&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;97&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;rtn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;tmp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charCodeAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;rtn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rtn&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;tmp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;rtn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It may look difficult to solve this without lots of trial and error. After staring at it a bit longer, you'll notice it just takes each letter of the string passed in, multiplies it by a prime at the same position, then adds them all up. &lt;/p&gt;

&lt;p&gt;How does that make things easier? If the string is 1 character, it just needs to have the code &lt;code&gt;4943.5&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The good news is &lt;a href="https://home.unicode.org/" rel="noopener noreferrer"&gt;Unicode&lt;/a&gt; does have character codes that high (&lt;a href="https://www.fileformat.info/info/unicode/char/134F/index.htm" rel="noopener noreferrer"&gt;4943 is ፏ&lt;/a&gt;, &lt;a href="https://www.fileformat.info/info/unicode/char/1350/index.htm" rel="noopener noreferrer"&gt;4944 is ፐ&lt;/a&gt;). The bad news is they are all integers so we can't get by with a one character password.&lt;/p&gt;

&lt;p&gt;If the string is 2 characters, we just need to solve a nice linear equation &lt;code&gt;2x + 3y = 9887&lt;/code&gt; where &lt;code&gt;x&lt;/code&gt; will be the first character of the string, and &lt;code&gt;y&lt;/code&gt; the second character. The &lt;a href="https://www.hackmath.net/en/calculator/integer-diophantine-equations-solver?input=2x+%2B+3y+%3D+9887&amp;amp;submit=Calculate" rel="noopener noreferrer"&gt;Integer Diophantine Equations Solver&lt;/a&gt; tells us there are over 500 integer-pairs that will open the lock (although, some don't correspond to existing unicode characters).&lt;/p&gt;

&lt;p&gt;100 is a nice number so I converted each to hex, then looked up each unicode character (&lt;a href="https://www.fileformat.info/info/unicode/char/12a/index.htm" rel="noopener noreferrer"&gt;Ī&lt;/a&gt;, &lt;a href="https://www.fileformat.info/info/unicode/char/c19/index.htm" rel="noopener noreferrer"&gt;ఙ&lt;/a&gt;):&lt;/p&gt;

&lt;pre&gt;
x100 = 298 = 0x12A =&amp;gt; Ī
y100 = 3097 = 0xC19 =&amp;gt; ఙ
&lt;/pre&gt;

&lt;p&gt;I've seeded the below RunKit example with that and you can change it to try others.&lt;/p&gt;


&lt;div class="runkit-element"&gt;
  &lt;code&gt;
    
  &lt;/code&gt;
  &lt;code&gt;
    
function jesChecksum(str) {
  var primes = [ 2, 3, 5, 7,11,
                13,17,19,23,29,
                31,37,41,43,47,
                53,59,61,67,71,
                73,79,83,89,97];
  var rtn = 0;

for (i = 0; i &amp;lt; (str.length); i++) {
    tmp = str.charCodeAt(i) * primes[i];
    rtn = rtn + tmp;
  }

return rtn;
}

// seeded with U+012A and U+0C19
jesChecksum("Īఙ") // = 9887

  &lt;/code&gt;
&lt;/div&gt;



&lt;h1&gt;
  
  
  Epilogue - Nothing is actually impenetrable
&lt;/h1&gt;

&lt;p&gt;&lt;sup&gt;📝 Elliot says this in &lt;a href="https://www.vulture.com/2015/07/mr-robot-recap-season-1-episode-5.html" rel="noopener noreferrer"&gt;eps1.4_3xpl0its.wmv&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;I used to think the stuff Elliot does in Mr Robot was entirely fictional. Then I read this thread:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-973725064507068416-255" src="https://platform.twitter.com/embed/Tweet.html?id=973725064507068416"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-973725064507068416-255');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=973725064507068416&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;The thing is, there are always security holes whether in the physical world or the software world. And software security is harder than physical security because it obeys &lt;a href="https://hbr.org/2017/05/why-is-cybersecurity-so-hard" rel="noopener noreferrer"&gt;different rules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are benefits to processing some security rules or other server-required constraints on the client-side but any &lt;a href="https://cwe.mitre.org/data/definitions/602.html" rel="noopener noreferrer"&gt;actual security should be done on the server&lt;/a&gt;. The biggest problem with the test environment I got into was it relied entirely on client side validation for security. I could have just bypassed it. It was't even obfuscated, and, though that won't stop someone who really wants to get in, it probably would have stopped me. By the way, &lt;a href="https://danielmiessler.com/study/security-by-obscurity/" rel="noopener noreferrer"&gt;adding obscurity on top of security&lt;/a&gt; is good practice, just don't let obscurity be your only security.&lt;/p&gt;

&lt;p&gt;Another big problem with the test site was rolling its own "hashing" function. Security is hard. Secure algorithms are hard. Experts created MD5 as a cryptographic hash function but that got &lt;a href="https://en.m.wikipedia.org/wiki/MD5#Security" rel="noopener noreferrer"&gt;compromised just a few years later&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Lastly, even if you do choose the right tool for the job, something may go terribly wrong if you don't use it correctly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgs.xkcd.com%2Fcomics%2Fencryptic.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgs.xkcd.com%2Fcomics%2Fencryptic.png" alt="XKCD Encryptic"&gt;&lt;/a&gt;&lt;br&gt;Explain XKCD has &lt;a href="https://www.explainxkcd.com/wiki/index.php/1286:_Encryptic" rel="noopener noreferrer"&gt;amazing details &lt;/a&gt; on this one
&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>beginners</category>
      <category>programming</category>
    </item>
    <item>
      <title>Quizlet Adopting Kotlin Multiplatform</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Wed, 18 Dec 2019 21:29:27 +0000</pubDate>
      <link>https://dev.to/touchlab/quizlet-adopting-kotlin-multiplatform-51l6</link>
      <guid>https://dev.to/touchlab/quizlet-adopting-kotlin-multiplatform-51l6</guid>
      <description>&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/kpgalligan"&gt;@kpgalligan&lt;/a&gt; shared Quizlet's Medium post, &lt;a href="https://medium.com/tech-quizlet/shared-code-at-quizlet-kotlin-multiplatform-2ee1b57646c" rel="noopener noreferrer"&gt;Shared Code at Quizlet: Deciding on Kotlin Multiplatform&lt;/a&gt;, the day it dropped. &lt;/p&gt;

&lt;p&gt;I then discovered &lt;a class="mentioned-user" href="https://dev.to/ankushg"&gt;@ankushg&lt;/a&gt; had already let that cat out of the bag nearly 2 months earlier:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1180626868174647296-253" src="https://platform.twitter.com/embed/Tweet.html?id=1180626868174647296"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1180626868174647296-253');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1180626868174647296&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;It's a super interesting read because it tells the story of trying to share with JavaScript first, thinking about sharing with C++, then finally deciding on Kotlin Multiplatform.&lt;/p&gt;

&lt;p&gt;I'm a fan of the term "platform citizen" but it's probably a coincidence that they used it too:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Kotlin Multiplatform promises the ability to write code in Kotlin and have it run as a first-class citizen on each platform.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;But here are my favorite takeaways:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;General&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For many businesses, requiring internet connectivity for core product features might be a very reasonable requirement! Quizlet however has a particularly strong affinity for mobile users with limited Internet access.&lt;br&gt;
...&lt;br&gt;
By focusing our shared code efforts on code based around state management and control flow, we saved our engineering team countless person-hours with minimal time spent on cross-platform threading or concurrency concerns.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;JavaScript&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;these issues resulted in an ecosystem where frontend web developers might have felt comfortable writing shared code, but mobile developers certainly did not feel comfortable consuming it.&lt;br&gt;
...&lt;br&gt;
We were able to write our most critical business logic in one place, ship it across multiple platforms, and unblock our resource-constrained native mobile teams. Most importantly, we were able to do this without committing to writing our entire client with the same framework.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Kotlin Multiplatform&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;even our frontend web engineers found themselves impressed by Kotlin.&lt;br&gt;
...&lt;br&gt;
In early 2019, Quizlet migrated all of our shared code over to Kotlin Multiplatform, and we are using it in production to serve over 50 million monthly active users.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Please read the whole thing: &lt;a href="https://medium.com/tech-quizlet/shared-code-at-quizlet-kotlin-multiplatform-2ee1b57646c" rel="noopener noreferrer"&gt;Shared Code at Quizlet: Deciding on Kotlin Multiplatform&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And checkout their mention in the KotlinConf Keynote alongside a several other great examples of Kotlin Multiplatform in production&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/0xKTM0A8gdI?start=781"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
Skip to 13:00 for Mobile Multiplatform mentions



</description>
      <category>kotlinmultiplatform</category>
      <category>ios</category>
      <category>android</category>
      <category>news</category>
    </item>
    <item>
      <title>How do you know when a technology is ready?</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Wed, 18 Dec 2019 15:43:03 +0000</pubDate>
      <link>https://dev.to/piannaf/how-do-you-know-when-a-technology-is-ready-1371</link>
      <guid>https://dev.to/piannaf/how-do-you-know-when-a-technology-is-ready-1371</guid>
      <description>&lt;p&gt;Technology is fast-moving. It seems there's something new to try everyday.&lt;/p&gt;

&lt;p&gt;Trying something out yourself is one thing. Piloting technology at a company is another. And putting it into production is a big deal.&lt;/p&gt;

&lt;p&gt;How do you know when a technology is ready for you and your company's time and effort?&lt;/p&gt;




&lt;p&gt;This general question inspired by by &lt;a href="https://dev.to/piannaf/kotlin-multiplatform-ready-or-not-2537"&gt;a more specific one which started life as a twitter poll&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Kotlin Multiplatform: Ready or Not?</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Wed, 18 Dec 2019 15:40:32 +0000</pubDate>
      <link>https://dev.to/piannaf/kotlin-multiplatform-ready-or-not-2537</link>
      <guid>https://dev.to/piannaf/kotlin-multiplatform-ready-or-not-2537</guid>
      <description>&lt;p&gt;The results of my twitter poll are in:&lt;/p&gt;

&lt;p&gt;Liquid error: internal&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a5XsyPka--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/aqggyeonz7dutl7e31sm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a5XsyPka--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/aqggyeonz7dutl7e31sm.png" alt="Final results: already started = 44%; Ready to jump in = 21%; still a bit too early = 35%" width="800" height="216"&gt;&lt;/a&gt;&lt;/p&gt;
What will it take to move from "too early" to "ready"?



&lt;p&gt;If you have started, what have you built and what successes and challenges have you experienced? &lt;/p&gt;

&lt;p&gt;If you haven't, what's holding you back?&lt;/p&gt;




&lt;p&gt;This question also inspired a more general one: &lt;a href="https://dev.to/piannaf/how-do-you-know-when-a-technology-is-ready-1371"&gt;How do you know when a technology is ready?&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kotlinmultiplatform</category>
      <category>kotlin</category>
      <category>ios</category>
      <category>android</category>
    </item>
    <item>
      <title>Paper as a Platform</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Fri, 06 Dec 2019 19:19:52 +0000</pubDate>
      <link>https://dev.to/piannaf/paper-as-a-platform-dc2</link>
      <guid>https://dev.to/piannaf/paper-as-a-platform-dc2</guid>
      <description>&lt;p&gt;The past couple of weeks, I've been printing articles from blogs, newspaper sites, magazine sites, and a few course description pages from a few colleges.&lt;/p&gt;

&lt;p&gt;And now it just hit me how great some of the experiences have been and how poor others have been. Images, margins, advertising, footers, etc. Some pages remove, resize, and re-emphasize exactly the right things for it to look great on the printed page.&lt;/p&gt;

&lt;p&gt;Most of the time I'm thinking about digital platforms: web, mobile, desktop (the odd kiosk now and again). But anyone could choose to print from a website, moving it from the digital platform to the paper platform.&lt;/p&gt;

&lt;h1&gt;
  
  
  Discuss
&lt;/h1&gt;

&lt;p&gt;How do you approach designing and implementing for paper UX?&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
      <category>css</category>
      <category>html</category>
    </item>
    <item>
      <title>Why did you (or not) choose cross-platform mobile technology?</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Thu, 05 Dec 2019 15:30:09 +0000</pubDate>
      <link>https://dev.to/piannaf/why-did-you-or-not-choose-cross-platform-mobile-technology-3f01</link>
      <guid>https://dev.to/piannaf/why-did-you-or-not-choose-cross-platform-mobile-technology-3f01</guid>
      <description>&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--fOsQrnVf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://pbs.twimg.com/profile_images/1189904323767078913/jO5X2gDG_normal.jpg" alt="Egor Tolstoy profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Egor Tolstoy
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @igrekde
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kDgU_xDI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      &lt;a href="https://twitter.com/jetbrains"&gt;@jetbrains&lt;/a&gt; In the last couple of months we’ve interviewed dozens of mobile developers. We wanted to understand why they choose (or don’t) to use some cross-platform technology, what are their goals, intentions and pains. And that influenced a lot how we see Mobile Multiplatform today.
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      13:59 PM - 05 Dec 2019
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1202588210246946817" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OXOJJiQT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1202588210246946817" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--foTp-unf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1202588210246946817" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SFHqU4bF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;This is an important discussion, not just for the people making the technology, but the people evaluating them too. Business context matters; team membership, recruiting and retention matter; technology, language, architecture, matters; and the community matters too. What else? And what matters to you?&lt;/p&gt;

</description>
      <category>kotlinmultiplatform</category>
      <category>kotlin</category>
      <category>ios</category>
      <category>android</category>
    </item>
    <item>
      <title>Craigslist Launches Mobile App</title>
      <dc:creator>Justin Mancinelli</dc:creator>
      <pubDate>Thu, 05 Dec 2019 13:56:13 +0000</pubDate>
      <link>https://dev.to/piannaf/craigslist-launches-mobile-app-2i1o</link>
      <guid>https://dev.to/piannaf/craigslist-launches-mobile-app-2i1o</guid>
      <description>&lt;p&gt;Woke up this morning to news that &lt;a href="https://www.launchticker.com/story/craigslist-launches-an-official-app-for-ios-it-is-the-10th" rel="noopener noreferrer"&gt;Craigslist launches an official app for iOS; it became the 10th most-downloaded app in the Shopping category one day after launch&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It was also released for iOS and Android at the same time (though Android in Beta) so I (naturally for me) wondered if it was a native app.&lt;/p&gt;

&lt;h1&gt;
  
  
  Ratings
&lt;/h1&gt;

&lt;p&gt;10th most downloaded and great ratings for iOS. &lt;/p&gt;

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

&lt;p&gt;More than 10,000 installs on Android and terrible ratings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F27bwuhu0383u67u0igu0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F27bwuhu0383u67u0igu0.png" alt="Play Store Ratings for Android app"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From my quick scanning of the reviews on Android, a lot of people are disappointed that it requires connecting to a Google account (even if you already have a Craigslist account) and frustrated that the search results on the website are different from in the app (even to the point that some things don't show up in the app with the same search string).&lt;/p&gt;

&lt;h1&gt;
  
  
  Is it native?
&lt;/h1&gt;

&lt;p&gt;I signed up for the Android beta, installed the app, and opened it in &lt;a href="https://play.google.com/store/apps/details?id=com.dexplorer&amp;amp;hl=en_US" rel="noopener noreferrer"&gt;Dexplorer&lt;/a&gt; before even opening the app.&lt;/p&gt;

&lt;p&gt;Tell-tale signs that React Native is in use.&lt;/p&gt;

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

&lt;p&gt;Confirmation that the app is React Native&lt;/p&gt;

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

&lt;p&gt;No, I don't consider React Native to be native. On &lt;a href="https://dev.to/touchlab/the-future-of-cross-platform-is-native-7cn"&gt;the scale of web to native&lt;/a&gt;, it is almost in hybrid tools territory.&lt;/p&gt;

&lt;p&gt;React Native tends to perform better on iOS than Android, though &lt;a href="https://dev.to/rishikc/react-native-just-got-better-the-new-javascript-engine-is-here-7nl"&gt;Hermes is supposed to narrow that gap&lt;/a&gt;. But given the negative Android reviews are mostly not about performance, that doesn't seem to be the issue.&lt;/p&gt;

&lt;h1&gt;
  
  
  Discuss
&lt;/h1&gt;

&lt;p&gt;I don't have an iOS device to compare personally. Maybe the feature set is different on each platform, or maybe iOS users are sufficiently different from Android users.&lt;/p&gt;

&lt;p&gt;Can anyone comment on why iOS might have such higher ratings than Android?&lt;/p&gt;

&lt;p&gt;Is anyone better at reverse engineering to see how well they are using React Native? Maybe it's just a shell for webviews in which case this app is even further in hybrid territory than other React Native apps.&lt;/p&gt;

&lt;p&gt;Craigslist keeps things quite simple as a website, any ideas why they wouldn't go the PWA route?&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>discuss</category>
      <category>ios</category>
      <category>android</category>
    </item>
  </channel>
</rss>
