diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/404.html b/404.html new file mode 100644 index 0000000..0d94b11 --- /dev/null +++ b/404.html @@ -0,0 +1 @@ +

4đŸ˜±4

40404040404

This page does not exist. If you come from a broken link, you may let me know on GitHub.

← Go back
\ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 0000000..e91b760 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +diessi.ca \ No newline at end of file diff --git a/atom.xml b/atom.xml new file mode 100644 index 0000000..9de3527 --- /dev/null +++ b/atom.xml @@ -0,0 +1,3796 @@ + + + DiĂ©ssica Gurskas + My home in the internet where I muse about life and computers. + + + Zola + 2024-09-19T13:13:42+00:00 + /atom.xml + + We Misunderstand Learning + 2024-09-19T13:13:42+00:00 + 2024-09-19T13:13:42+00:00 + + + + + Unknown + + + + + + /blog/we-misunderstand-learning/ + + <p><em>We misunderstand learning.</em> We think learning happens as we consume information, so we insist on consumption, hoping it will make sense. Reading sparks new ideas—yet often we merely seek out validation for the ones we already have. <em>We misunderstand learning.</em> We cling to theory like a lifeline, as though it can stand on its own, while overlooking the experimental space where it transforms: practice. Perhaps we gamify it. (Unlearning our addictions is another matter entirely.) We escape the confusion that must linger–it slips us that lingering isn’t forever. <em>We misunderstand learning.</em> Through edutainment, we satisfy the illusion of smooth progress, estimated reading times, chapter after chapter. True learning is too disjointed, unpredictable, and fraught with setbacks. We obsess over minimising gaps between repetitions, but are these gaps learning breaks, or learning itself? I recall the first time I picked up a guitar: my fingers aching to stretch, shredding like crazy against the strings. The morning after, I played the chord—not through conscious effort or passion, but because my fingers developed dexterity and calluses overnight. <em>We misunderstand learning.</em> Technique matters, yes, but some processes of embedding patterns are handled in their own time. Others have it easier, and we feel ashamed. I won’t lie–some do have it easier. But most often we don’t know, we weren’t there to see behind the ease, and nobody’s quite vulnerable these days.</p> +<p>We misunderstand learning, but once, we were in intimate touch with it. Back when we hadn’t yet been subjected to environments of comparison, deadlines, narrow molds, and had our complexities and neuro-diversities amassed into pure functions. I’m not immune to this. At times, learning as an adult feels like a endless chase of the instinctive dance of curiosity it once was. Throw at it: Pomodoro timers, habit trackers and productivity hacks. Yet, it’s only when I sit down to an unmysterious learning practice and truly welcome confusion, chaos, and seeming non-productivity that I feel like I can dance with curiosity again, and learn.</p> + + + + + Fetch a npm package on GitHub without npm install + 2024-08-25T16:30:00+00:00 + 2024-08-25T16:30:00+00:00 + + + + + Unknown + + + + + + /blog/fetch-npm-package-without-npm-install/ + + <p>The other day, a npm package was released broken to a private GitHub registry and it wouldn’t install:</p> +<pre style="background-color:#282a36;color:#f8f8f2;"><code><span>&gt; npm install @company/my-package +</span><span>This error happened while installing the dependencies of @company/my-package@0.0.34 +</span><span> +</span><span>another-package is not in the npm registry, or you have no permission to fetch it. +</span></code></pre> +<p>The error message is clear: the released package <code>@company/my-package</code> I’m trying to install depends on a package <code>another-package</code> expected to exist in the npm registry somewhere. But <code>another-package</code> is not there. I already knew those packages came from a monorepo, so likely <code>another-package</code> was only an internal dependency in the monorepo, left unreleased. I wanted to inspect the package contents before releasing any fix to be sure, but couldn’t rely on <code>npm install</code> for that. There used to be an option to download npm packages via GitHub UI, but that’s no longer the case.</p> +<h2 id="finding-the-package-tarball">Finding the package tarball</h2> +<p>One can read the package’s metadata to find a download URL for the package’s latest version. Here’s how:</p> +<ol> +<li> +<p>(For private GitHub registries) Grab a <a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens#creating-a-personal-access-token-classic">classic GitHub token</a> with <code>packages:read</code> permissions (hereafter <code>{GITHUB_TOKEN}</code>).</p> +</li> +<li> +<p>The URL of a npm package published to GitHub is <code>https://npm.pkg.github.com/{PACKAGE_NAME}</code>. Use that to fetch the package metadata, which contains the package tarball URL.</p> +</li> +</ol> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#ff79c6;">&gt;</span><span> curl </span><span style="color:#50fa7b;">-L</span><span style="font-style:italic;color:#ffb86c;"> -H </span><span style="color:#f1fa8c;">&quot;Authorization: Bearer {GITHUB_TOKEN}&quot; &quot;https://npm.pkg.github.com/@company%2Fmy-package&quot; </span><span style="color:#ff79c6;">| </span><span style="color:#50fa7b;">grep</span><span style="font-style:italic;color:#ffb86c;"> -o </span><span style="color:#f1fa8c;">&#39;&quot;tarball&quot;:&quot;[^&quot;]*&quot;&#39; +</span><span style="color:#f1fa8c;">&quot;tarball&quot;</span><span style="color:#50fa7b;">:</span><span style="color:#f1fa8c;">&quot;https://npm.pkg.github.com/download/@company/my-package/0.0.34/3d0304f38791214b09ec92a2262ca1697f&quot; +</span></code></pre> +<ol start="3"> +<li>Download the package using the tarball URL.</li> +</ol> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#ff79c6;">&gt;</span><span> curl </span><span style="color:#50fa7b;">-L</span><span style="font-style:italic;color:#ffb86c;"> -H </span><span style="color:#f1fa8c;">&quot;Authorization: Bearer {GITHUB_TOKEN}&quot; &quot;https://npm.pkg.github.com/download/@company/my-package/0.0.34/3d0304f38791214b09ec92a2262ca1697f&quot; </span><span style="color:#ff79c6;">| </span><span style="color:#50fa7b;">tar</span><span> zx +</span></code></pre> +<p>That will download the package to your current folder, and you may inspect the package contents now. :-)</p> + + + + + The Bitter Reality of Ebooks and the Kindle Model + 2023-08-16T13:55:00+00:00 + 2023-08-16T13:55:00+00:00 + + + + + Unknown + + + + + + /blog/the-bitter-reality-of-ebooks/ + + <p>A few years back, I jumped into the world of ebooks to broaden my reading without stacking so many physical books. I went with the ever-popular Kindle; yet the full weight of “owning” ebooks, particularly from Amazon, was not something I understood.</p> +<p>
Until I decided to break up with Amazon, despite its convenience. You know the drill: Amazon <a href="https://www.theguardian.com/technology/2020/feb/05/amazon-workers-protest-unsafe-grueling-conditions-warehouse">exploits workers</a>, <a href="https://fairtaxmark.net/tax-gap-of-silicon-six-over-100-billion-so-far-this-decade/">aggressively avoids taxes</a>, <a href="https://www.bloomberg.com/graphics/2019-amazon-reach-across-markets/">dominates markets</a>, and I was just itching to explore alternative bookstores. The hiccup? My Kindle was firmly rooted and entangled in Amazon’s ecosystem. Without Amazon, I could no longer conveniently <em>or legally</em> read books on my Kindle, and without Kindle, I could not legally read books I once purchased on Amazon.</p> +<p>Here’s what I’ve learned while attempting to part ways.</p> +<h2 id="it-all-begins-with-drm">It all begins with “DRM”</h2> +<p>Digital Rights Management (“DRM”) might not be a household term, yet its fingerprints are everywhere. <strong>Ever wondered how we consume content via proprietary software, rather than owning the content?</strong></p> +<p>Think Spotify (you never own the music), Netflix (you never own the film), Adobe Creative Cloud (you never own the software), Steam (you never own the game), and Amazon Kindle (you never own the ebook). You download those proprietary software on your device, not the content itself. While you may have a license to the content, but it’s not <em>truly</em> yours.</p> +<p>The use and distribution of the copyrighted content provided by those services (and many others) are restricted by DRM (“<em>Digital Rights Management</em>”) technologies, <a href="https://en.wikipedia.org/wiki/Digital_rights_management#Technologies">implemented in various ways, increasingly restrictive and controversial</a>. While DRM aims to address the legitimate need of copyright protection, it fundamentally reshapes the landscape of intellectual consumption, often at the expense of user privacy and freedom. For example:</p> +<ul> +<li> +<p><strong>Content Sharing</strong>: DRM often limits, or restricts altogether, the ability to share, lend and gift content outside of the same ecosystem.</p> +</li> +<li> +<p><strong>Content Portability</strong>: DRM can authorise content to only a specific set of devices or apps, and restrict the supported file formats (even to a proprietary format). That limits content migration across platforms, technologies and devices that better suit you.</p> +</li> +</ul> +<p class="note">The points above reveal an alarming side-effect: dependency on the ecosystem, or "<b>vendor lock-in</b>", which is detrimental to individual freedom and market competition. When content is tightly bound to the platform, disengaging becomes challenging. And when you're limited to sharing only within an ecosystem, your social circle gets roped in too. Kinda seem like cute digital mutualism until it's a toxic relationship you can't leave.</p> +<ul> +<li> +<p><strong>Content Perpetuity</strong>: DRM cannot guarantee perpetual access to content. If a service or platform discontinues the content or themselves entirely, you may simply lose what you purchased. In fact, <a href="https://www.bbc.com/news/technology-47810367">that has already happened</a>, <a href="https://www.nytimes.com/2009/07/18/technology/companies/18amazon.html">more than once</a> or <a href="https://www.bekkelund.net/2012/10/22/outlawed-by-amazon-drm/">twice</a>.</p> +</li> +<li> +<p><strong>Content Geographical Restrictions</strong>: DRM can prevent access to certain content based on location. With the internet alone, we could technically provide equal access to cultural and educational resources – DRM kills that.</p> +</li> +<li> +<p><strong>Content Offline Access</strong>: DRM often requires <em>online</em> authentication or periodic online checks. Not very nice in low connectivity areas or during travel.</p> +</li> +<li> +<p><strong>Personal Identification</strong>: DRM requires authentication to consume content. By withholding identifiable information, DRM systems may also monitor behavior and consumption patterns and then profile you. <a href="https://en.wikipedia.org/wiki/Nothing_to_hide_argument">You’ve got nothing to hide</a>? Well, perhaps it at least bothers you to have to login? <a href="https://en.wikipedia.org/wiki/Straw_man">(And if that keeps going on we might soon have login on physical books too?! And there will be no refresh token cookie irl?!?????)</a></p> +</li> +</ul> +<p>All those “side-effects” (given they are actually unintended 😉) of copyright protection through DRM conveniences corporations. Corporations may not only protect their profit but also <em>actively profit</em> through DRM, charging high customer cost while delivering zero customer value.</p> +<p>Finally, because DRM implementations vary so much, it’s nearly impossible to determine your rights without diving into lengthy terms of use agreements. The restrictions are rather obscured by clever marketing – you’ll soon see.</p> +<h2 id="leaving-amazon-and-failing">Leaving Amazon, and failing</h2> +<p>Do you still remember I was trying to break up with Kindle? I get too hung up sometimes but let’s not forget why we’re both here, right!!?!</p> +<p>First things first, let me make it clear – I did not want to give up ebooks. It’d been a pleasure to be able to dive into new literature and keep only the gems in my bedroom bookshelf. And I could also carry a multitude of stories effortlessly during my travels.</p> +<p>Secondly, I had no intention of trashing my Kindle. It was a fully functional piece of hardware, and it worked well.</p> +<p>So here was my grand plan: I’d log out of my Amazon account on the Kindle, and source my ebooks somewhere else. Seems pretty straightforward, right? But the hurdles kicked in right from the very first step.</p> +<p class="note">FuN fACt: <a href="https://www.bbc.com/news/technology-19907546">Kindle sales are not very profitable to Amazon</a>, as they hope to make up for it with e-book and app sales.</p> +<p>As it turns out, signing out of my Amazon account meant every single piece of content I’d ever acquired through Kindle would vanish into thin air. On Kindle, your books are tied to your Amazon account.</p> +<p>That was an unforeseen repercussion. I naĂŻvely expected to hold rights over books I’d purchased regardless of whether they were digitally or physically distributed. So I was disappointed and surprised – with myself, the state of things; both. And yes, I clearly had not read Kindle terms of use back when I got into the ecosystem (otherwise you wouldn’t be reading this! 😉).</p> +<h3 id="finally-reading-kindle-terms-of-use">FINALLY reading Kindle Terms of Use</h3> +<p>The latest <strong><a href="https://www.amazon.com/gp/help/customer/display.html?nodeId=201014950">Kindle Store Terms of Use</a></strong> (Last updated: November 30, 2022), determines a set of restrictions you buy into when you decide to buy Kindle and Kindle content, DRM-protected or not. The “Use of Kindle Content” section states a couple of DRM-ish things:</p> +<ol> +<li>ebooks are meant to be consumed only on Kindle, or Kindle apps.</li> +</ol> +<p class="note">Upon your download or access of Kindle Content and payment of any applicable fees (including applicable taxes), the Content Provider grants you a non-exclusive right to view, use, and display such Kindle Content an unlimited number of times (for Subscription Content, only as long as you remain an active member of the underlying membership or subscription program), <b>solely through a Kindle Application or as otherwise permitted as part of the Service, solely on the number of Supported Devices specified in the Kindle Store</b>, and solely for your personal, non-commercial use. [...]</p> +<ol start="2"> +<li>when you click “Buy Now”<sup class="footnote-reference"><a href="#1">1</a></sup>, you are actually buying a license i.e. renting.</li> +</ol> +<p class="note">Kindle Content is licensed, not sold, to you by the Content Provider. [...]</p> +<p>Coming from DRM-based services like Spotify or Netflix, where you subscribe for access to a collection of music or film, the Kindle model might be a surprise.</p> +<p>Within the Kindle ecosystem, you are able to buy <em>individual</em> content, which does evoke a stronger sense of direct ownership. Yet, when you do so, you’re essentially obtaining a license: every ebook is an one-off payment to a mini-subscription. And that was absolutely not straightforward or intuitive to me.</p> +<ol start="3"> +<li>you may not lend or sell your ebooks.</li> +</ol> +<p class="note">Unless specifically indicated otherwise, you may not sell, rent, lease, distribute, broadcast, sublicense, or otherwise assign any rights to the Kindle Content or any portion of it to any third party [...]</p> +<ol start="4"> +<li>your books might disappear anytime.</li> +</ol> +<p class="note">We may change, suspend, or discontinue the Service, in whole or in part, including adding or removing Subscription Content from a Service, at any time without notice.</p> +<p>(Funny enough, I checked <a href="https://web.archive.org/">Wayback Machine</a> and noticed that one was amended around March 2015, after reports of disappearing ebooks years before. đŸ€·)</p> +<h3 id="and-embracing-the-sacrifice">
And embracing the sacrifice</h3> +<p>Delving into the Kindle’s terms brought the truth crashing down on me: I never really had a choice to transition away from Amazon while retaining my content. Severing ties with Kindle came at a cost I hadn’t anticipated, and I felt very exploited for it.</p> +<p>Some might argue I <em>actually</em> had the “choice” to enter Kindle’s ecosystem. And sure, it’s true – I did it willingly, no one coerced me into becoming a Kindle user. But, hey, there’s a nuanced reality here you can’t brush aside: we make our individual choices <em>within systems</em>. There’s an entire environment lying behind the notion of individual choice.</p> +<p>Systems can be designed to subtly exert control or exploit personal choice in ways that aren’t always apparent. You can’t look at individual choice alone overseeing the environment in which those decisions are made. In no defensiveness, blaming on individual choice is, I dare to say, exactly how exploitative systems maintain their facade of legitimacy. And I don’t think being exploited or not should be a choice to be made.</p> +<p>Yeah, a bitter pill to swallow, but a new plan has to emerge out of my anger: to log out of my Amazon account, <strong>and therefore leave books I’ve purchased behind</strong>, and use Kindle only as an e-reader, not a shop.</p> +<h2 id="leaving-amazon-and-failing-less">Leaving Amazon, and failing less</h2> +<p>After logging out of my Amazon account, I’m left with an anonymised Kindle (I hope). At this point I wonder if I even have the right to keep the hardware I’ve purchased, but so far nobody hasn’t taken it away from me. 😉 So, how can I rebuild my e-book library?</p> +<h3 id="using-kindle-with-other-bookstores">Using Kindle with other bookstores</h3> +<p>Before buying ebooks elsewhere, one needs to understand what file formats are supported by Kindle. The file formats supported by Kindle are MOBI, PRC, PDF, and primarily the proprietary AZW, and the files may or may not be DRM-protected depending on the publisher. <strong>Only Amazon sells AZW books<sup class="footnote-reference"><a href="#2">2</a></sup></strong>. So my options are:</p> +<ul> +<li>MOBI. But no bookstores sell them these days.</li> +<li>PDF. But formatting sucks for reading books.</li> +<li>PRC. I don’t know what that is.</li> +</ul> +<p>So I have no options. \😎/ Bookstores sell <a href="https://en.wikipedia.org/wiki/EPUB">EPUB</a> books, an open standard well supported by all e-readers in the market <strong>but Kindle</strong>. Fortunately, you can manually convert EPUB books into one of the Kindle-compatible formats above. Unfortunately, if the book is DRM-protected (very likely!), you would need to strip out DRM before conversion <strong>which is downright illegal LMAOOOOOO</strong>!!!!! This drives me CRAZY, but let’s move on.</p> +<p>For ebook format conversions, Amazon fortunately offers <a href="https://www.amazon.com/gp/feature.html?ie=UTF8&docId=1000765261">Kindle Previewer</a>, a publishing software, but it’s just a little too bloated for my goal. So I went with <a href="https://github.com/kovidgoyal/calibre">Calibre</a>, a free and open source e-book manager that does it all. It works wonders!</p> +<p class="note">If you keep your Amazon account, importing EPUB into is easier with <a href="https://www.amazon.com/gp/sendtokindle/email">Send to Kindle</a>. It's a more convenient option but it often messes up with the book formatting.</p> +<p>Ultimately, using non-Amazon ebooks on a Kindle device can involve various technical and legal considerations, especially when dealing with DRM-protected content. DRM-free book shopping is also limited – DRM <em>is</em> an industry standard! <strong>So using a Kindle without Amazon is not just very inconvenient, it’s barely legal.</strong> 😉</p> +<p>The most promising plan seems to be tossing Kindle altogether, and choose an open standard e-reader with less hostile DRM platforms, but that’s for another time.</p> +<h2 id="amazon-caters-for-publishers-not-consumers">Amazon caters for publishers, not consumers</h2> +<p>It all makes sense when you put it all together. When traditional publishing giants contemplated the world of e-readers and online stores, they had to be a bit careful about it. With physical distribution, they already had a model that offered a clear sense of ownership and control. Then, remember the music industry’s digital transformation, marked by piracy and revenue decline<sup class="footnote-reference"><a href="#3">3</a></sup>? Obviously publishers would be wary of a similar fate.</p> +<p>But in comes a compelling offer from Amazon: a tight grip on digital ownership of books, and a shortcut into an already profitable book marketplace. All or nothing. A captivating promise of control and access which publishers, late to digital transformation, did not pass up. And so seamlessly, Amazon paved the way towards market dominance. 👏</p> +<p>Today, Amazon also positions itself as a platform for emerging writers and attracts independent publishers. So does Spotify for musicians, and Steam for game developers. For both publishers and consumers, content discovery is what’s great about such platforms, despite their license model.</p> +<p>Alternatives like Bandcamp (music) and GOG.com (games) also promote publishers’ content. In contrast, their DRM-free<sup class="footnote-reference"><a href="#4">4</a></sup> model ethically caters to both consumers and publishers: the consumer has direct ownership to content, and publishers get their content secured, even earning more<sup class="footnote-reference"><a href="#5">5</a></sup>. How does that work? Fingerprinting content files (i.e. watermarks), but above all, cultivating consumer trust and transparency, and a sense of community and support for artists.</p> +<h2 id="final-words">Final words</h2> +<p>While writing this, an analogy came to mind.</p> +<p>Picture when you buy a physical book from a store. You know that book will patiently await you right where you left it and not vanish into thin air, whether you frequent the store or it eventually shuts down. That store is unaware of your identity. It doesn’t know when you open or close the book, nor does it know which passages you’ve highlighted. You can even lend the book to a friend, regardless of whether they shop at the same store or if the store recognizes them. And that both of you can go buy books elsewhere later with no strings attached.</p> +<p>But I know that’s kinda corny. It’s an oversimplification. Digital content IS different, and copying files is far easier technically than producing physical copies. We do have new challenges.</p> +<p>Yet, while the analogy might not outright invalidate DRM as a solution, it can serve as a reminder of the current asymmetry of our digital rights today. A nudge to the way our essential rights are exploited within the current framework of digital copyright protection. And, ultimately, it extends an invitation to reimagine it from the ground up. Perhaps looking at how other platforms like Bandcamp have already done so brilliantly, perhaps radically starting at copyright itself.</p> +<h2 id="keep-reading">Keep reading</h2> +<p>
on how despite massive technical effort and corporate interest, DRM is a flawed security model.</p> +<ul> +<li><a href="https://wiki.openrightsgroup.org/wiki/Digital_Rights_Management">Open Rights Group: Digital Rights Management</a></li> +<li><a href="https://www.defectivebydesign.org/guide/ebooks">Defective by Design: Guide to DRM-Free Literature</a></li> +<li><a href="https://www.defectivebydesign.org/faq">Defective by Design: DRM FAQ</a></li> +<li><a href="https://en.wikipedia.org/wiki/Comparison_of_e-readers#File_format_support">Comparison of e-readers: File format support</a></li> +<li><a href="https://meshedinsights.com/2017/07/09/drm-is-toxic-to-culture/">DRM is Toxic to Culture</a></li> +</ul> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>As of 16/08/2023, Amazon’s checkout button for Kindle ebooks is labeled “Buy Now”.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p><a href="https://s3-us-west-2.amazonaws.com/customerdocumentation/EM/Kindle_User_Guide_EN-US.pdf">“Kindle User Guide 4th Edition</a>, p. 39</p> +</div> +<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup> +<p><a href="https://www.sowi.uni-stuttgart.de/dokumente/forschung/soi/soi_2020_4_Dolata.digital.transformation.music.industry.pdf">Ulrich Dolata, “The Digital Transformation +of the Music Industry: The Second Decade: From Download to Streaming” (2020)</a>, p. 7</p> +</div> +<div class="footnote-definition" id="4"><sup class="footnote-definition-label">4</sup> +<p>See <a href="https://get.bandcamp.help/hc/en-us/articles/360013673153-Are-Bandcamp-s-download-formats-DRM-free-">Are Bandcamp’s download formats DRM-free?</a> and <a href="https://www.gog.com/news/bgog_2022_update_2b_our_commitment_to_drmfree_gaming">GOG 2022 UPDATE #2: OUR COMMITMENT TO DRM-FREE GAMING</a>.</p> +</div> +<div class="footnote-definition" id="5"><sup class="footnote-definition-label">5</sup> +<p>In comparison to Spotify, whose profit margin for publishers is often questioned. See <a href="https://www.nytimes.com/2021/05/07/arts/music/streaming-music-payments.html">Ben Sinano: Musicians Say Streaming Doesn’t Pay. Can the Industry Change?</a>.</p> +</div> + + + + + Long Time No See + 2023-06-30T11:19:00+00:00 + 2023-06-30T11:19:00+00:00 + + + + + Unknown + + + + + + /blog/long-time-no-see/ + + <p>In the past three years, a wild mix of stuff dragged me away from writing. More time 🌳 offline ⛰, which was great. Then a demanding role in a small team, the chaotic grip of a global pandemic, increasing perfectionism, and a blossoming and ultimately collapsing relationship – which all conspired to shake up my pursuits and thrust me into an introspective whirlwind. And as if that wasn’t difficult enough, I lost two years’ worth of drafts in a backup blunder.</p> +<p>Whenever I attempted to restart, I found myself entangled in a web of what still resonated with me and what no longer did. But hey, listing more excuses would only scratch the surface. I recognize now, after seeing how little it takes for me to be back, that parts of me were simply in disarray. Yet, as I come together again, so does my motivation to reclaim what I enjoy, and make time for it despite the busyness and excuses.</p> +<p>So, last night, I did what I do best: I embarked on an in-one-sitting endeavor! I migrated this blog to <a href="https://www.getzola.org/documentation/getting-started/overview/">Zola</a> (a speedy static generator written in Rust), so this WeBpAg3 remains therefore static and snappy af, joining the <a href="https://512kb.club/">&lt;512 kB club</a>. Letting my creativity flow with <a href="https://tailwindcss.com/">Tailwind</a>, I gave my WeBpAg3 an extravagant-outrageous look, and made sure it’s accessible. I rewrote my introduction like a million times. I sifted through my writings, organising and archiving some, and lo and behold!: I stumbled upon those lost drafts hidden away in the depths of my physical backups. <em>Pretty thrilling.</em> As a friend once told me, <strong>good things happen when good things happen</strong>.</p> +<p>Long time no see! It all feels quite nice, if you ask me. 😉</p> + + + + + What I've Learned by Simply Journaling + 2020-04-20T00:10:15+00:00 + 2020-04-20T00:10:15+00:00 + + + + + Unknown + + + + + + /blog/journaling/ + + <p>In 2018, circumstances inevitably changed and I began taking up much more in life. I was under stress, regardless of being on the safe side, and the patterns that kept me grounded were no longer holding up.</p> +<p>Back then, seeing the big picture was unattainable with the stress snowballing and skewing my perspective. Dwelling in my head, paving the way to <a href="https://en.wikipedia.org/wiki/Learned_helplessness">learned helplessness</a>, I decided to try out journaling.</p> +<p>More than a year later, I can finally say <em>alles gut</em>. Although circumstances haven’t changed much, I certainly handle them better. I keep journaling as of today, and am excited to share my setup and (hopefully) motivating takeaways!</p> +<h2 id="how-i-journal">How I Journal</h2> +<p>I did not go for the traditional diary format. I decided to Bullet Journal, a flexible journal method founded in quick lifelogging by means of a pen, paper, and bullet points.</p> +<p>Pen and paper pull me out of my head and let me continuously evolve my notebook as my needs change, since there is no predefined template. As for bullet points, we all know their efficacy: hasty logging and later reviewing at a glimpse.</p> +<h3 id="method">Method</h3> +<p class="note">Peek into <a href="https://bulletjournal.com/pages/learn">Bullet Journal official page</a> for an overview, as I won't dive into the framework basics.</p> +<p>The Bullet Journal framework is made out of four fundamental “collections”: Index, Daily Log, Monthly Log, and Future Log, plus custom collections you find valuable. After a while of tinkering around, I came to some insights and tweaks.</p> +<ul> +<li> +<p><strong>Index</strong> turned out useful when I added custom collections, as those usually end up scattered across the journal and thus hard to find.</p> +</li> +<li> +<p><strong>Daily Logs</strong> is where I keep track of notes, events, tasks, thoughts, and ideas. (All mixed together, which portrays a day accurately if you ask me.) I recommend using signifiers and nesting (for a tree-like view) in bullet points to convey meaning with ease, as Bullet Journal suggests.</p> +</li> +<li> +<p><strong>Monthly Log</strong> didn’t work for me. I steer towards weekly or quarterly ranges. Also, my online calendar is more practical so I couldn’t bother drawing calendars every month.</p> +</li> +<li> +<p><strong>Future Logs</strong> are useful to migrate tasks or events to upcoming months, for when you don’t get something done but can’t “nevermind” it either.</p> +</li> +</ul> +<p>As for custom collections, the Bullet Journal ecosystem is huge! I’ve seen stuff of all kinds out there: finance/sleep/food/water trackers, recipes, trip planning, doodles, and whatnot. Yet, these are the ones I always come back to:</p> +<ul> +<li><strong>Diaries</strong>: longer diary entries or brain dumps without the limitation of bullet points, for when I feel like it.</li> +<li><strong>Habit Trackers</strong>: a simple daily tracker to monitor or develop habits across weeks, e.g. meditation, alcohol intake, call family.</li> +<li><strong>Weekly Logs</strong>: my weekly variation of “Monthly Log”, with upcoming events and small goals for the week. Usually done on Sunday or Monday.</li> +<li><strong>Quarterly Logs</strong>: my quarterly variation of “Monthly Log”, with upcoming events and big goals for the quarter.</li> +<li><strong>Year Retrospective</strong>: a straightforward year review regarding what did and did not go well, what to keep or let go from last year etc. +I journal spontaneously throughout the day, but mostly in mornings or evenings. I do it every day, even when I don’t feel like it. In the long run, that’s gotten me to fathom my anxieties by having them logged as well as what was up days before. It goes a long way to flip through logs of piled up chores, social isolation, binge drinking, and sleep deprivation, to later find yourself taking down “I am anxious. Can’t do shit”.</li> +</ul> +<p>Be that as it may, I don’t keep it all gloomy. With my throughput in mind, I may also soften up my daily logs with receipts from exquisite restaurants I come across, cute post-its from friends, or even silly useless quotes from fortune cookies.</p> +<p>At last, I have to say I’m not really a big planner so you can see that’s not what I optimise my journal for. All I strive for is a little awareness of whatever I’m doing for the time being. I enjoy a spontaneous and organic life, and that’s gotten me far enough to make me happy.</p> +<h3 id="pen-paper">Pen &amp; Paper</h3> +<figure class="text-center"><picture><img src="../../media/2020/bullet-journal.jpg" alt="Notebooks on desk. On the left: Camel brown notebook with bear symbol on cover. On the right: Forest green notebook with deer symbol on cover."></picture> +<figcaption> +My 2019 journal (left) and 2020 journal (right).</figcaption></figure> +<p>In 2019, I used an A5+ (slightly wider than regular A5) dot-grid notebook. It’s bulky to carry around but I don’t regret it: the pages are wide enough to encourage writing. The quality of its pleasing yellow paper is outstanding, thick enough to prevent ink from leaking through. I ended 2019 with a few pages empty.</p> +<p>This year, I went for something more portable: an A6 dot-grid notebook. It took me a while to get used to the size constraints, and I’ve been certainly more straightforward with my logs. I am pretty sure I will have no pages left this time. (Wondering what was the advantage of it all as I’m not going anywhere anyway thanks to COVID-19.)</p> +<p>As for pens, I use different colours of a 0.4 mm fineliner.</p> +<h2 id="what-i-ve-learned">What I’ve Learned</h2> +<p class="note">I'd not assume these stem necessarily from the way I set myself up. Audio or video recordings, traditional diary, and other journal formats are worth exploring and might help just as well.</p> +<ul> +<li> +<p><strong>Less overwhelm, more time.</strong> To truly chill out when life gets overwhelming, you gotta plan ahead. Especially in already busy weeks, I use my journal to put down chores I commit to get done, prioritising what I signify as deadline-sensitive. Before, with my tendency to overfocus, I’d take up activities without planning and end up neglecting my responsibilities and needs. Imagine how far this can go!</p> +</li> +<li> +<p><strong>Emotional awareness.</strong> I’ve gained a grasp of the phenomenology of my emotions and the lens through which I see life, markedly my cognitive distortions on stressful days. Attitudes like pessimism inevitably surface as you jot down negative thoughts all the time. Being mindful allowed me to reframe negative views, and turn obstacles into opportunities.</p> +</li> +<li> +<p><strong>Better retainment.</strong> It’s easy to fall into the trap of “I have a bad memory” when one has been busy and mooning for so long. Leading a busy life mindlessly is not what I strive for, and journaling only feeds into that: I hold dear people, moments, promises, and no longer miss so many appointments (planning helped here too!).</p> +</li> +<li> +<p><strong>Constant assessment.</strong> Journaling is a tool to assess the present as well as the past and the future. By peeping into where I’ve been, what did/didn’t go well, or who I have been with, for instance, I can ponder more sensibly on my growth and relationships. Early feedback on my own life, sort of, to leverage self-improvement in relationships, health, work, and so on.</p> +</li> +</ul> +<h3 id="pitfalls">Pitfalls</h3> +<ul> +<li> +<p><strong>Perfectionism.</strong> Obsession over constant logging or perfection is right at the door for you to slip into. On social media (Pinterest, YouTube), everyone’s journal seems visually-appealing every day without fail. Even Bullet Journal, a method dead straightforward, can be a rabbit hole. Remind yourself to solve your problem in a way that enhances your daily life, not burdens it. You gain absolutely nothing from buying into slices of life people sell online.</p> +</li> +<li> +<p><strong>Habit-building.</strong> When not a habit, journaling is just another chore. Make it effortless and engaging: establish a routine (if that’s your thing), designate it a place where it’s always within reach, or tailor the framework to your needs. If you enjoy drawing once in a while, why not? If you have no patience for 29872 different pen colours, why do it? If you want to write about your day with your partner in bullet points instead of coming up with a best-seller love story, who cares?</p> +</li> +<li> +<p><strong>Procrastination.</strong> Journaling constantly nudges you to look back at your life and how you’ve been spending your time and energy. That can be challenging and won’t change. For starters, you might come to the unpleasant realisation that you self-sabotage, or that a certain relationship is fading away. If you are avoidant, you will most likely put off journaling often; not because of the method or routine, but fear of what you may find – fertile soil for procrastination.</p> +</li> +<li> +<p>For pen &amp; paper
 <strong>No backup</strong>. Some companies have tried, but what’s hand-written won’t sync with a cloud server. You do carry the weight if traveling or taking it to work, and it’s probably gone if you spill coffee on it. I, though, think the trade-off is worth it and haven’t looked back.</p> +</li> +</ul> +<h2 id="final-takeaway-takeout-box">Final Takeaway đŸ„Ą</h2> +<p>I am all for simplicity, yet that didn’t keep my mind from boggling when I realised such a simple tool turned out to be a game-changer. Starting off was not easy, but the benefits showed up and kept me motivated – a rewarding feeling I wouldn’t expect so hastily while building a new habit. Today, it’s just effortless and natural.</p> +<p>Ultimately, I hope this stimulates you to try journaling in whatever way and to deem simple tools as helpful to uncomplicate and improve our lives.</p> +<h2 id="references">References</h2> +<ul> +<li><a href="https://bulletjournal.com/pages/learn">Learn Bullet Journal</a></li> +</ul> + + + + + How to Spy on a React Prop with Jest + 2019-10-31T14:15:42+00:00 + 2019-10-31T14:15:42+00:00 + + + + + Unknown + + + + + + /blog/how-to-spy-on-a-prop-with-jest/ + + <p>When we want to test whether a prop has been called, mocking the prop in the component is usually the preferred way. This is how it goes with <a href="https://jestjs.io/">Jest</a> and <a href="https://airbnb.io/enzyme/">Enzyme</a>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">buy </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">jest</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">fn</span><span>(); +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">wrapper </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">enzyme</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">shallow</span><span>(&lt;button onClick={buy}&gt;</span><span style="color:#ffffff;">Buy</span><span style="color:#ff79c6;">&lt;/</span><span style="color:#ffffff;">button</span><span style="color:#ff79c6;">&gt;</span><span>); +</span><span> +</span><span style="color:#ffffff;">wrapper</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">simulate</span><span>(</span><span style="color:#f1fa8c;">&quot;click&quot;</span><span>); +</span><span> +</span><span style="color:#50fa7b;">expect</span><span>(</span><span style="color:#ffffff;">buy</span><span>)</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">toBeCalled</span><span>(); +</span></code></pre> +<p>You may also want to spy on the prop directly, when the component is tested along with a provider passing down its props.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">wrapper </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">enzyme</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">shallow</span><span>( +</span><span> &lt;ClickProvider&gt; +</span><span> &lt;button&gt;</span><span style="color:#ffffff;">Buy</span><span style="color:#ff79c6;">&lt;/</span><span style="color:#ffffff;">button</span><span style="color:#ff79c6;">&gt; +</span><span> </span><span style="color:#ff79c6;">&lt;/</span><span style="color:#ffffff;">ClickProvider</span><span style="color:#ff79c6;">&gt; +</span><span>); +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">buy </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">jest</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">spyOn</span><span>(</span><span style="color:#ffffff;">wrapper</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">instance</span><span>()</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">props</span><span>, </span><span style="color:#f1fa8c;">&quot;onClick&quot;</span><span>); +</span><span> +</span><span style="color:#ffffff;">wrapper</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">simulate</span><span>(</span><span style="color:#f1fa8c;">&quot;click&quot;</span><span>); +</span><span> +</span><span style="color:#50fa7b;">expect</span><span>(</span><span style="color:#ffffff;">buy</span><span>)</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">toBeCalled</span><span>(); +</span></code></pre> +<p>I am using Enzyme however you should be able to spy on similarly using other testing libraries – just make sure you are spying on a function in the props coming from the component prototype (as in <code>wrapper.instance()</code>).</p> +<p>That’s all. Just posting it here cuz I couldn’t find it easily anywhere else.</p> + + + + + Setup for Audio Interface with Guitar Rig 5 on macOS Mojave + 2019-08-18T22:19:05+00:00 + 2019-08-18T22:19:05+00:00 + + + + + Unknown + + + + + + /blog/guitar-rig-macos-mojave-setup/ + + <p>Setting up <a href="https://www.native-instruments.com/en/products/komplete/guitar/guitar-rig-5-pro/">Guitar Rig 5</a> on macOS Mojave seems not to be straightforward.</p> +<p>Although I had gotten the signals to be sent from my guitar to the audio interface and from the interface to Guitar Rig, somehow it’d still not work. Instead of using my audio interface as the input <strong>and output</strong> device on Guitar Rig, I had to set up an “aggregate device”.</p> +<p>This how you can do it too.</p> +<p>(My specs, just so you know:)</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">macOS</span><span> Mojave Version 10.10.14 +</span><span style="color:#50fa7b;">Guitar</span><span> Rig Pro 5.2.2 +</span><span style="color:#50fa7b;">Audio</span><span> Interface Steinberg UR22mkII +</span></code></pre> +<h2 id="audio-midi-setup">Audio MIDI setup</h2> +<ol> +<li> +<p>Open “Audio MIDI setup” in your Mac. (It’s a tiny secret sound manager shipped along with the system, you’ll find it.)</p> +</li> +<li> +<p>At the very bottom of the app, there is a small + (“plus”) button wherein you should select <em>“Create an aggregate device”</em>.</p> +</li> +<li> +<p>Set up your “aggregate device” with your 1) audio inteface and 2) speakers/headphones/whatever – which should be all shown up there, given the setup is correct. Remember to give your device a remarkable name – I suggest <em>FUCK COMPUTERS AND AUDIO</em>.</p> +</li> +</ol> +<figure class="text-center"><picture><img src="../../media/2019/guitar-rig-macos-mojave-setup/audio-midi-setup.png" alt="Audio MIDI Setup app open showing audio device with both devices'"></picture> +<figcaption>My custom device in Audio MIDI Setup on macOS.</figcaption></figure> +<ol start="4"> +<li>Go back to Guitar Rig. In the context menu “File”, go to <em>“Audio and MIDI Settings”</em>. In the “Audio” tab, select your aggregate device as the <strong>device</strong>, instead of only the audio interface as you were doing before; then configure input/output as expected in the “Routing” tab.</li> +</ol> +<p>Should work! If it doesn’t, <a href="https://support.native-instruments.com/hc/en-us/articles/210275885-I-Cannot-Get-Any-Sound-Output-from-GUITAR-RIG-5">this guide by Native Instruments on how to troubleshoot audio</a> and others guides on the website might help. Depending on your audio interface, make sure the right driver setup is in place – you can try out <a href="http://www.asio4all.org/">ASIO4ALL</a>.</p> +<img src="../../media/2019/guitar-rig-macos-mojave-setup/guitar-rig.png" alt="Guitar Rig app showing its custom amps"> +<p>If it still doesn’t work, I am sorry and prolly have no idea. Have fun.</p> + + + + + OMG Climate: Reflecting Together on the Climate Catastrophe + 2019-05-30T11:39:14+00:00 + 2019-05-30T11:39:14+00:00 + + + + + Unknown + + + + + + /blog/omg-climate/ + + <figure class="text-center"><picture><img src="../../media/2019/omg-climate/global-warming-nasa.gif" alt="NASA's illustration of Planet Earth warming process across the years"></picture> +<figcaption>Credits: NASA’s Scientific Visualization Studio/Kathryn Mersmann.</figcaption></figure> +<p>Planet Earth, May 2019. <a href="https://www.weforum.org/agenda/2019/05/the-uk-just-became-the-first-country-in-the-world-to-declare-a-state-of-emergency-on-climate-change">The UK has announced a state of emergency for climate change</a> and <a href="https://globalnews.ca/news/5280082/what-is-a-climate-emergency-canada/">Canada considers the same</a>; we are <a href="https://agupubs.onlinelibrary.wiley.com/doi/10.1029/2018JD029522">more confident about our model to capture rising global temperatures</a>, and <a href="https://www.theguardian.com/environment/gallery/2019/may/24/student-climate-strikes-around-the-world">students all around the world walk out of school protesting the lack of climate action</a>. Yet, not enough of us are genuinely concerned about the role we’ve played on this catastrophe.</p> +<p>A Saturday afternoon of May and a few square meters in Berlin were what a couple of people needed to open– and voluntarily discuss how we impact the Planet to change and how those changes impact us. Topics ranged from radical solarpunk utopia to more down-to-earth and short-term ideas within our generation’s reach today: musings about climate change awareness, sustainability policies for companies, traveling sustainably, tech tools for political change, and how to get out of our bubbles and active listen to other realities.</p> +<p>In this post, I’ll be sharing my personal notes on that engaging and constructive afternoon. There will be, also, references at the end of this post so you can keep yourself posted.</p> +<h2 id="pitching-and-picking-topics-for-discussion">Pitching and picking topics for discussion</h2> +<p><strong>OMG Climate</strong> is an unconference, meaning that attendees proactively come up with the agenda and topics to be discussed. To kick it off, we got instructed to pitch topics for discussion that’d be prioritised also by ourselves into tracks, attended based off our preferences. Everyone was expected to have at least a certain knowledge, even if rather tacit, about the challenges we’re facing right now with the climate emergency.</p> +<p>These were the tracks of the first OMG Climate:</p> +<ul> +<li><strong>Track 1</strong>: “Low-carbon travel” / “Green Mafia” / “How do you sleep at night? Coping with climate anxiety”</li> +<li><strong>Track 2</strong>: “Tech tools for political action” / “Circular economies: Re-use and tech” / “Company sustainability policy template”</li> +<li><strong>Track 3</strong>: “Solarpunk, imagination and excitement” / “CO2 Offsets as an API and tracking carbon” / “Climate change awareness in developing countries”</li> +</ul> +<p>We had enough attendees for tracks to make for productive discussions. Listening and talking to one another, while facilitated by a volunteer, did the job on keeping up an constructive flow between finding root causes and ways to take action.</p> +<figure class="text-center"><picture><img src="../../media/2019/omg-climate/discussion.jpg" alt="People sitting in a circle, listening attentively to one"></picture> +<figcaption>During the "Green Mafia" discussion.</figcaption></figure> +<p>I’ve joined “Low-carbon travel”, “Green mafia”, and “Climate change awareness in developing countries”, so these are the ones I have more insights about. Towards the end, we all got together to wrap it up, and I have to say: all tracks were interesting, so don’t restrain yourself to this post!</p> +<p class="note">The following notes don't reflect directly what's happened or everything that's been said in the event, it's rather my personal perspective. They are also somewhat vague, but I hope you can benefit from them somehow.</p> +<h2 id="low-carbon-travel">Low-carbon travel</h2> +<p>Air travel, even when occasional, has an <a href="https://en.wikipedia.org/wiki/Environmental_impact_of_aviation#Climate_change">environmental impact</a> difficult to make up for no matter how many bamboo toothbrushes we gift our friends, how often we commute by bike or how vegan is our diet.</p> +<p>With low airplane ticket prices getting more popular than ever and enabling people to travel more, how can we make traveling sustainable when <em>not traveling to begin with</em> is not an option? That was the question we kicked off the “low-carbon travel” discussion with.</p> +<h3 id="meeting-notes">Meeting notes</h3> +<figure class="text-center"><picture><img src="../../media/2019/omg-climate/low-carbon.jpg" alt="Piece of paper sticked to the wall with sketches"></picture> +<figcaption>Collective sketch notes about the low-carbon travel track</figcaption></figure> +<ul> +<li>In our circle, everyone seemed to have access to the privilege that is air flying.</li> +<li>We began exploring traveling by breaking it down into traveling for work vs. pleasure.</li> +<li><strong>Ground travel</strong> might be an option; however, it’s rather time-consuming and hence less appealing in a capitalist society where time translates to money. How can we shift the paradigm?</li> +<li>Instead of seeing longer trips as wasted time, we should begin seeing the journey as part of the trip.</li> +<li><strong>Traveling less</strong>: We often optimise our trips to visit as many places as possible; instead, we can optimise for depth and start going to fewer places for a longer time. Think: going to a European country and making the most of it, instead of going to 999 different countries just because they are 1-hour-flight away from each other.</li> +<li>Share practical solutions for people to make trade-offs, <a href="http://ecocostsvalue.com/"><strong>EcoCost</strong></a> rather than overwhelming scientific evidence.</li> +<li>What if companies supported employees whose carbon footprint is the least?</li> +<li>Green travel agencies and flying policies.</li> +<li>Search engines for flights obviously don’t suggest alternative ways to get to a place when a plane is definitely not the best option.</li> +<li><a href="https://bvg.de">BVG</a> app, on the other hand, recommends walking instead of taking public transport sometimes.</li> +<li>Transport apps could also order route options by the least environmental impact.</li> +<li>The car industry should be ashamed of its climate record.</li> +<li>The train industry is not modernised and integrated, rather rigid.</li> +<li>Investment on 10 km of autobahn could pay off the renovation for bike lanes all over Berlin.</li> +<li>Globalisation vs. environmental footprint: IT workers immigrating usually go back to their countries often since they have the need and resources. I asked whether there was data available on how that situation in particular could’ve increased our carbon emissions coming from aviation.</li> +<li>Business trips by train are possible only among those who have the privilege of a flexible work schedule, such as freelancers.</li> +<li>Making the most out of idle time: we tend to be more creative in idle times, while in a train; not hunching over a keyboard or in an office environment.</li> +<li>“Fast-moving home/office” as an alternative to turn the journey time into productive time.</li> +<li><strong>Frequent flyer levy</strong>: A fairer tax system according to how often people fly. Those that fly more should pay more. (More information: <a href="http://afreeride.org/">A Free Ride</a>)</li> +<li>Airline campaigns often promote the image that everyone should become part of a group of young, urban frequent flyers, visiting another city every few weeks for very low costs.</li> +</ul> +<h3 id="action-points">Action points</h3> +<ul> +<li>everyone to shift mindsets in regard to traveling.</li> +<li>everyone to vote instead of buying a bamboo toothbrush.</li> +<li>everyone to use and promote tools with different options of transport within a route, instead of blindly going to specific train or flight websites.</li> +<li>everyone to keep consuming local goods.</li> +<li>airline companies to stop promoting flying as a status symbol.</li> +<li>travel agencies to work out more sustainable ways to travel and consider it in their branding.</li> +</ul> +<h2 id="green-mafia">Green Mafia</h2> +<p>How corporate interests and ideologues work to undermine science and make countries doubt about the risks of climate change? Think <a href="https://www.theguardian.com/environment/planet-oz/2015/aug/06/how-australians-were-ready-to-act-on-climate-science-25-years-ago-and-what-happened-next">what stopped Australia, 25 years ago, to act on climate change</a>.</p> +<p>We should fight back! We mused about beating off lobby groups representing the coal, car, oil, electricity, and aluminium industries using their same sneaky techniques, as a <strong>Green Mafia</strong>. An intriguing and fun topic!</p> +<p>The brainstorming served as a tool to get a grasp on the way those mafias function, and discuss whether the ethical approach is always the way to go when facing a crisis.</p> +<h3 id="meeting-notes-1">Meeting notes</h3> +<figure class="text-center"><picture><img src="../../media/2019/omg-climate/green-mafia.jpg" alt="Piece of paper sticked to the wall with sketches"></picture> +<figcaption>Collective sketch notes about the Green Mafia track</figcaption></figure> +<ul> +<li>Leverage civil disobedience and tools of intimidation to influence green policies for the climate, fight extreme wealth and weaken existing mafias such as the oil industry.</li> +<li>How far should one go with non-ethical practices, such as blackmailing or public shaming of those who harm the planet?</li> +<li>What’s ethics after all?</li> +<li>Could we use illegal money to fund our causes?</li> +<li>Could we use legal money to fund our cases? There are ways to get money from the state in licit ways such as from green parties.</li> +<li>What if we made the green cause as profitable for the mafia as oil?</li> +<li>Sell a belief system, or use an existing one such as “harmony with nature”.</li> +<li>Cyber hacking/hijacking internet algorithms to spread awareness instead of climate change denial and fake news as it happens today.</li> +</ul> +<h2 id="awareness-in-developing-countries">Awareness in developing countries</h2> +<p>The rich, the poor and the Earth.</p> +<p><a href="https://www.theguardian.com/environment/2015/dec/02/worlds-richest-10-produce-half-of-global-carbon-emissions-says-oxfam">World’s richest 10% produce half of the global carbon emissions, while the poorest half contribute a mere 10%</a>; but climate change affects the poorest people the most. Moreover, developing countries are the most responsible for climate change now, and vulnerable too.<sup class="footnote-reference"><a href="#1">1</a></sup></p> +<p>Coming from a developing country, I was looking forward to this topic! Apart from Brazil, we had people from India too. There was a range of issues that could be tackled within this track, such as the risk of massive displacements of people in developing countries, the need of support to adapt, environment destruction for the sake of economic prosperity, how to approach climate change education etc.</p> +<h3 id="meeting-notes-2">Meeting notes</h3> +<ul> +<li>We are <strong>building awareness</strong>, not “teaching” others about climate change.</li> +<li>Climate change is an existential threat to life, but it seems rather remote if you think about poverty, disease and economic stagnation. How do we educate children for the long-term if, for some of them, not showing up at school tomorrow means not eating at all?</li> +<li>How do we let them know about the risk of massive displacements of people who have no resources whatsoever to move?</li> +<li>Just by existing in a developed country in Europe, our carbon footprint is more impactful than any developing country.</li> +<li>Indigenous people are already defenders and protectors of the environment more than we will ever be in our generation.</li> +<li>Economic development is a priority in developing countries, and politicians may ignore environmental impact for the sake of it. (See <a href="https://www.climatechangenews.com/2019/01/22/brazils-natural-resources-open-business-bolsonaro-says/">Brazil’s natural resources open for business, says Bolsonaro</a>)</li> +<li>Developing countries idealisation of economic development, influenced by “developed world standards”: tall buildings and industries all over the place, where often we don’t see the green implications of “success”.</li> +<li>What about a model of development thats puts together the simple living of developing countries with the green development of developed ones?</li> +<li>How waste affects developing countries; example of <a href="https://www.bangkokpost.com/news/world/1666380/philippines-duterte-says-to-sail-garbage-back-to-canada">Philippines to sail garbage back to Canada</a>.</li> +<li>We could shift the discussion to think about environmental impact in terms of social classes instead of countries. After all, rich lifestyles and “status” in general damage the environment in untold ways.</li> +<li>The <a href="https://en.wikipedia.org/wiki/Swadeshi_movement">Swadeshi movement</a> brought back self-manufactured clothing in India to boycott foreign goods, a part of a movement to liberate India from British control and industrialisation.</li> +<li>When teaching, consider what’s in people’s context, reach and language instead of what’s “out there”.</li> +<li>We should actively listen more to those communities and what’s happening in those countries. Sometimes, instead of thinking that there is something to be taught, we should rather learn from their realities so we can bring about a meaningful conversation.</li> +<li>This is a problem not to be approached by technology, remotely. It’s rather about Politics and Education.</li> +</ul> +<h3 id="action-points-1">Action points</h3> +<ul> +<li>everyone to assure inclusivity, cooperation and engagement across boundaries, <strong>first and foremost</strong>.</li> +<li>countries to keep cooperating efforts <em>internationally</em> through policies, institutional frameworks for development and investments in infrastructure.</li> +</ul> +<h2 id="conclusion">Conclusion</h2> +<p>Well-led communities that strive for welcoming environments enable the best out of people. OMG Climate has shown that – its <a href="https://en.wikipedia.org/wiki/Unconference">unconference format</a> got everyone to take responsibility and engage towards constructive and meaningful discussions about climate change.</p> +<figure class="text-center"><picture><img src="../../media/2019/omg-climate/presentation.jpg" alt="Participant presenting using microphone, all sketch notes of the unconference sticked to the wall, on background"></picture> +<figcaption>Final presentations wrapping up the tracks.</figcaption></figure> +<p>Although most of us had a tech background, everyone seemed aware: tech alone will not solve all problems, but we are eager to address them either way.</p> +<h2 id="learn-about-climate-change">Learn about Climate Change</h2> +<ul> +<li>Reddit: <a href="https://www.reddit.com/r/climatechange/">/r/climatechange</a> and <a href="https://www.reddit.com/r/globalwarming/">/r/globalwarming</a></li> +<li><a href="https://www.theguardian.com/environment/climate-change">The Guardian on Climate Change</a></li> +<li><a href="https://ourworldindata.org/co2-by-income-region">Global inequalities in CO₂ emissions</a></li> +<li><a href="https://anildash.com/2018/10/03/were-still-not-being-alarmist-enough-about-climate-change/">We’re (still) not being alarmist enough about climate change</a></li> +</ul> +<h2 id="more-on-omg-climate">More on OMG Climate</h2> +<ul> +<li><a href="https://ti.to/omg/climate/">OMG Climate Event page</a></li> +<li><a href="https://medium.com/omg-climate">OMG Climate Medium website</a></li> +<li><a href="https://twitter.com/search?q=%23omgclimate&amp;src=typed_query">#OMGCLIMATE on Twitter</a></li> +<li><a href="https://climateaction.tech/">ClimateAction.tech</a></li> +</ul> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p><a href="https://www.cgdev.org/blog/climate-change-and-development-three-charts">Climate Change and Development in Three Charts</a></p> +</div> + + + + + I've Sensory-Deprived Myself In a Tank + 2018-12-02T08:01:00+00:00 + 2018-12-02T08:01:00+00:00 + + + + + Unknown + + + + + + /blog/isolation-tank/ + + <p>I struggle every day trying not to be one step ahead. Living everywhere else but the present and leaping through time have become part of how my brain is wired, so I often find myself not experiencing much anymore.</p> +<p>A while ago, a friend told me about his sensory-deprivation experience in some kind of pool, the so-called <a href="https://en.wikipedia.org/wiki/Isolation_tank"><em>Isolation Tank</em></a>. No sight, no hearing, no touch, no taste, no smell – the idea of getting absolutely no input from anywhere struck me as a way to get my perception back on track. I decided to try it out.</p> +<p>On a sunny Saturday of November, I, along with my endless stream of thoughts, floated for 1 hour straight in a soundproof egg-shaped tub shallowly filled up with salt water. This is my report.</p> +<h2 id="getting-in">Getting In</h2> +<p>With my bathing suit on and no expectations of anything, I showered, got into the tub and sealed down its cover. My body floated easily on that water that thermically felt like my own skin, and a relaxing sound was playing in the background up to the moment my surroundings got all pitch-black.</p> +<p>The first 15 minutes were all about withstanding how restlessly my mind wanted to get out of there. I’ve had done meditation before, but 1 hour was <em>something else</em>. I recalled I worked 8 hours a day, 5 days a week, and therefore I should be making the most out of my Saturday instead. Leisure time! In modern life, that usually means stimulation by means of binge-drinking with friends, uplifting music, delicious food, watching heart-breaking movies
. Quite the opposite of soul-crushingly doing nothing.</p> +<p>The mind just plays a lot of games on you all the time. It tricked me into being <em>physically</em> irritated by the water, its salt, that bogus zero-gravity environment, and that I’d be better off giving up <em>for my own survival</em>  – at least, that was how my body anxiously (over-)reacted to it. But there was actually no physiological danger or whatsoever; truth be told, I was way safer than I had ever been throughout that week. I quit panicking.</p> +<p>I came upon different phases of denial, approval and mind-numbness from that onwards. Saw myself bringing up problems and drifting them away. Tried to work out situations I had no control over. Missed music, so made my own by tapping on the water. Went hyper-focused on how I had performed socially last week to what was going to happen in the next few weeks when I eventually hand over my old apartment’s keys to that spiteful Hausmeister who hates my German.</p> +<p>My thoughts just went on super randomly. After a while, I could draw the exact line where each one ended, and got mindful about my weary physical overreactions to them.</p> +<p>Towards the end, I sank into something else: weightlessness, timelessness, solitude were emerging from that isolation. Things started losing shape. Didn’t perceive water. I was either a floating head or a floating body. I had to touch my thighs, boobs, neck just to relieve myself from the uncertainty that being so relaxed made me feel about where I was.</p> +<p>I wanted to come back down to Earth from wherever I was, and, surprisingly, <strong>to be myself</strong> – the way I was. Then time was up.</p> +<h2 id="getting-out">Getting Out</h2> +<p>I showered again to wash the salt off. The spa provided a relaxation lounge that was essential to ease the transition, since I had neither desire nor need (important!) to rush anywhere. Hung out there for 1 hour.</p> +<p>The readjusting was an interesting and unexpected phase to me. Had an apple and felt how crispy in sound and taste it was. Drank a glass of water and sensed it going <em>right down through</em>. Read a book and couldn’t make sense of why we humans have ever brought up speed reading techniques in the first place.</p> +<p>Stepping out of the spa, I got savagely welcomed by a gloomy afternoon<sup class="footnote-reference"><a href="#1">1</a></sup> undergoing that life I was used to every day. A lot was happening out there: lights of apartments being turned on and out, cars groaning, people running around, traffic noise, the cozy energy of having my friend by my side, sharper textures of the sidewalks’ cobblestones, and the joy of a having a sky whose amount of stars doesn’t depend on the many times we screw up as human beings, thankfully.</p> +<p>Berlin-Schöneberg is quite chill so that’s helped to readjust. I was sensible and my thoughts were vivid and receptive – pretty much the actual poetic mood I strive for, where I settle and listen to what’s being said in order to write it down. A mood that is “highly disturbed by Philosophy”, as Goethe brilliantly summed up to Schiller once:</p> +<p><em>“I am still hoping for poetic hours, and philosophy, in my case, disturbs the poetic mood, probably because it drives me into the object, for I am never able to keep myself in a purely speculative mood, but have immediately to try and form a distinct conception, and on this account at once fly out into nature. [
]</em><sup class="footnote-reference"><a href="#2">2</a></sup></p> +<p>I had finally my mind drifted towards just as much of the world as it was going on.</p> +<h2 id="lessons-learned">Lessons Learned</h2> +<p>My poetic mood didn’t last much – it wore off the day after.</p> +<p>I’ve realized how much we are externally stimulated and easily adapt to it as if it were natural. On top of that, we are internally stimulated by our worries and whatnot: have I paid my taxes? Am I persuading a career? Does my family still love even though I am thousands of kilometers from them? Have I been eating healthy enough?</p> +<p>It turns out it’s clear why we don’t feel much anymore. Our brain gets wired to parallelising stimuli, and we have less and less coming from our body to the head than the other way around. Apart from that, our experience of the world is barely passive: <strong>we actively generate it</strong> with our biases, mental models, what and how much we consume. Mind shortcuts are crucial, but might restrain us from genuinely experiencing life, getting us to either ignore ou hyper-focus unconsciously.</p> +<p>I, now, have a better grasp of what Erling Kagge meant in <a href="https://www.goodreads.com/book/show/36243813-silence">Silence: In the Age of Noise</a>, written after he had spent fifty days walking solo in Antarctica: <em>“Everything seemed completely flat and white. [
] Eventually, in complete isolation, I began to notice that nothing was completely flat after all. The ice and snow formed small and large abstract shapes. The uniform whiteness was transformed into countless shades of white. [
]”</em></p> +<p>Meditation is the absolute protagonist here, but floating got me into a different flow, and faster. The topic of <a href="https://en.wikipedia.org/wiki/Sensory_deprivation">sensory deprivation</a> is definitely worth-exploring. Think like: If you ditch sugar for a while, it tastes sweeter afterwards. ;-)</p> +<p>This is pretty much what floating offers: <strong>sensory starvation and you on your own</strong>. You may waste your time and never get to anything, or make even most out of that 1 hour than me.</p> +<p>Personally, I can’t wait to do nothing again.</p> +<hr /> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>Just another Autumn day in Berlin.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>Goethe (and Friedrich Schiller). <a href="https://archive.org/stream/correspondencebe01schi/correspondencebe01schi_djvu.txt">Correspondence Between Schiller and Goethe from 1794 to 1805</a>. Translated by George H. Calvert.</p> +</div> + + + + + How I Lock My Bike in Berlin + 2018-08-30T07:00:00+00:00 + 2018-08-30T07:00:00+00:00 + + + + + Unknown + + + + + + /blog/how-i-lock-my-bike-in-berlin/ + + <p class="summary">1 year with a bike in Berlin, and counting...</p> +<p>I bought a bike 2 months after moving to Berlin, and a really good lock 1 day after.</p> +<p>With no clue about the theft scene in Europe – Berlin, in special –, I did myself some research on <a href="https://www.reddit.com/r/reddit/">/r/berlin</a>, <a href="https://www.reddit.com/r/bicycling/">/r/bycicling</a> and a few other places around the internet. What I did find out? Well, <a href="https://www.welovecycling.com/wide/2015/11/25/european-bike-stealing-championships-in-numbers/">the numbers on bike theft are quite concerning</a>.</p> +<p>Nevertheless, after witnessing some people getting their bikes stolen, I feel privileged to say that <strong>it’s been more than 1 year I’ve got my bike</strong>. If that is because of my good lock or my good luck, I’ll never know.</p> +<p>But I can tell you about the lock.</p> +<h2 id="my-lock-setup">My lock setup</h2> +<p>I generally agree that you should invest as much as you can afford in your lock setup. I’ve put a considerable amount of money on mine because I <em>deeply</em> care – in other words, I have no psychological resilience when it comes to bicycles so losing mine would definitely get me in tears.</p> +<p class="note">If you care about numbers without any trustable source, I've seen recommended somewhere that you should be investing between 10%-20% of the bike price in a lock. đŸ€·</p> +<p>Therefore, considering the price of having to go home by feet and with tears in my eyes, I did the best I could and went for the <a href="https://www.kryptonitelock.com/en/products/product-information/current-key/000990.html">Kryptonite Evolution Mini-7 with Double Loop Cable</a> (highly recommend you to check their website for more information).</p> +<p>I make sure my bike’s <strong>frame and both wheels</strong> are locked to a fixed rack – cemented into the ground, ideally.</p> +<figure class="text-center"><picture><img src="../../media/2018/yellow-bike-lock.jpg" alt="Yellow bike in a parking space locked with a U-lock and a flexible steel cable."></picture> +<figcaption>My tiny yellow bike parked and properly locked at the office's parking space! Locking up the U-lock to the front wheel instead is a good alternative. Also, I often wrap the steel cable through the rack.</figcaption></figure> +<p class="note">I had considered the <a href="https://www.kryptonitelock.com/en/products/product-information/current-key/997986.html">Kryptnonite's New York Fahgettaboutdit</a>, but I found it way too heavy and the safety factor difference didn't pay off for me at that time. I'd recommend it if an extra weight is no problem for you though.</p> +<p>For I still have my bike after 1 year, I am honestly happy with my choice. The lock came with:</p> +<ul> +<li>Three keys with an unique number. For your information, Kryptonite has a system where <a href="https://kryptonite.zendesk.com/hc/en-us/articles/231011287-Finding-My-Key-Number-">every key gets a number</a>, so you can order replacements online in case you mess up.</li> +<li>A handy mount made by Kryptonite: <a href="https://www.kryptonitelock.com/en/products/product-information/current-key/000730.html">Transit FlexFrame U-Bracket</a> (not visible in the photo because it’s in the top tube), so I don’t have to carry the U-lock in my backpack or whatever.</li> +<li>Manuals that I didn’t read and got recycled.</li> +<li>1 year coverage according to the <a href="https://www.kryptonitelock.com/en/customer-service/register-for-anti-theft.html">Kryptonte’s Anti-theft Program</a>, because the security rating is high enough.</li> +</ul> +<p>I’ve read a couple complaints about the lock not fitting both the wheel and frame to most city racks, however I’ve managed to do it in most racks around Berlin. It’s definitely not the most flexible and spacious lock, but thieves would love some extra space to do their work too, so I think it’s just the size it should be after all.</p> +<p>In the worst-case scenario, there is always the <a href="https://www.sheldonbrown.com/lock-strategy.html">Sheldon Method lock strategy</a> – or <a href="http://www.802bikeguy.com/2011/07/the-modified-sheldon-brown-bike-locking-strategy/">its modified version</a> – anyway!</p> +<h2 id="what-bike-locks-are-about">What bike locks are about</h2> +<p>When looking for a lock, instead of (only) asking yourself what’s the best lock ever, ask <em>“How much trouble am I putting a thief into with my lock strategy?”</em>.</p> +<p>It hasn’t been enough stressed that locks do NOT prevent determined thieves with their lock pics, cable cutters, bolt cutters and angle grinders to steal you bike. Period.</p> +<p>Locks do, though, make it harder for thieves to <em>pick</em> your bike, by increasing the “risk” factor in the risk/reward calculation done before they attempt to steal.</p> +<p><strong>It’s all about making it harder</strong>. And how do you do that? By having a <em>diverse</em> lock setup, and, just as important: by being extremely careful on where and how to park.</p> +<p>Don’t think just U-lock: saddle locks, wheel locks might be worth-checking too! One awesome lock is just one at the end of the day, and the more tools the thief needs to carry out, the better.</p> +<h2 id="looking-further">Looking further</h2> +<p>Some articles I’ve read last year and that might be interesting if you own a bike and want to learn more on how to keep it safe.</p> +<ul> +<li><a href="https://thewirecutter.com/reviews/best-bike-lock/">Best Bike Lock</a>: Review of several bike locks and learnings on how to pick a good one.</li> +<li><a href="http://thebestbikelock.com/how-to-lock-your-bike/">How to Lock your Bike</a>: Great tips on where to park your bike and what to lock it to.</li> +</ul> +<p>There are a lot of cool videos out on YouTube too, e.g. <a href="https://www.youtube.com/watch?v=IXNASUSivqg">“How to Lock your Bike” from GCN</a>.</p> +<p>Have a nice ride! đŸšČ</p> + + + + + Working Better with Git for a Clear History + 2018-08-04T07:00:00+00:00 + 2018-08-04T07:00:00+00:00 + + + + + Unknown + + + + + + /blog/working-better-with-git-for-a-clear-history/ + + <p>Your teammate worked on a few improvements in all forms of the company’s website. At some point you, also a programmer, are asked for a code review.</p> +<p>This is the feature branch’s <strong>commit history</strong> you get in the Pull Request:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">[290xx26]</span><span> Resolve merge conflicts +</span><span style="color:#50fa7b;">[9efxxf2]</span><span> Refactor event listener for form fields +</span><span style="color:#50fa7b;">[5d9xx5a]</span><span> Update snapshots +</span><span style="color:#50fa7b;">[948xxfa]</span><span> Update dispatch event +</span><span style="color:#50fa7b;">[f5xxea1]</span><span> WIP +</span><span style="color:#50fa7b;">[f8xxaae]</span><span> Revert change +</span><span style="color:#50fa7b;">[49xxf55e]</span><span> Revert changes +</span><span style="color:#50fa7b;">[02xxdf1]</span><span> Update snapshots +</span><span style="color:#50fa7b;">[21xx329]</span><span> Pass down prop +</span><span style="color:#50fa7b;">[28xxa865]</span><span> Fix onChange event and add minimal design in form +</span><span style="color:#50fa7b;">[cfxx37c]</span><span> U[date snapshots +</span><span style="color:#50fa7b;">[cfxx36c]</span><span> Update form to handle onChange event for autofill +</span><span style="color:#50fa7b;">[242xx25]</span><span> Fix another bug with onChange +</span><span style="color:#50fa7b;">[f7xx738]</span><span> Update form component +</span><span style="color:#50fa7b;">[09xx868]</span><span> Update snapshots +</span></code></pre> +<p>It seems like a lot, when actually those improvements are simply 1) fixing a bug with event handling and 2) introducing a minimal style to them. It just that it takes time to visualise that.</p> +<p>Indeed, committing often to a branch is a good practice<sup class="footnote-reference"><a href="#1">1</a></sup> and commits are supposed to be low-level rather than huge. However, a commit is applicable when you have a meaningful, self-contained batch of work to log to the history – and updating Jest snapshots is not it.</p> +<p>How about the following history?</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">[9efxxf2]</span><span> Refactor event listener for form fields +</span><span style="color:#50fa7b;">[cfxx37c]</span><span> Add minimal design in form +</span><span style="color:#50fa7b;">[cfxx36c]</span><span> Update form to handle onChange event for autofill +</span></code></pre> +<p>That history communicates in a clear way <strong>what</strong> in the codebase has been changed in order to get the improvements done. If you want to know <strong>how</strong> it’s changed, it’s just a matter of checking out a particular commit.</p> +<h2 id="why-a-clear-history-matters">Why a clear history matters</h2> +<p>Apart from facilitating code reviews, since reviewers could grasp the context of the changes right at the first glimpse, <strong>a clear Git history is healthy for the project</strong>.</p> +<p>When commits started to reflect one’s workflow rather than the work done itself, the history turns into a mess of both meaningful and meaningless logs, hard to navigate through and undo changes (since commits are “checkpoints” of work). It’s highly likely that, as time goes by, developers will stop caring about the source code history as the powerful resource it is.</p> +<p>*<em>The final Git history should reflect <em>your work</em> not the way you worked.</em></p> +<p>You begin to lose the benefit of source code management with a messy history, which was supposed to reflect how the codebase evolved over time.</p> +<h2 id="a-better-relationship-with-git">A better relationship with Git</h2> +<p>There are very common comprehensible reasons – yet not excuses at all! – for developers to unnecessarily commit. I can think of:</p> +<ol> +<li>“I had to update snapshots/fix unit test/code formatting/a typo in something I introduced.”</li> +<li>“I had to merge master.”</li> +<li>“I wanted to save my work.”</li> +<li>“I don’t necessarily follow a clear flow – I am productive when I work in iterative way and usually do a lot of things at once.”</li> +</ol> +<p>They can all be worked out by developing a better relationship with Git itself. That might take a while at first, but when it’s part of your daily workflow, you barely think about it at all. <em>(I promise!)</em></p> +<h3 id="first-let-s-talk-git-rebasing">First, let’s talk Git rebasing</h3> +<p><a href="https://git-scm.com/docs/git-rebase">Git rebase</a> is a very powerful tool to reorganise your commits. It does a lot, so I won’t get deep into it.</p> +<p>The command <code>git rebase</code> has an important tool you should get comfortable with: <strong>interactive rebase</strong>. Let’s say we want to reorganise the latest 3 commits:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> rebase</span><span style="font-style:italic;color:#ffb86c;"> --interactive</span><span> HEAD</span><span style="color:#bd93f9;">~</span><span>3 +</span></code></pre> +<p class="note"><code>HEAD</code> points to the current branch in your Git repository. You can use @ as an alias as well: <code>@~3</code>, or the commit hash.</p> +<p>Interactive rebase will provide you a text interface with the list of the commits (in this case, within the range <code>HEAD~3..HEAD</code>) that are about to be rebased and actions you can apply to them:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>242xx25</span><span style="color:#ff79c6;">]</span><span> Fix another bug with onChange +</span><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>f7xx738</span><span style="color:#ff79c6;">]</span><span> Update form component +</span><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>09xx868</span><span style="color:#ff79c6;">]</span><span> Update snapshots +</span><span> +</span><span style="color:#6272a4;"># Rebase 242xx25..09xx868 onto 242xx25 +</span><span style="color:#6272a4;"># +</span><span style="color:#6272a4;"># Commands: +</span><span style="color:#6272a4;"># p, pick = use commit +</span><span style="color:#6272a4;"># r, reword = use commit, but edit the commit message +</span><span style="color:#6272a4;"># e, edit = use commit, but stop for amending +</span><span style="color:#6272a4;"># s, squash = use commit, but meld into previous commit +</span><span style="color:#6272a4;"># f, fixup = like &quot;squash&quot;, but discard this commit&#39;s log message +</span><span style="color:#6272a4;"># x, exec = run command (the rest of the line) using shell +</span><span style="color:#6272a4;"># +</span><span style="color:#6272a4;"># These lines can be re-ordered; they are executed from top to bottom. +</span><span style="color:#6272a4;"># +</span><span style="color:#6272a4;"># If you remove a line here THAT COMMIT WILL BE LOST. +</span><span style="color:#6272a4;"># +</span><span style="color:#6272a4;"># However, if you remove everything, the rebase will be aborted. +</span><span style="color:#6272a4;"># +</span><span style="color:#6272a4;"># Note that empty commits are commented out +</span></code></pre> +<p class="note"><code>pick</code> just means that commit is included. It's the default.</p> +<p>Editing that file (either by applying actions to commits or reordering them) and closing it will reapply those commits to the branch. We’ll explore some scenarios where that is useful.</p> +<h3 id="rebase-instead-of-merge">Rebase instead of merge</h3> +<p>The branch that you branched from has been updated (let’s call it <code>master</code>), so you need to fetch latest changes and merge that into yours with <code>git pull</code>. Instead of merging and introducing an ugly new commit for that, you can rebase and pretend that nothing ever happened in the first place.</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> pull origin master</span><span style="font-style:italic;color:#ffb86c;"> --rebase +</span></code></pre> +<p class="note">"Why isn't that the default then?", you might ask. I'd guess they didn't want to make a feature that rewrites history part of the default behaviour.</p> +<h3 id="squash-commits-when-you-can">Squash commits when you can</h3> +<p>You need to fix a typo, update a test, or include anything else that should have actually been part of a commit previously introduced. You can create a new commit and later squash it to the initial one with rebase.</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> commit</span><span style="font-style:italic;color:#ffb86c;"> -m </span><span style="color:#f1fa8c;">&quot;Update contact form tests&quot; +</span><span style="color:#50fa7b;">git</span><span> rebase</span><span style="font-style:italic;color:#ffb86c;"> -i</span><span> HEAD</span><span style="color:#bd93f9;">~</span><span>2 </span><span style="color:#6272a4;"># act on top of latest 2 commits +</span></code></pre> +<p>Interactive rebase will show up, and you can mark that “Update contact form tests” as the commit to be squashed into a previous one by changing pick to <code>s</code> (squash).</p> +<p>The squashed commit has to come exactly before the commit you want to squash into, so you might have to some reordering.</p> +<h4 id="fix-up-and-save-time">Fix up and save time</h4> +<p>Using the <code>--fixup</code> flag along with the commit hash of the previous commit will <strong>mark a commit as a fix of an existing one</strong>. Then, when you rebase with <code>--autosquash</code>, they will
 well, automatically get squashed.</p> +<p>Let’s say we have fixed a typo in the commit <code>i2r923</code>:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> commit</span><span style="font-style:italic;color:#ffb86c;"> --fixup</span><span> i2r923 +</span><span style="color:#50fa7b;">git</span><span> rebase</span><span style="font-style:italic;color:#ffb86c;"> --autosquash</span><span> 9ef00f2 </span><span style="color:#6272a4;"># one commit before above +</span></code></pre> +<p class="note">You can configure Git to use the <code>--autosquash</code> flag by default when rebasing. I do that so you can check <a href="https://github.com/diessica/dotfiles/blob/master/git/config">my dotfiles</a> if you're curious.</p> +<p>Quite often, you’ll know how far you’re traveling from the current commit (HEAD). Instead of specifying hashes, you can just use <code>HEAD</code> as a reference to previous commits:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> commit</span><span style="font-style:italic;color:#ffb86c;"> --fixup</span><span> HEAD </span><span style="color:#6272a4;"># fix 1 commit before HEAD +</span><span style="color:#50fa7b;">git</span><span> rebase</span><span style="font-style:italic;color:#ffb86c;"> --autosquash -i</span><span> HEAD</span><span style="color:#bd93f9;">~</span><span>1 </span><span style="color:#6272a4;"># squash latest 2 commits +</span></code></pre> +<h3 id="stash-to-save-your-work-in-progress">Stash to save your work in progress</h3> +<p>You want to check or change other branch’s files, but don’t want to commit unfinished work either. You can <strong>stash your work in progress</strong> (“WIP”):</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> stash +</span></code></pre> +<p>That stores everything from your working directory into stash. It’s so useful in my day-to-day work that I honestly often cry using it.</p> +<p>On how to get your work back, name your WIPs, or stash specific files, refer to the <a href="https://git-scm.com/book/en/v1/Git-Tools-Stashing">docs on Git staging</a>. No way I am better at explaining than the documentation itself!</p> +<h3 id="commit-selected-chunks-of-your-work">Commit selected chunks of your work</h3> +<p>Remember the “I work in a very messy way, iterating between features” excuse? This helps. (It helped me yesterday when I refactored and introduced something new to it – should not be done altogether! –  at the same time without noticing.)</p> +<p>Besides only adding a specific file to your commit with <code>git add</code>, you may want to add only a <strong>chunk of the file’s code</strong> to a commit. That can be achieved with the <code>--patch</code> flag:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> add</span><span style="font-style:italic;color:#ffb86c;"> --patch +</span></code></pre> +<p>That’s another interface you’ll have to get comfortable with. You can also try out its <code>--interactive</code> option.</p> +<h4 id="using-vs-code">Using VS Code?</h4> +<p>VS Code has a powerful built-in Git editor that allows you to add chunks of code to a commit. To stage specific lines to commit later, open VS Code’s Git editor, select the lines of code you feel should go into a commit, and “Stage selected changes” by right-clicking on it.</p> +<figure class="text-center"><picture><img src="../../media/2018/vs-code-stage-selected-changes.png" alt="Showing how to use 'Stage Selected Changes' in VS Code"></picture> +<figcaption>Changed the whole thing but want to commit only a chunk of it? VS Code has got you covered.</figcaption></figure> +<p>The <a href="https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette">Command Palette</a> also has a “Git: Stage selected changes” option.</p> +<h3 id="rename-commit-messages-for-meaning">Rename commit messages for meaning</h3> +<p>You had a look at the final history and found out your commit messages need some love. To change your latest commit (HEAD), you can just do <code>git commit --amend</code>; for other commits, you’ll have to rebase.</p> +<p>Let’s say you want to fix the latest 5 commits:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> rebase</span><span style="font-style:italic;color:#ffb86c;"> -i</span><span> @</span><span style="color:#bd93f9;">~</span><span>5 +</span></code></pre> +<p>That will open up the <strong>interactive rebase</strong> you’re already familiar with. Find the commit you want, change pick to <code>e</code> (edit), and save and close the file; after Git rewinds to that commit, edit its message with <code>git commit --amend</code>, and run <code>git rebase --continue</code> when you’re done.</p> +<h2 id="got-a-clear-history-push-it">Got a clear history? Push it!</h2> +<blockquote> +<p>Commit Often, Perfect Later, Publish Once.<sup class="footnote-reference"><a href="#1">1</a></sup></p> +</blockquote> +<p>Make sure that your branch has got a clear, readable and meaningful history
</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> log</span><span style="font-style:italic;color:#ffb86c;"> --oneline +</span></code></pre> +<p>Then push it into the remote repository!</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> push origin head +</span></code></pre> +<p class="note"> If you have already pushed (Y THO???!), you can (carefully) use the force option (<code>-f</code>) to rewrite the remote history.</p> +<h2 id="extra-fixing-the-first-history">Extra: Fixing the first history</h2> +<p>Remember the first history? We can fix it. It’s definitely harder to change it after it’s done, but totally doable with <code>rebase -i</code>. A possible solution would be:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>290xx26</span><span style="color:#ff79c6;">]</span><span> Resolve merge conflicts +</span><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>9efxxf2</span><span style="color:#ff79c6;">]</span><span> Refactor event listener for form fields +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>5d9xx5a</span><span style="color:#ff79c6;">]</span><span> Update snapshots +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>948xxfa</span><span style="color:#ff79c6;">]</span><span> Update dispatch event +</span><span style="color:#50fa7b;">delete </span><span style="color:#ff79c6;">[</span><span>f5xxea1</span><span style="color:#ff79c6;">]</span><span> WIP +</span><span style="color:#50fa7b;">delete </span><span style="color:#ff79c6;">[</span><span>f8xxaae</span><span style="color:#ff79c6;">]</span><span> Revert change +</span><span style="color:#50fa7b;">delete </span><span style="color:#ff79c6;">[</span><span>49xxf55e</span><span style="color:#ff79c6;">]</span><span> Revert changes +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>02xxdf1</span><span style="color:#ff79c6;">]</span><span> Update snapshots +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>21xx329</span><span style="color:#ff79c6;">]</span><span> Pass down prop +</span><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>28xxa865</span><span style="color:#ff79c6;">]</span><span> Fix onChange event and add minimal design in form +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>cfxx37c</span><span style="color:#ff79c6;">]</span><span> U[date snapshots +</span><span style="color:#50fa7b;">pick </span><span style="color:#ff79c6;">[</span><span>cfxx36c</span><span style="color:#ff79c6;">]</span><span> Update form to handle onChange event for autofill +</span><span style="color:#50fa7b;">fixup </span><span style="color:#ff79c6;">[</span><span>242xx25</span><span style="color:#ff79c6;">]</span><span> Fix another bug with onChange +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>f7xx738</span><span style="color:#ff79c6;">]</span><span> Update form component +</span><span style="color:#50fa7b;">squash </span><span style="color:#ff79c6;">[</span><span>09xx868</span><span style="color:#ff79c6;">]</span><span> Update snapshots +</span></code></pre> +<p><strong>Be mindful about your decisions and make sure you are not losing work along the way</strong>. I deleted commits unused commits (WIP then reverted), squashed “fix” and “update tests” commits, and then picked only those that are meaningful batches of work.</p> +<p>I could have also split <code>Fix onChange event and add minimal design in form</code> into two separate commits
 But that’s for a future post.</p> +<h2 id="final-considerations">Final considerations</h2> +<p>Nowadays, I can say for sure that Git helps me to work better. Those techniques you’ve learned are all part of my daily workflow.</p> +<p>There is always something I don’t know about Git though, so I keep exploring. I recommend you do to do the same, and you can start right from your command line:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">git</span><span> help</span><span style="font-style:italic;color:#ffb86c;"> -w</span><span> reset +</span></code></pre> +<p>Finally, if somehow you don’t feel comfortable with moving around your work from the command line, I’d recommend Git GUI clients<sup class="footnote-reference"><a href="#2">2</a></sup> – they are powerful and simplify visualising branches and its commits, especially when it gets tough<sup class="footnote-reference"><a href="#3">3</a></sup>.</p> +<p>I hope you have better, more sane, work days after that!</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p><a href="http://sethrobertson.github.io/GitBestPractices/">Commit Often, Perfect Later, Publish Once: Git Best Practices</a> by Seth Robertson.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>Some clients I can think of: <a href="https://desktop.github.com/">GitHub’s Git client</a> (free), <a href="https://www.gitkraken.com/">Git Kraken</a> (free), <a href="https://www.git-tower.com/">Git Tower</a> (paid).</p> +</div> +<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup> +<p>It will get tough, because source code management is not easy. Anyhow, it’s always tougher when you care about things anyway. Easiest thing is not to care about anything at all.</p> +</div> + + + + + Computer and Human Languages + 2018-06-20T18:06:00+00:00 + 2018-06-20T18:06:00+00:00 + + + + + Unknown + + + + + + /blog/computer-and-human-languages/ + + <p class="note">Basic knowledge of computer languages (mainly JavaScript) is assumed.</p> +<p>Some time ago, a friend of mine asked how skilled I’d say I was with JavaScript. I told him I was <em>fluent</em>.</p> +<p>– <em>Fluent? What does it mean to be fluent?</em></p> +<p>– <em>Well, think Portuguese.</em> – We both speak Portuguese — <em>I don’t know every word, but I do know the language enough to express anything I need somehow.</em></p> +<p>It turned out that “fluent” was just the perfect word.</p> +<hr /> +<p>Fluency is a powerful and straightforward concept to express your ability with a language. When it comes to <strong>human languages</strong>, it’s the ability to fully communicate your intentions to a human; for <strong>computer languages</strong>, the ability to fully communicate your intentions to a computer.</p> +<p>That line of thought is shared in one of the most important and revolutionary introductory books to Computer Science. In <em>Structure and Interpretation of Computer Programs</em>, right before introducing Lisp (the programming language used throughout the book) a similar analogy is made:</p> +<blockquote> +<p>Just as our everyday thoughts are usually expressed in our natural language (such as English, French, or Japanese), and descriptions of quantitative phenomena are expressed with mathematical notations, our procedural thoughts will be expressed in Lisp. <sup class="footnote-reference"><a href="#1">1</a></sup></p> +</blockquote> +<p>For both kinds of languages, the levels are the same: one <em>cannot</em> communicate; <em>can poorly</em> do it (beginner); <em>can</em> do it (native/fluent), or <em>can brilliantly</em> do it (think book authors, public speakers, and Software Engineers in a senior level).</p> +<h2 id="why-do-they-match-so-well">Why do they match so well?</h2> +<p>They match because the linguistics of computer and natural languages wonderfully intersect. Both consist of <strong>syntax</strong>, <strong>semantics</strong> and <strong>pragmatics</strong> functions, found in the core of theoretical linguistics.</p> +<p>In their ecosystem, we can also find <strong>syntax trees</strong> and different <strong>style guides</strong>.</p> +<h3 id="syntax">Syntax</h3> +<p><strong>Syntax</strong> is the set of rules that govern how language elements are combined to form a valid expression.</p> +<p>In English, the basic rule is that elements like nouns, verbs and punctuation marks must follow the <a href="https://en.m.wikipedia.org/wiki/Subject%E2%80%93verb%E2%80%93object">subject-verb-object order</a> to produce a valid sentence. In JavaScript, a programming language, to produce a valid conditional statement, elements such as <code>if</code>, parenthesis, braces, comparison operators (<code>===</code>, <code>&lt;=</code> ) must be combined in a certain order too.</p> +<p>In the same way that “Do they car a put?” (??) is not valid English, the following code is not valid JavaScript:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">if </span><span>{</span><span style="color:#bd93f9;">1 </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">2</span><span>} ( +</span><span> </span><span style="color:#ffffff;">return </span><span style="color:#bd93f9;">true +</span><span>) +</span><span style="color:#6272a4;">// =&gt; SyntaxError: missing ( before condition +</span><span> +</span><span style="color:#ffffff;">add x y </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">x </span><span style="color:#ff79c6;">+ </span><span style="color:#ffffff;">y </span><span style="color:#6272a4;">// u can&#39;t use elm&#39;s lambda syntax on js, no +</span></code></pre> +<p class="note">And just like a pedant friend would do when you write shitty English, the computer will throw a syntax error when running your program. Forgot closing a brace? Wrote an <code>if</code> statement condition using curly braces instead of parenthesis? Well, <code>SyntaxError</code>!</p> +<p>This, however, is valid JavaScript:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#bd93f9;">1 </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">2</span><span>) { +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#bd93f9;">true +</span><span>} </span><span style="color:#6272a4;">// &quot;if (1 === 2) return true&quot; is also fine! +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">add </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">x</span><span>, </span><span style="font-style:italic;color:#ffb86c;">y</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">x </span><span style="color:#ff79c6;">+ </span><span style="color:#ffffff;">y +</span></code></pre> +<p>In HTML there are syntax rules too. Adding a <code>div</code> inside <code>ul</code>, for instance, is invalid. An unordered list in HTML (<code>ul</code>) only allows list items as children, such as <code>li</code> – and <code>div</code> is not one.</p> +<p>Languages have different degrees of syntax strictness, which is what usually makes some harder to grasp than others. Think the <strong>German language</strong> – German imposes very strict rules for articles: they may vary in number, gender, and function. English, on the other hand, has a definite (the) and an indefinite article (a/an) – and that’s it.</p> +<p>The same applies to computer languages: some happen to be extremely strict when it comes to syntax, while others are designed for greater syntactic flexibility, letting you achieve the same result in different ways. Think <strong>semicolons</strong>: they are optional when ending statements in JavaScript, but mandatory in C.</p> +<h3 id="semantics">Semantics</h3> +<p><strong>Semantics</strong> is what the language expression evaluates to. In human languages, expressions evaluate to thoughts, questions, answers; while computers evaluate expressions to CPU instructions that comprise a program’s flow.</p> +<p>Consider the following English statement:</p> +<blockquote> +<p>The ant ran over the car.</p> +</blockquote> +<p>I don’t know what ants you are familiar with, but even though the sentence contains the necessary elements in correct order and grammar, that doesn’t make sense. The statement is <strong>syntactically correct</strong> but <strong>semantically wrong</strong> – we can’t conceive a meaning from it.</p> +<p>(<em>“The car ran over the ant”</em>, however, would be definitely more acceptable to our ears.)</p> +<p>We can relate semantics to computer languages in several ways (like “solving the wrong problem”, basically), but the “semantic” word bubbles up more often when we think about HTML. Consider the following markup:</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">span</span><span>&gt;What is a fruit?&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> A fruit is something that humans eat. Some examples of fruits are: +</span><span> watermelon, pineapple and apples. +</span><span>&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span></code></pre> +<p>The elements <code>span</code> and <code>div</code> do exist in the language and are validly marked in this case (I didn’t do <code>&gt;div&lt;</code>, right?), so the browser will understand and show it accordingly to the user. The syntax is correct; yet, <code>span</code> and <code>divs</code> are non-semantic elements, so computers won’t get any meaning from it. Again, <strong>syntactically correct</strong> but <strong>semantically wrong</strong>.</p> +<p>That text, though, is clearly a title and a paragraph. With a bit of HTML knowledge, we can communicate this in a meaningful way to computers! The language provides elements to achieve that.</p> +<p>The following code improves the previous markup for better semantics.</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">h1</span><span>&gt;What is a fruit?&lt;/</span><span style="color:#ff79c6;">h1</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> A fruit is something that humans eat. Some examples of fruits are: +</span><span> watermelon, pineapple and apples. +</span><span>&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span></code></pre> +<p>The element <code>h1</code> is being used to communicate the main title, and <code>p</code> communicates the paragraph. Both syntax and semantics make sense now!</p> +<h3 id="pragmatics">Pragmatics</h3> +<p><strong>Pragmatics</strong> is what the language expression evaluates to within its interactional context – which might totally affect semantics and syntax.</p> +<p>In a natural language, the context is essentially built around the cultural aspects of the speaker, place, time, manner, and several others unpredictable aspects that humans introduce when communicating.</p> +<p>For computer languages, we can see pragmatics as the methodology or implementation used when approaching a problem: composition vs. inheritance, functional vs. imperative, picking a Design Pattern etc.</p> +<p>Consider the following examples:</p> +<ul> +<li>A child saying that the food is horrible to a beginner that started cooking just recently.</li> +<li>A new joiner in the company filters items in an JavaScript array using <code>forEach</code>, but the team expected <code>filter</code> to be used – a more functional approach.</li> +<li>A programmer implements Fibonacci with recursion instead of iteration.</li> +<li>Your friend uses a very erudite language to add a cake recipe on the internet.</li> +</ul> +<p>What do they all have in common? By themselves, they are neither right or wrong – <em>unless</em> you consider the context in which they were approached in.</p> +<p>Having either syntax or semantic skills won’t help you understand what’s wrong, since pragmatics is more about what’s <strong>appropriate</strong> within a context. Some approaches are more elegant, antiquated, or dialect-based than others, and we can only tell how valid they are considering what we are trying to achieve.</p> +<h3 id="syntax-trees">Syntax trees</h3> +<p>Both kinds of languages can be represented using syntax trees, a concept that reuses the mathematical concept of <a href="https://en.m.wikipedia.org/wiki/Partially_ordered_set">partially ordered sets</a>.</p> +<p>Human languages are analysed through the Concrete Syntax Tree (“CST”), a context-free analysis that tells us about the function of each language token (word, punctuation etc) used.</p> +<p>This is the Concrete Syntax Tree for the previous sentence, <em>“The water drank a glass of Mary.”</em>:</p> +<figure class="text-center"><picture><img src="../../media/2018/mary-glass-syntax-tree.png" alt="Concrete Syntax Tree of the sentence 'The water drank a glass of Mary.'"></picture> +<figcaption>Concrete Syntax Tree for a sentence in a human language, where "S" stands for "sentence", "N" for "noun", "V" for "verb", and P for "phrase". See <a href="https://en.m.wikipedia.org/wiki/Parse_tree">Wikipedia on Parse Trees</a> for more information.</figcaption></figure> +<p>Computer languages are also represented using syntax trees! When the code (high-level) gets translated into instructions for the computer (low-level), a program called <em>compiler</em> make uses of them. The Concrete Syntax Trees for a program contains a lot of detailed information, from whitespaces to language expressions, so you can imagine a CST for a real-world JavaScript program as something really lengthy.</p> +<p class="note">What compilers do might be tough to understand at first, but think of this program inside us that converts languages to meaning – our <b>internal <i>compiler</i></b>. Kids improve their compilers while communicating with their families, so every day they get to understand their mother language even more. If you understand English yet struggle with German, we can say your <i>German compiler is pretty bad and has to be improved</i>.</p> +<p>The compiler simplifies the CST down to the expressions that truly represent the program after syntax analysis. That’s where the <strong>Abstract Syntax Tree</strong> (AST) comes in: the syntax tree that actually lies at the heart of semantic definitions!</p> +<p>Let’s consider the following JavaScript program:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">x </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">0 +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">x</span><span>) { +</span><span> </span><span style="color:#ffffff;">x</span><span style="color:#ff79c6;">++ +</span><span>} +</span></code></pre> +<p>This is the Abstract Syntax Tree for it:</p> +<figure class="text-center"><picture><img width="400" src="../../media/2018/abstract-syntax-tree.png" alt="Concrete Syntax Tree of the sentence 'The water drank a glass of Mary.'"></picture> +<figcaption>Abstract Syntax Tree for a JavaScript program.</figcaption></figure> +<p>It’s really about the essentials when considering language grammar. If a whitespace means nothing in a language, that won’t show up in the AST.</p> +<p>Compare that against <a href="https://raw.githubusercontent.com/cst/cst/master/docs/cst-example.png">a Concrete Syntax Tree for another program of similar size</a>, which is way more detailed, and therefore more useful in a language-specification level.</p> +<h3 id="style-guides">Style guides</h3> +<p>When the same expression can be written in several ways because the language is not strict enough about it, style guides aim to answer the question of <strong>which style to go for</strong>. Curiously, style guides of writing are just as useful for programmers as they are for journalists!</p> +<p>Let’s say I’m telling someone my favourite fruits. I could do it in different ways:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ffffff;">My favourite fruits are watermelon</span><span>, </span><span style="color:#ffffff;">bananas and strawberries</span><span style="color:#ff79c6;">. +</span><span> +</span><span style="color:#6272a4;">// or using the Oxford comma +</span><span style="color:#ffffff;">My favourite fruits are watermelon</span><span>, </span><span style="color:#ffffff;">bananas</span><span>, </span><span style="color:#ffffff;">and strawberries</span><span style="color:#ff79c6;">. +</span></code></pre> +<p class="note">The Oxford comma comes from the <a href="https://www.ox.ac.uk/sites/files/oxford/media_wysiwyg/University%20of%20Oxford%20Style%20Guide.pdf">Oxford Style Guide</a>.</p> +<p>In JavaScript, you can write a <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects">JavaScript object</a> in different ways too:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">hero </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> firstName: </span><span style="color:#f1fa8c;">&quot;Ada&quot;</span><span>, +</span><span> lastName: </span><span style="color:#f1fa8c;">&quot;Lovelace&quot;</span><span>, +</span><span> birthYear: </span><span style="color:#bd93f9;">1815</span><span>, +</span><span> superPower: </span><span style="color:#f1fa8c;">&quot;computers&quot;</span><span>, +</span><span>} +</span><span> +</span><span style="color:#6272a4;">// or comma-first style +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">hero </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> firstName: </span><span style="color:#f1fa8c;">&quot;Ada&quot;</span><span>, +</span><span> lastName: </span><span style="color:#f1fa8c;">&quot;Lovelace&quot;</span><span>, +</span><span> birthYear: </span><span style="color:#bd93f9;">1815</span><span>, +</span><span> superPower: </span><span style="color:#f1fa8c;">&quot;computers&quot;</span><span>, +</span><span>} +</span></code></pre> +<p>Either way, <strong>there’s no definite rule</strong>. They mean the same, only changing their style of writing.</p> +<p>Some examples of style guides are <a href="https://github.com/airbnb/javascript">Airbnb’s Style guide</a>, for writing JavaScript; and <a href="http://www.chicagomanualofstyle.org/home.html">Chicago style guide</a>, for general writing.</p> +<h2 id="where-they-don-t-match">Where they don’t match</h2> +<blockquote> +<p>The programmer, like the poet, works only slightly removed from pure thought-stuff. He builds his castles in the air, from air, creating by exertion of the imagination. [
] Yet the program construct, unlike the poet’s words, is real in the sense that it moves and works, producing visible outputs separately from the construct itself. It prints results, draws pictures, produces sounds, moves arms. <sup class="footnote-reference"><a href="#2">2</a></sup></p> +</blockquote> +<p>Even with all the similarities, programming languages are still artificial, while human languages are natural. Computers are rigorous, won’t allow you to be ambiguous, and only get what you mean if you put it the right way.</p> +<p>You won’t have filler words in a computer language, because computers don’t benefit from your thought process. Humans do benefit, though, and I’d even say that those communication imperfections is what connects us to others.</p> +<p>Apart from that, <strong>a programming language is an interface between you and a computer, while a natural language is an interface between you and another human being.</strong> You are communicating to a computer, but as a human – and you probably won’t be the only one doing it.</p> +<p>Writing in a way that’s meaningful for both is therefore part of the writing process – and probably the most demanding one.</p> +<h2 id="final-thoughts">Final thoughts</h2> +<p>Just like experienced programmers look at documentation and easily apply language features to create pieces of software, fluent English speakers would look at the dictionary and easily come up with phrases.</p> +<p>Because both computer and natural languages share linguistic structures, speaking about programming skills in terms of fluency works just as well.</p> +<p>After all, fluency is all about how easily our intentions are expressed with a language.</p> +<hr /> +<p class="note">As a next reading, I'd highly recommend <a href="https://medium.freecodecamp.org/exploring-the-linguistics-behind-regular-expressions-596fab41146">Exploring the Linguistics Behind Regular Expressions</a> if you are interested in the linguistics of computer languages.</p> +<hr /> +<p><a href="https://www.reddit.com/r/compsci/comments/8t413x/computer_and_human_languages_the_linguistics_of/">Follow the discussion thread on Reddit</a></p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>“Programming in Lisp” in <em>“Structure and Interpretation of Computer Programs”</em>, 1979.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>Fred Brooks. <em>“The Mythical Man-Month: Essays on Software Engineering”</em>, 1975, page 7.</p> +</div> + + + + + React and Form Management: Is Redux Form Worth It? + 2018-05-21T18:14:00+00:00 + 2018-05-21T18:14:00+00:00 + + + + + Unknown + + + + + + /blog/react-and-form-management-is-redux-form-worth-it/ + + <p class="note">This is an improvement over my answer to a question in a Brazilian forum: "<a href="https://github.com/frontendbr/forum/issues/929">is using Redux for forms worth it?</a>", in Portuguese. It assumes previous knowledge with React and Redux, and also mentions <a href="https://redux-form.com/">Redux Form</a>, a library for managing forms in React.</p> +<p>It depends.</p> +<p>I know “it depends” is far from an interesting answer, yet that’s the perfect-generic answer to any <em>“is using X worth it?”</em> question. It really depends, yes, but more often you don’t need that.</p> +<p>Last year I picked Redux Form to build a multi-step form wizard, each step containing different forms, with its own fields and validations (some of them asynchronous!). In the end, all forms would be merged into one JavaScript object to be sent at some point.</p> +<p>So, I’d like to share my experiences and hopefully help you to figure it out what your problem is, and help you to decide by telling you how I’ve solved mine.</p> +<h2 id="where-redux-form-thrives">Where Redux Form thrives</h2> +<p><a href="https://redux-form.com/">Redux Form</a> is useful for larger and more complex forms where <strong>ease of development</strong>, <strong>high control</strong> (especially), <strong>consistency</strong>, and <strong>persistence</strong> (especially) are required. There are advantages from:</p> +<ol> +<li>the state form being in the Redux store, and</li> +<li>Redux Form’s abstraction itself.</li> +</ol> +<p>Which are two different things. You might need both, just one, or none at all.</p> +<h3 id="ease-of-development">Ease of development</h3> +<p>Considering you are using <a href="https://redux-form.com/7.3.0/docs/api/field.md/">Redux Form’s Field</a> and wrap your form in its <a href="https://redux-form.com/7.3.0/docs/api/reduxform.md/">higher-order component</a> – you’re done. Your form will work out of the box.</p> +<p class="note">Yes, you could also get to build forms in a productive way with only React, but I think it's still worth-mentioning that Redux Form makes it really painless.</p> +<h3 id="high-control">High control</h3> +<p>You can manipulate forms from anywhere in the application: you trigger Redux actions provided by Redux Form and that’s all. No need to create your own Redux reducers and actions.</p> +<p>Redux Form is also flexible on what can be an input. <strong>Anything works as a field</strong>: custom 3rd-party inputs, a regular HTML input, a fancy select component without any standard form element at all
 Just pass the right props to it.</p> +<p>You can set up validation at the form and field level, supporting either synchronous or asynchronous validation. The errors triggered are also in the store – which makes it sweet to give useful feedbacks for users from anywhere, and also to debug! 👌</p> +<h3 id="consistency">Consistency</h3> +<p>All forms have the same data structure so you’d have the exact same information for every form and its fields, such as field values, field/form validity and further information (is the field touched? Pristine? Dirty?) in the Redux store.</p> +<p>Of course you can build forms consistently just by using React itself, but using Redux Form definitely enforces it.</p> +<h3 id="persistence">Persistence</h3> +<p>Since the state is already in the Redux store, Redux Form is easily pluggable with tools from the ecosystem.</p> +<p>Let’s say you want to save drafts from user’s inputs so people can finish and submit the form later. Redux Form + <a href="https://github.com/rt2zz/redux-persist">redux-persist</a> make it pretty easy: the rehydrate process in the Redux store autofills the UI like magic!</p> +<h2 id="where-redux-form-might-die">Where Redux Form might die</h2> +<p class="note">In the thread, someone mentioned the article <a href="https://matwrites.com/redux-form-is-dead/">Redux Form is dead.</a> <b>TL;DR</b>: It's not fucking dead, as any library, framework and whatsoever that has an "X is dead" post for it.</p> +<p>Let’s not forget that the JavaScript community is flooded with “X is dead” articles for everything in the ecosystem. That post, in particular, mentions valid points to consider such as ephemerality of the state (quoting Dan Abramov), performance issues within Redux Form, and the project maintenance/activity. I will go through them a bit.</p> +<h3 id="form-data-in-the-redux-store">Form data in the Redux store</h3> +<p><a href="https://twitter.com/dan_abramov">Dan Abramov</a>, creator of Redux, <a href="https://github.com/reduxjs/redux/issues/1287#issuecomment-175351978">said</a>: <em>“Use React for ephemeral state that doesn’t matter to the app globally and doesn’t mutate in complex ways. For example, a toggle in some UI element, a form input state. [
]”.</em></p> +<p>Which is completely accurate. Where your state should live in your app depends entirely on its <strong>ephemerality</strong> – how trivial it is for the application as a whole when it comes to reading, updating it and so on.</p> +<p>In the post, that quote is used to support the claim that Redux Form fucks up when stores all form data in the Redux store by default – a <strong>pretty bold design decision</strong> for sure.</p> +<p>However, Dan did not write that in stone – he never does and he’s clear about it. That should serve as an encouragement for developers to think better about where your application’s states should go into. So, yes, you should think twice – and that doesn’t kill Redux Form.</p> +<p>The state of a form wizard, whose input data persists until the end of the steps (in a session or local level, for instance), whose inputs may trigger UI changes, whose inputs gets touched and changed by external components, it’s definitely <strong>not as ephemeral as the state of a newsletter sign up or a contact form</strong>. In the former, the form state is important for the whole application. Just notice that’s a very specific case.</p> +<h3 id="performance-issues">Performance issues</h3> +<p>Redux Form has reached a well-optimised (see <a href="https://github.com/erikras/redux-form/issues/529">redux-form #529</a> and <a href="https://github.com/erikras/redux-form/issues/1405">redux-form #1405</a>) state.</p> +<p>When it comes to performance, though, you should never rest easy anyway. If you measure and find that your forms are slow, you should find bottlenecks and optimise from that.</p> +<h3 id="project-activity">Project activity</h3> +<p>Regarding the project activity, it is something to consider when deciding, and should always be. Is it active? Are there people maintaining it? Can YOU help to maintain it?</p> +<p>Yes, Erik (the author) has recently started working on another solution called <a href="https://github.com/final-form/final-form">Final Form</a>, which moves the form state out of the Redux store. However, Redux Form is mature, still well maintained (<a href="https://github.com/erikras/redux-form">check GitHub</a>, and he even said it himself <a href="https://www.reddit.com/r/reactjs/comments/7fukt7/introducing_react_final_form_high_performance/dqf8lw1/?utm_content=permalink&amp;utm_medium=front&amp;utm_source=reddit&amp;utm_name=reactjs">on Reddit</a>), and its documentation is great.</p> +<h2 id="final-words">Final words</h2> +<p>Only if the state of your form is non-trivial enough to live in the Redux store, I’d give it a chance for Redux Form, <strong>especially</strong> if you are considering making your own solution. Redux Form has suffered and evolved a lot and nowadays it has a very stable and mature API you can count on, I’d say.</p> +<p>Other React form management solutions you should definitely be looking at are <a href="https://github.com/jaredpalmer/formik">Formik</a> and <a href="https://github.com/final-form/react-final-form">react-final-form</a>, by Redux Form’s author. They don’t rely on Redux for state management and are most likely what you need now – or not.</p> +<p>The price is the abstraction, of course, it always is. 🙄 However, their everyday API is indeed minimal though, just be prepared to go through the documentation when you need to achieve specific stuff. In return, don’t forget you’ll get a consistent and solid structure to build forms upon.</p> +<p>Have fun building forms! 🎉</p> + + + + + T. T. T. + 2018-04-01T23:36:00+00:00 + 2018-04-01T23:36:00+00:00 + + + + + Unknown + + + + + + /blog/ttt/ + + <i> +Put up in a place<br /> +where it's easy to see<br /> +the cryptic admonishment<br /> +&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T. T. T.<br /> +<p>When you feel how depressingly<br /> +slowly you climb,<br /> +it’s well to remember that<br /> +      Things Take Time. +</i></p> +<p>Piet Hein</p> + + + + + Writing Mode in VS Code + 2018-02-28T02:30:00+00:00 + 2018-02-28T02:30:00+00:00 + + + + + Unknown + + + + + + /blog/writing-mode-in-vs-code/ + + <p>I’m a big fan of writing. I’m also a big fan of using my <strong>code editor</strong> and <strong>Markdown</strong> for that!</p> +<figure class="text-center"><img src="../../media/2018/vs-code-writing-mode.png" alt="Screenshot of the VS Code in the zen mode without any clutter"> +<figcaption>My "writing mode" in VS Code, with the dark theme enabled.</figcaption></figure> +<p>Code editors are usually packed with a bunch of useful features, such as multi-selection, syntax highlighting, a file tree easy to operate, and sometimes even <a href="https://code.visualstudio.com/docs/languages/markdown">Markdown support</a> – which I need for writing my articles, notes, to-do lists, and absolutely everything I can write using Markdown. I love having a consistent workflow and that’s crucial to me, so why not?</p> +<p>After configuring my editor of choice, VS Code, to get rid of the coding mode clutter (and also after <a href="https://github.com/Microsoft/vscode/pull/40757">an important update on its zen mode</a> ❀), I’ve finally achieved a totally distraction-free writing experience!</p> +<h2 id="setting-up-the-writing-mode">Setting up the “Writing Mode”</h2> +<h3 id="1-user-settings">1. User Settings</h3> +<p>There are some important details to achieve total focus on writing. No line numbers, word wrap enabled, comfortable line height, no rulers, are some of them.</p> +<p>Since I only write in Markdown, I only set up those settings (and other tweaks) specifically for that language.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#6272a4;">// github.com/diessica/dotfiles/blob/master/vscode/settings.json +</span><span>{ +</span><span> </span><span style="color:#ff79c6;">.... +</span><span> +</span><span> </span><span style="color:#f1fa8c;">&quot;[markdown]&quot;</span><span>: { +</span><span> </span><span style="color:#6272a4;">// force centering in zen mode +</span><span> </span><span style="color:#f1fa8c;">&quot;zenMode.centerLayout&quot;</span><span>: </span><span style="color:#bd93f9;">true</span><span>, +</span><span> </span><span style="color:#6272a4;">// use the beautiful duospace font when available +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.fontFamily&quot;</span><span>: </span><span style="color:#f1fa8c;">&quot;iA Writer Duospace, monospace&quot;</span><span>, +</span><span> </span><span style="color:#6272a4;">// enable word wrap, since horizontal scroll while writing isn&#39;t human +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.wordWrap&quot;</span><span>: </span><span style="color:#bd93f9;">true</span><span>, +</span><span> </span><span style="color:#6272a4;">// i don&#39;t need line numbers, i&#39;m not coding +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.lineNumbers&quot;</span><span>: </span><span style="color:#f1fa8c;">&quot;off&quot;</span><span>, +</span><span> </span><span style="color:#6272a4;">// light by default, but can be easily toggled to dark +</span><span> </span><span style="color:#f1fa8c;">&quot;workbench.colorTheme&quot;</span><span>: </span><span style="color:#f1fa8c;">&quot;Default Light+&quot;</span><span>, +</span><span> </span><span style="color:#6272a4;">// i don&#39;t need rules, i&#39;m not coding +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.rulers&quot;</span><span>: [], +</span><span> </span><span style="color:#6272a4;">// larger text, to improve focus on writing +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.fontSize&quot;</span><span>: </span><span style="color:#bd93f9;">14</span><span>, +</span><span> </span><span style="color:#6272a4;">// more comfortable line height +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.lineHeight&quot;</span><span>: </span><span style="color:#bd93f9;">25</span><span>, +</span><span> </span><span style="color:#6272a4;">// disable editor suggestions based on previous words +</span><span> </span><span style="color:#f1fa8c;">&quot;editor.quickSuggestions&quot;</span><span>: </span><span style="color:#bd93f9;">false</span><span>, +</span><span> }, +</span><span> +</span><span> </span><span style="color:#ff79c6;">... +</span><span>} +</span></code></pre> +<p class="note">You can learn more about this file by checking the docs on <a href="https://code.visualstudio.com/docs/getstarted/settings">"User and Workspace Settings"</a>.</p> +<p>Now, <strong>toggle zen mode</strong> in VS Code (see <a href="https://code.visualstudio.com/docs/getstarted/keybindings">Keybindings</a>, or <code>View &gt; Toggle Zen Mode</code>) and check if that fits you!</p> +<h3 id="2-theme">2. Theme</h3> +<p>Honestly, I think the default themes provided by VS Code do a great job. I use Dark+ as the dark theme; for light themes, either Quiet Light or Solarized Light.</p> +<p class="note">If you don't like them, feel free to pick anything else, since most themes provide sufficient Markdown support anyway. Just don't procrastinate – a good theme won't make you a better writer.</p> +<h3 id="3-font">3. Font</h3> +<p>My font of choice for writing is the <a href="https://github.com/iaolo/iA-Fonts/tree/master/iA%20Writer%20Duospace">Duospace</a>, designed by the people behind the text editor <a href="https://ia.net/writer/">iaWriter</a>. It’s a free and beautiful font shaped for the perfect writing experience.</p> +<h3 id="4-extensions">4. Extensions</h3> +<ul> +<li><a href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker">Spell Checker</a> catches your spelling errors.</li> +<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.wordcount">Word Count</a> helps you to not to be too wordy.</li> +<li><a href="https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one">Markdown All in One</a> gives you some extra power to play with Markdown files.</li> +<li><a href="https://marketplace.visualstudio.com/items?itemName=mushan.vscode-paste-image">Paste Image</a> lets you directly paste images from clipboard to files.</li> +</ul> +<h2 id="extra-tips">Extra tips</h2> +<ul> +<li><a href="https://code.visualstudio.com/docs/languages/markdown#_markdown-preview">VS Code’s Markdown Preview</a> is your friend – use it when you’re done with writing!</li> +<li>Configure the spell checker for your language, there are dictionary extensions for that available in the <a href="https://marketplace.visualstudio.com/">marketplace</a>. I also have <a href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker-portuguese-brazilian">the Brazilian Portuguese package</a> installed, for instance.</li> +<li>Like extensions? Keep exploring! The extension <a href="https://marketplace.visualstudio.com/items?itemName=shinnn.alex">alex</a>, for instance, catches insensitive, inconsiderate writing in texts.</li> +<li>Learn the Markdown keybindings provided by the All in One extension for a better workflow.</li> +</ul> +<p>Happy writing! 🌟</p> + + + + + My Hacking Adventure in Lithuania + 2018-02-15T00:00:00+00:00 + 2018-02-15T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/my-hacking-adventure-in-lithuania/ + + <div class="summary"> +<p>Exploring the country where my surname came from and hacking collaboratively at Science Hack Day Vilnius!</p> +</div> +<p>I love to hack stuff, and, this year, I’ve been pushing myself to do more of that along with people.</p> +<p>That’s how I found a hackathon called Science Hack Day, a weekend event with the goal of “making weird, silly or serious things with science”<sup class="footnote-reference"><a href="#1">1</a></sup> in collaboration with others. Although I missed the Berlin edition for just a few days after it happened in November, another event was about to come – this time, in <strong>Lithuania</strong>, where my surname “Gurskas” came from.</p> +<p>There it was the perfect replacement: the <a href="http://vilnius.sciencehackday.org/">Science Hack Day Vilnius 2018</a> would be my great excuse to explore the country where my grandfather was born.</p> +<p>Right on the last minute, I got a bedroom in a cheap hotel booked, and my flight and event tickets ready. All set for the hacking adventure!</p> +<h2 id="welcome-to-vilnius">Welcome to Vilnius</h2> +<p>Approximately 2 hours from Berlin by plane, there I was: Vilnius, the capital of Lithuania. A modest city, so small you can pretty much explore everything by feet.</p> +<p>Temperatures were more negative than in Berlin. Winter, and the city wasn’t the most colourful either, so the atmosphere was somewhat dark – even though the snow was painting all buildings, houses, and streets in a shining white.</p> +<p>The cold was totally dismissible as soon as I met the Lithuanians, warm and welcoming people who seemed to lead a simple life.</p> +<h2 id="science-hack-day-vilnius-2018">Science Hack Day Vilnius 2018</h2> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-trophies.jpg" alt="Trophies for different prize categories"></picture> +<figcaption>Trophies for different prize categories. (Photo: <a href="http://makerraitis.com">Raitis Gocentas</a>)</figcaption></figure> +<p>A Science Hack Day is a 2-day event run by volunteers. Since it’s a hackathon, it’s pretty hectic and leaves you exhausted at the end. However, also since it’s a hackathon, it’s remarkably rewarding at the end.</p> +<p>These were my days!</p> +<h3 id="first-day">First Day</h3> +<p>Early on Saturday, I walked to <a href="https://technarium.lt/">Technarium</a>, where the event would happen. It’s a laid-back and community-operated hackerspace in Vilnius, where technology enthusiasts work or co-work on their projects and share knowledge. My perfect habitat, sort of.</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-technarium.jpg" alt="Technarium space"></picture> +<figcaption>Technarium. (Photo: <a href="http://makerraitis.com">Raitis Gocentas</a>)</figcaption></figure> +<p>I found a seat in the middle of a diverse crowd of enthusiasts: kids, teenagers, and adults (in which you could also find scientists and professors). I had forgotten to adjust my clock to the local timezone when I arrived in Lithuania – 1 hour ahead of Berlin –, so I was kinda late and the talks on open science had already started.</p> +<p>With honestly no idea on how all that’d end up (a feeling I’m used to, since I always do unexpected stuff to myself anyway), I was watching the talks and telling myself that the worst that could happen was that I’d have no idea and no team, and would end up just exploring what others were building. It didn’t sound any bad at all! Being around creative people is always appreciated anyway.</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-badge.jpg" width="800" alt="Electronic hackable badge and stickers from Science Hack Day Vilnius 2018"></picture> +<figcaption>Electronic hackable badge and some stickers I got for joining the event! The badge features a WiFi-enabled micro-controller and MicroPython, for some hardware hacking fun. <a href="https://github.com/Technariumas/shd18badge">Check the badge's GitHub repository</a>.</figcaption></figure> +<p>After the talks, it was time for people to pitch about their potential projects. Most ideas involved Biology, Programming, Physics, Chemistry – anything related to (science) hacking! One of the ideas, from a team of 3 guys, was to build an audio visualiser.</p> +<p><em>“We need a Python engineer who understands some audio engineering”</em>, they said, in Lithuanian (thanks person who was real-time translating everything!). Luckily, in a beautiful coincidence, I love music, Python, and also have been playing with spectrum analysis for audio visualisation in the last year – so I decided to take a shot and ask them to join the team.</p> +<p>They said they had no idea how to get the input from a microphone, and that they knew more about the hardware part, Arduino, and manipulating those machines in the hackerspace to come up with a cool design for our project. I’m just bad at things that require manual work that isn’t with the keyboard, so my manual help would be typing Python for 2 days on my laptop. They accepted it. So far, we had:</p> +<ul> +<li>the idea;</li> +<li>an Arduino Nano;</li> +<li>a power supply;</li> +<li>long LED strip lights;</li> +<li>an acrylic sheet.</li> +</ul> +<p>Since Arduino Nano isn’t powerful enough for that computation, it’d be only used for data acquisition, and the spectrometer would live in our Python program in my laptop, computing the Fourier transform of the audio signals.</p> +<p>By the end of the day, we managed to get input from the microphone, analyse its signals in the frequency domain with Python, and start mapping that data to be sent to our Arduino over a serial interface. Some libraries we played with were: <a href="https://people.csail.mit.edu/hubert/pyaudio/">pyaudio</a>, <a href="http://www.numpy.org/">numpy</a>, <a href="https://github.com/pyserial/pyserial">pyserial</a>, <a href="https://matplotlib.org/">matplotlib</a>.</p> +<h3 id="second-day">Second Day</h3> +<p>Now with the clock correctly set (thanks to my friend that asked what timezone I was in, otherwise I wouldn’t ever know), I was on my way to Technarium again, walking over and under snow in that early Sunday morning.</p> +<p>A day in the Science Hack Day Vilnius was a day with Lithuanian hearty lunch, black coffee, and hard work around kind people. (By the way, if you ever end up there, try the <a href="https://en.m.wikipedia.org/wiki/Kibinai">kibinai</a> – I ate one filled with spinach and will never forget how it smelled and tasted.)</p> +<p>Most people there were Lithuanians and I didn’t know anything about their language besides “labas vakaras”<sup class="footnote-reference"><a href="#2">2</a></sup> (“good evening”), so I felt like an outsider sometimes. My teammates and other Lithuanians in the event – including kids –, though, were friendly and spoke English flawlessly, and fortunately even translated some stuff into English for me.</p> +<p class="note"><b>Curious fact:</b> A teenager at the event told me that my surname was "wrong" – in Lithuania, single women get a different surname suffix, so my name should be Gurskaite ("skaite" suffix, instead of –kas). In Brazil, of course, they didn’t know that and only cloned my grandfather’s surname – with the "kas" suffix, since he was a man: Gurskas.</p> +<p>More talks in the morning on open hardware and software. They introduced everyone to GitHub, and many people, even students, were already familiar with it. The importance given to open source was impressive! That made me really happy.</p> +<p>Time flew on the second day! We had got the data we needed, and the next step was to decide on what would be more fun: to map amplitudes from the maximum frequency to RGB values for all LEDs, or map each LED to a frequency and change its colour depending on the amplitude? We picked up the latter, and got our LEDs to blink.</p> +<hr /> +<p>One of my teammates was learning Programming. He told me he didn’t know what programming languages to really <em>sit down and learn</em>, as seen that there were a lot of them out there. True, and a nice question! I gave him a biased answer, of course: “go for Python or JavaScript”. My reasons? Way more fun. Besides beginner-friendly, those languages have the most interesting, welcoming and lively ecosystems I know these days.</p> +<hr /> +<p>We were running out of time. While 2 of my teammates were building the LED tower, the other and I were testing the code and trying to improve our algorithm, everything at the same time. Eventually, we got our LEDs to blink the way we wanted them to, and the clock pointed 18:00 sharp. <strong>Time for presenting</strong>!</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-lasers.jpg" alt="Laser project presentation"></picture> +<figcaption>Project showing how lasers work. It emitted sounds too! (Photo: <a href="http://makerraitis.com">Raitis Gocentas</a>)</figcaption></figure> +<p>Teams came up with a lot of cool things! Projects related to lasers, contactless payment systems security tests, <a href="https://www.instagram.com/p/BfEKAXYH-iH">shopping-cart-rocket launch</a> (#SpaceXLithuania!), plant-watering automation, posters with LEDs crafted by kids celebrating the 100th year of the Lithuanian as an independent country
 And ours, of course.</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-spectrogram.jpg" alt="Presenting the LED tower to the public"></picture> +<figcaption>Two of my teammates (one's missing!) and me. I was weirdly concentrated uttering different notes to show how LEDs reacted to frequencies. (Photo: <a href="http://makerraitis.com">Raitis Gocentas</a>)</figcaption></figure> +<p>There were different category prizes, and we won as the <strong>Best Data Hack</strong>!</p> +<p>I got the honor to take home not just this LED-powered trophy below, but also a memorable experience I had the pleasure to share with people I didn’t know in a country I didn’t know.</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-prize.jpg" width="800" alt="A trophy for Best Data Hack 2018 and a Raspberry Pi"></picture> +<figcaption>A trophy for the Best Data Hack 2018 and a Raspberry Pi. Our prizes for having fun!</figcaption></figure> +<p>The Hack Day ended with a science show by <a href="http://n-2.lt/en/performances/">N2</a>! Lots of fun with liquid nitrogen and eating cookies at temperatures close to the absolute zero. My teammates, Physics students, knew a lot of the science behind that stuff so I got some extra explanations! (I have to say, though, that one of my greatest learnings of that day was to not to chew those cookies slowly – they stick to your tongue in a TORTURING way.)</p> +<figure class="text-center"><picture><img src="../../media/2018/sdhv18-n2-fire.jpg" alt="N2 science show group playing with fire"></picture> +<figcaption>Playing with fire. Literally. (Photo: <a href="http://makerraitis.com">Raitis Gocentas</a>)</figcaption></figure> +<p>It’s always truly amazing to experience closely how creative and curious humans are! The event was awesome, well-organised, and, last but not least, <em>fun</em>. Organisers provided us all the materials (food included!), borrowing me even the single USB-C adapter they had!</p> +<p>Clearly, the only intent behind Science Hack Days is for people to <strong>share and learn</strong> openly. And that has been achieved just right.</p> +<h2 id="final-words">Final words</h2> +<p>Open knowledge is one of the most valuable things in this world. I have no doubt.</p> +<p>I’m happy to have picked such an eccentric travel destination for my weekend, and really grateful for everything I saw and everyone I’ve met on the way.</p> +<figure class="text-center"><picture><img src="../../media/2018/gurskas-snow.jpg" alt="Gurskas written in snow"></picture> +<figcaption>I don't feel my fingertips anymore since I did that. Writing in the snow: definitely NOT encouraged!</figcaption></figure> +<p>Lithuania was freezing, yes, but people were warm.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>From the <a href="/blog/my-hacking-adventure-in-lithuania/%20https://en.m.wikipedia.org/wiki/Science_Hack_Day">Science Hack Day’s Wikipedia page</a>.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>Special thanks to my father, who taught me that, otherwise I wouldn’t know anything really.</p> +</div> + + + + + Creativity + 2018-02-05T21:25:00+00:00 + 2018-02-05T21:25:00+00:00 + + + + + Unknown + + + + + + /blog/creativity/ + + <p>In a life where, by default, there’s no meaning at all, I value creating above all. If I’m creating, that’s a meaningful day.</p> +<p>Lately, I’ve been pondering on the phenomenon of creativity and why creative people are so inspiring to be around. They just broaden my perception of the universe profoundly. What really happens?</p> +<h2 id="the-phenomenon">The Phenomenon</h2> +<p>In an interview in the late 1990s<sup class="footnote-reference"><a href="#1">1</a></sup>, Steve Jobs said something that years later would be seen as one of the most simple but accurate definitions of creativity:</p> +<blockquote> +<p>Creativity is just connecting things.</p> +</blockquote> +<p>And he followed with something I couldn’t help but relate: <em>“When you ask creative people how they did something, they feel a little guilty because they didn’t really do it, they just saw something. It seemed obvious to them after a while. [
]”</em>.</p> +<p>In the wake of being called creative, I was used to responding with the most unfair answer ever: “But everything I did was mixing stuff from here and there!?!“. It turns out, however, that “mixing stuff” actually describes precisely the process creative people go through.</p> +<p>And when Steve Jobs said that, he was mixing stuff as well! He most likely got inspired by James Webb Young’s conception of idea, presented in his book <a href="https://www.goodreads.com/book/show/534755.A_Technique_for_Producing_Ideas">A Technique for Producing Ideas</a>, from the 1940s.</p> +<blockquote> +<p>An idea is nothing more nor less than a new combination of old elements [and] the capacity to bring old elements into new combinations depends largely on the ability to see relationships.</p> +</blockquote> +<p class="note">For James to suggest that, well, guess what? He was inspired by <a href="https://en.wikipedia.org/wiki/Vilfredo_Pareto">Pareto</a>'s idea of the "speculator", a personality type characterized by a constant preoccupation with the possibilities of new combinations of old elements. (Which sort of proves his own point on "ideas as a combination of old elements".)</p> +<p>Creatives are just so overloaded with elements to mix that those overflow and flow out of their heads, and they can’t help but inspire everyone around.</p> +<p>They reframe experiences and mix their elements to be synthesised into something valuable and unique. From songs, painting, programming to scientific theories – all of them comes from <strong>mixtures</strong>. When the mixture feels good, either as a homogeneous or heterogeneous result, it’s then a <em>creation</em>.</p> +<h2 id="the-creation-the-weird">The Creation, The Weird</h2> +<figure class="text-center"><picture><img class="mx-auto" src="../../media/2018/creativity.png" width="500" alt="Creativity comics"></picture> +<figcaption><a href="http://dorrismccomics.com/post/64681231561">Creativity</a>, by Alex Norris.</figcaption></figure> +<p>When the creation distances itself too much from its origin elements (which are things people are already aware of, most likely), it’s perceived as <strong>weird</strong>, rather than authentic. But that’s when we truly innovate! To come up with the weird, though, we have to limit ourselves to certain existing elements – an outstanding habit people like Alan Turing had.</p> +<p class="note">Alan Turing was an inspiring computer scientist. Among other cool stuff, he proposed humans to consider the question <a href="http://phil415.pbworks.com/f/TuringComputing.pdf">"Can computers think?"</a>, and also designed <a href="https://en.m.wikipedia.org/wiki/Bombe">cryptanalytical machines</a>, crucial to cracking German encoded communication during the World War II. Cool stuff!</p> +<p>As described by James Wilkinson, who worked closely with him, Turing avoided looking at previous work on a topic just so he could invent something truly original, truly <strong>weird</strong>.</p> +<p><em>”Turing had a strong predilection for working things out from first principles, usually in the first instance without consulting any previous work on the subject, and no doubt it was this habit which gave his work that characteristically original flavor.“</em> <sup class="footnote-reference"><a href="#2">2</a></sup></p> +<p>Finally, the ones who release their creations end up turning into painters, mathematicians, writers, architects, sculptors, programmers, musicians. It’s a process that happens in absolutely every realm of thinking and work.</p> +<p>And you know what?</p> +<h2 id="it-s-been-shown-by-nature">
It’s Been Shown by Nature</h2> +<p>When Young and Steve Jobs pointed out that the creative process wasn’t magic, they, again, didn’t do anything “new” either. That definition has been shown by Nature for a long time, and, as early as 450 B.C, the philosopher <a href="https://en.wikipedia.org/wiki/Anaxagoras">Anaxagoras</a> described it:</p> +<blockquote> +<p>Wrongly do the Greeks suppose that something<sup class="footnote-reference"><a href="#3">3</a></sup> begins or ceases to be; for nothing comes into being or is destroyed; but all is an aggregation or secretion of pre-existing things; so that all becoming might more correctly be called becoming mixed, and all corruption, becoming separate.</p> +</blockquote> +<p class="note">That might remember you of the Law of Conservation of Mass, later defined by the chemist Antoine Lavoisier.</p> +<p>Just like in the creative process, Nature has always found a way out of its problems by coming up with solutions from pre-existing elements. Even the Planet Earth has transformed from a violent, molten rock to a supporter of life by using what the Universe had already provided!</p> +<p>Its process of creation was the same as the human’s creative process for the discovery of fire, the invention of the wheel, shitty <em>and</em> useful startup ideas, the Pink Floyd’s Echoes song, and all quotes in this post: mixing, connecting, combining “stuff”. From the Planet Earth to what you’re reading right now, the laws that ruled their creations were, in essence, the same.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>Steve Jobs. <a href="https://www.wired.com/1996/02/jobs-2/">“Steve Jobs: The Next Insanely Great Thing”</a>. WIRED. January 1996.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>James H. Wilkinson, <a href="http://www.jdl.ac.cn/turing/pdf/p137-wilkinson.pdf">“Some Comments from a Numerical Analyst”</a>, 1970. <a href="https://en.wikipedia.org/wiki/Turing_Award">Turing Award</a> lecture, <em>Journal of the ACM</em>. February 1971.</p> +</div> +<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup> +<p>I’ve deliberately changed “aught”, an archaic English word, to “something” for the sake of readability.</p> +</div> + + + + + Dental Health and Habits + 2017-12-21T08:58:09+00:00 + 2017-12-21T08:58:09+00:00 + + + + + Unknown + + + + + + /blog/dental-health-and-habits/ + + <p>Brushing teeth is a good habit. An easy-to-build one, I’d say, thanks to the immediate reward given by the refreshing sensation. After brushing, you <em>feel</em> clean right away.</p> +<p>On the other hand, flossing teeth isn’t a habit as easy to build. After flossing, what comes to mind is how dirty your teeth still were even though you just brushed, not how cleaner they became. There’s no such thing as a fresh sensation in your mouth.</p> +<p>When you finish brushing your teeth, they’re still dirty – no doubt. However, it’s still gratifying, since you’re fooled by the menthol ability to trigger the cooling sensation. <em>(Hence the human inclination to brushing rather than flossing!?)</em></p> +<p>In terms of dental health, though, flossing teeth is more effective on cleaning than brushing<sup class="footnote-reference"><a href="#1">1</a></sup>, <strong>even if it doesn’t feel like it.</strong> There’s no immediate reward in flossing, but definitely a long-term one.</p> +<p>What am I trying to say? Apart from dental health advice, that sort of reminds me that we shouldn’t rely on feeling instantaneously compensated as a fuel to build habits. After all, some things just need the long-term to pay off; for we to benefit from them.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>I’ve read that at some point in my life but don’t remember where. You can find some resources out there, such as “<a href="https://askthedentist.com/flossing-or-brushing-more-important/">What’s More Important: Flossing or Brushing?</a>”. Anyway, I think we’re safe assuming that flossing is, at least, <em>as important</em> as brushing.</p> +</div> + + + + + Expressive JavaScript Conditionals (for Humans) + 2017-10-30T00:00:00+00:00 + 2017-10-30T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/expressive-javascript-conditionals/ + + <p>Conditionals! As programmers, we write at least one every day. Easy to write, horrible to read, and sometimes it seems as though there’s no way to work around that.</p> +<p>Today, I’m happy to share some patterns I’ve learned over time and have spread heavily in code reviews. Let’s rethink conditionals to make the most out of a language’s power of expression – in the case of this article, JavaScript.</p> +<h2 id="patterns-for-conditionals">Patterns for Conditionals</h2> +<p>First, to put you in the mood, a quote from Literate Programming<sup class="footnote-reference"><a href="#1">1</a></sup>, by Donald Knuth.</p> +<blockquote> +<p>The practitioner of literate programming can be regarded as an essayist, whose main concern is with exposition and excellence of style. Such an author, with thesaurus in hand, chooses the names of variables carefully and explains what each variable means. He or she strives for a program that is comprehensible because its concepts have been introduced in an order that is best for human understanding, using a mixture of formal and informal methods that reinforce each other.</p> +</blockquote> +<p>That sums up the approach for this post: purely aimed at <strong>how to write code for people to read</strong>. Performance doesn’t matter now, since 1) that’s not the goal and 2) I don’t believe in premature optimisation.</p> +<p>I’ll briefly talk about each pattern, but what’s more important here is to read the code carefully and get something out of it (as if it were poetry or something!).</p> +<h3 id="1-variables-that-hold-conditions">1. Variables that hold conditions</h3> +<p>When your condition is made up of an expression (or many of them), you can store it within meaningful-named variables.</p> +<p>Let’s say, to illustrate, that our program holds some data about a fruit and we have to check whether that fruit is a banana. We could do this:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;green&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">true</span><span>, +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">sweet </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">true </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">colors</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>((</span><span style="font-style:italic;color:#ffb86c;">color</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">color </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>)) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;do your stuff 🍌&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#f1fa8c;">&quot;is banana&quot; +</span><span>} +</span></code></pre> +<p>Or we could store our conditions in variables!</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;green&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">true</span><span>, +</span><span>} +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isSweet </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">sweet </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">true </span><span style="color:#6272a4;">// or just `fruit.sweet` +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">colors</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>((</span><span style="font-style:italic;color:#ffb86c;">color</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">color </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isSweet +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">isBanana</span><span>) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;do your stuff 🍌&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#f1fa8c;">&quot;is banana&quot; +</span><span>} +</span></code></pre> +<p class="note">Not all conditions need to be in a variable. <code>fruit.sweet</code>, for instance, is quite expressive by its own.</p> +<p>This way, if we or our workmates need to know what makes a fruit a banana in our program, it’s just a matter of checking out the variable itself. The logic for how conditions evaluate will be there, behind a meaningful name.</p> +<p>It’s even more useful for composing and reusing conditions.</p> +<h4 id="filtering-arrays">Filtering arrays</h4> +<p class="note">In the previous example, all variables were conditions based on the <code>fruit</code> object, for didactic purposes. Commonly, though, those variables actually store (pure) functions that take any fruit and test against it. I'm changing that to fit this example.</p> +<p>Let’s say we’ve got an array of fruits and we need to filter all the bananas out of it.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruits </span><span style="color:#ff79c6;">= </span><span>[ +</span><span> { +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;green&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">true</span><span>, +</span><span> }, +</span><span> { +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;red&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">false</span><span>, </span><span style="color:#6272a4;">// don&#39;t know what kind of fruit this&#39;d be +</span><span> }, +</span><span>] +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">isSweet </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">sweet </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">true +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">isYellow </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">colors</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>((</span><span style="font-style:italic;color:#ffb86c;">color</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">color </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>) +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">isBanana </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#50fa7b;">isSweet</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#50fa7b;">isYellow</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">bananas </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruits</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">filter</span><span>(</span><span style="color:#ffffff;">isBanana</span><span>) +</span></code></pre> +<p>So expressive! I love the way that I can read that last line and even a kid (a non-programmer one!) can understand. <em>(Yes, I’ve tried that.)</em></p> +<p>The currying technique would help introduce expressiveness without the verbosity for <code>isBanana</code>. An optional appendix at the end of the article elaborates more on that, if you’re curious.</p> +<p>That’s it. Hold on to that one though – it’s the foundation for what’s next.</p> +<h3 id="2-define-value-conditionally">2. Define value conditionally</h3> +<p>Still considering the variables from the example above, this could also be done:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">myFruit </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isSweet </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#f1fa8c;">&quot;banana&quot; +</span><span style="color:#ff79c6;">return </span><span style="color:#ffffff;">myFruit +</span></code></pre> +<p>The value for the <code>myFruit</code> variable will only be assigned to “banana” if those conditions are true. Pretty useful for when values are defined conditionally!</p> +<p>That saves you from <code>if (isYellow &amp;&amp; isSweet) [...]</code>, and it’s quite expressive, I’d say. An expressive expression. 👌</p> +<h3 id="3-define-value-conditionally-with-fallback">3. Define value conditionally with fallback</h3> +<figure class="text-center"><picture><img width="250" src="https://imgs.xkcd.com/comics/conditionals_2x.png" alt="Conditionals, a comic from xkcd"></picture> +<figcaption><a href="http://xkcd.com/1652">xkcd: Conditionals</a></figcaption></figure> +<p>What if we want something else in case it’s not a banana? Instead of an <code>if (isBanana) [...]</code> with <code>else</code>, go for the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator">ternary operator</a>.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isSweet +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">myFruit </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">? </span><span style="color:#f1fa8c;">&quot;is banana&quot; </span><span style="color:#ff79c6;">: </span><span style="color:#f1fa8c;">&quot;is other stuff&quot; +</span><span style="color:#ff79c6;">return </span><span style="color:#ffffff;">myFruit +</span></code></pre> +<p>Some additional but important advice I’d give regarding ternary expressions:</p> +<ul> +<li>Make them as compound as possible.</li> +<li>Do NOT nest them. Don’t pretend the nesting is readable – it’s not even human to do that.</li> +<li>Don’t avoid writing <code>if</code> statements because you want to look smart.</li> +</ul> +<h3 id="4-check-for-all-conditions">4. Check for all conditions</h3> +<p>We’ve (finally) found out that checking for <code>isYellow</code> and <code>isSweet</code> isn’t enough to make sure the fruit is a banana. After all, yellow pepper is both sweet and yellow and it’s still not a banana, right?</p> +<p>Right. We then add more checks to the <code>isBanana</code> variable, and this time they’re ugly ones: they check whether the fruit is either from Brazil or Ecuador, both top banana producing countries.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;green&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">true</span><span>, +</span><span> countries: [ +</span><span> { +</span><span> name: </span><span style="color:#f1fa8c;">&quot;Brazil&quot;</span><span>, +</span><span> topProducer: </span><span style="color:#bd93f9;">true</span><span>, </span><span style="color:#6272a4;">// i&#39;m brazilian and therefore biased +</span><span> }, +</span><span> { +</span><span> name: </span><span style="color:#f1fa8c;">&quot;Ecuador&quot;</span><span>, +</span><span> topProducer: </span><span style="color:#bd93f9;">false</span><span>, +</span><span> }, +</span><span> ], +</span><span>} +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isSweet </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">sweet </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">true </span><span style="color:#6272a4;">// or just `fruit.sweet` +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">colors</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>((</span><span style="font-style:italic;color:#ffb86c;">color</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">color </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBrazilian </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">countries</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">find</span><span>((</span><span style="font-style:italic;color:#ffb86c;">i</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">i</span><span style="color:#ff79c6;">.</span><span>name </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;Brazil&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isEcuadorian </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">countries</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">find</span><span>((</span><span style="font-style:italic;color:#ffb86c;">i</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">i</span><span style="color:#ff79c6;">.</span><span>name </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;Ecuador&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isSweet </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isBrazilian </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isEcuadorian +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">isBanana</span><span>) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;do your stuff!11 🍌&quot;</span><span>) +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;now this is really a banana&quot;</span><span>) +</span><span>} +</span></code></pre> +<p>Did you see how big <code>isBanana</code> is getting? We’d have to start breaking lines in those <code>&amp;&amp;</code> to improve readability, which, personally, I don’t like doing.</p> +<p>If refactoring the booleans into new variables isn’t an option anymore, what about <em>storing the conditions in an array and testing every item for truthiness</em>?</p> +<p>Use the power of <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every">array’s <code>every</code></a>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span>[</span><span style="color:#ffffff;">isYellow</span><span>, </span><span style="color:#ffffff;">isSweet</span><span>, </span><span style="color:#ffffff;">isEcuadorian</span><span>, </span><span style="color:#ffffff;">isBrazilian</span><span>]</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">every</span><span>(</span><span style="font-style:italic;color:#66d9ef;">Boolean</span><span>) </span><span style="color:#6272a4;">// or `x =&gt; x === true` +</span></code></pre> +<p class="note">Repetitive friendly reminder: don't store every condition in a variable. Remember you can always add the condition itself to the array.</p> +<p>You can even turn that into a snippet:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">all </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">arr</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">arr</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">every</span><span>(</span><span style="font-style:italic;color:#66d9ef;">Boolean</span><span>) +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#50fa7b;">all</span><span>([</span><span style="color:#ffffff;">isYellow</span><span>, </span><span style="color:#ffffff;">isSweet</span><span>, </span><span style="color:#ffffff;">isEcuadorian</span><span>, </span><span style="color:#ffffff;">isBrazilian</span><span>]) +</span></code></pre> +<p>I don’t know how useful that looks for you, but, in everyday work, I really appreciate doing it.</p> +<h3 id="5-check-for-any-condition">5. Check for any condition</h3> +<p>What if we’ve got crazy and we’re fine considering something a banana when it’s either yellow, Brazilian or sweet?</p> +<p>Use the power of <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some">array’s <code>some</code></a>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span>[</span><span style="color:#ffffff;">isYellow</span><span>, </span><span style="color:#ffffff;">isSweet</span><span>, </span><span style="color:#ffffff;">isBrazilian</span><span>]</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>(</span><span style="font-style:italic;color:#66d9ef;">Boolean</span><span>) </span><span style="color:#6272a4;">// or `x =&gt; x === true` +</span></code></pre> +<p class="note">Yeah, yeah, I know, you can just use the <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_OR_()">OR operator</a>.</p> +<p>If any of them evaluates to true, profit! – it’s a banana. 🍌</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">any </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">arr</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">arr</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>(</span><span style="font-style:italic;color:#66d9ef;">Boolean</span><span>) +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#50fa7b;">any</span><span>([</span><span style="color:#ffffff;">isYellow</span><span>, </span><span style="color:#ffffff;">isSweet</span><span>, </span><span style="color:#ffffff;">isBrazilian</span><span>]) +</span></code></pre> +<p>In other words, being a Brazilian means you’re a banana! It doesn’t sound any bad to me honestly.</p> +<p>Pretty similar to <a href="http://ramdajs.com/docs/#either">Ramda’s <code>either</code></a>. 😎</p> +<h3 id="6-early-return">6. Early return</h3> +<p>We want something special for when the banana is Brazilian! <code>else</code> conditions would do the trick, wouldn’t they?</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> colors: [</span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;green&quot;</span><span>], +</span><span> sweet: </span><span style="color:#bd93f9;">true</span><span>, +</span><span> countries: [ +</span><span> { +</span><span> name: </span><span style="color:#f1fa8c;">&quot;Brazil&quot;</span><span>, +</span><span> topProducer: </span><span style="color:#bd93f9;">true</span><span>, </span><span style="color:#6272a4;">// i&#39;m brazilian and therefore biased +</span><span> }, +</span><span> { +</span><span> name: </span><span style="color:#f1fa8c;">&quot;Ecuador&quot;</span><span>, +</span><span> topProducer: </span><span style="color:#bd93f9;">false</span><span>, +</span><span> }, +</span><span> ], +</span><span>} +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isSweet </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">sweet </span><span style="color:#ff79c6;">=== </span><span style="color:#bd93f9;">true </span><span style="color:#6272a4;">// or just `fruit.sweet` +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">colors</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">some</span><span>((</span><span style="font-style:italic;color:#ffb86c;">color</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">color </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;yellow&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBrazilian </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">countries</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">find</span><span>((</span><span style="font-style:italic;color:#ffb86c;">i</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">i</span><span style="color:#ff79c6;">.</span><span>name </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;Brazil&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isEcuadorian </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruit</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">countries</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">find</span><span>((</span><span style="font-style:italic;color:#ffb86c;">i</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">i</span><span style="color:#ff79c6;">.</span><span>name </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;Ecuador&quot;</span><span>) +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">isYellow </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isSweet +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isBrazilian</span><span>) { +</span><span> </span><span style="color:#6272a4;">// first true case! +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;i am a brazilian banana i love football 🍌&quot;</span><span>) +</span><span>} </span><span style="color:#ff79c6;">else if </span><span>(</span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isEcuadorian</span><span>) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;i am an ecuadorian banana do not mess with me 🍌&quot;</span><span>) +</span><span>} </span><span style="color:#ff79c6;">else </span><span>{ +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;a normal banana from somewhere else&quot;</span><span>) +</span><span>} +</span></code></pre> +<p>Alternatively, THOOOUGH, we can early return (nothing at all, i.e. <code>undefined</code>), which will make <strong>our code stops its flow at that point</strong>.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isBrazilian</span><span>) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;i am a brazilian banana i love football 🍌&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#6272a4;">// sTAAAAHP!!!1 +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">&amp;&amp; </span><span style="color:#ffffff;">isEcuadorian</span><span>) { +</span><span> </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;i am an ecuadorian banana do not mess with me 🍌&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#6272a4;">// DON&#39;T GO ANY FURTHER, JAVASCRIPT!11 +</span><span>} +</span><span> +</span><span style="color:#6272a4;">// or do, whatever +</span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&quot;a normal banana from somewhere else&quot;</span><span>) +</span></code></pre> +<p class="note">Those checks could also be refactored into a variable named <code>isBrazilianBanana</code>. I found it too much for this example though, so this is just a friendly reminder that your conditions can always be composable.</p> +<p>Keep in mind that early returns might make the flow of your program confusing. Different from when you’re using <code>else</code> conditions, it’s not explicit that the conditionals are from the same logical group anymore.</p> +<h3 id="7-check-for-the-same-variable">7. Check for the same variable</h3> +<p>Let’s get the colour of the fruits! Each fruit has one.</p> +<p>Hmmm
 Different cases that require different handling, but all handled cases depend on the same thing. What do we do? We conditionally check for its value and handle the case depending on that.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">getFruitColor </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>{ +</span><span> </span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;banana&quot;</span><span>) { +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#f1fa8c;">&quot;is yellow&quot; +</span><span> } </span><span style="color:#ff79c6;">else if </span><span>(</span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;apple&quot;</span><span>) { +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#f1fa8c;">&quot;is red&quot; +</span><span> } </span><span style="color:#ff79c6;">else if </span><span>(</span><span style="color:#ffffff;">fruit </span><span style="color:#ff79c6;">=== </span><span style="color:#f1fa8c;">&quot;orange&quot;</span><span>) { +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#f1fa8c;">&quot;is orange&quot; +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#50fa7b;">getFruitColor</span><span>(</span><span style="color:#f1fa8c;">&quot;banana&quot;</span><span>) </span><span style="color:#6272a4;">// =&gt; is yellow +</span></code></pre> +<p class="note">This code would benefit from early returns, and, of course, the <code>switch</code> statement.</p> +<p>Or we don’t. Because, alternatively, we can create a getter function (<code>getFruitColor</code>) that:</p> +<ol> +<li>inputs a key (<code>fruit</code>), and</li> +<li>outputs the value that was assigned to that key in a specific map (<code>fruitColors</code>).</li> +</ol> +<p>Like this:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">fruitColors </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> banana: </span><span style="color:#f1fa8c;">&#39;is yellow&#39; +</span><span> </span><span style="color:#ffffff;">apple</span><span>: </span><span style="color:#f1fa8c;">&#39;is red&#39;</span><span>, +</span><span> orange: </span><span style="color:#f1fa8c;">&#39;is orange&#39;</span><span>, +</span><span>} +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">getFruitColor </span><span style="color:#ff79c6;">= </span><span style="font-style:italic;color:#ffb86c;">fruit </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#ffffff;">fruitColors</span><span>[</span><span style="color:#ffffff;">fruit</span><span>] +</span><span> +</span><span style="color:#50fa7b;">getFruitColor</span><span>(</span><span style="color:#f1fa8c;">&#39;banana&#39;</span><span>) </span><span style="color:#6272a4;">// fruitColors[&#39;banana&#39;] =&gt; is yellow +</span></code></pre> +<p>Simplifying, since that map isn’t useful outside of the getter itself anyway:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">getFruitColor </span><span style="color:#ff79c6;">= </span><span style="font-style:italic;color:#ffb86c;">fruit </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>({ +</span><span> banana: </span><span style="color:#f1fa8c;">&#39;is yellow&#39; +</span><span> </span><span style="color:#ffffff;">apple</span><span>: </span><span style="color:#f1fa8c;">&#39;is red&#39;</span><span>, +</span><span> orange: </span><span style="color:#f1fa8c;">&#39;is orange&#39;</span><span>, +</span><span>}[</span><span style="color:#ffffff;">fruit</span><span>] +</span><span> +</span><span style="color:#50fa7b;">getFruitColor</span><span>(</span><span style="color:#f1fa8c;">&#39;banana&#39;</span><span>) </span><span style="color:#6272a4;">// =&gt; is yellow +</span></code></pre> +<p>This is a very common technique I first saw on a <a href="https://javascriptweblog.wordpress.com/2010/03/08/caseagainstswitch/">blog post from Angus Croll</a> in 2010. I love the simplicity of it.</p> +<p>Nowadays there’s even more freedom with this technique, considering features such as <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names">computed property names for objects</a>. But don’t get too creative with that! Go for what’s more readable and expressive for you <strong>AND</strong> the people you work with.</p> +<h3 id="appendix-currying-because-verbosity-isn-t-expressiveness">Appendix: Currying, because verbosity isn’t expressiveness</h3> +<p class="note">This is an additional reading and requires familiarity with curried functions. For further reading on the currying technique, I recommend the <a href="https://drboolean.gitbooks.io/mostly-adequate-guide/content/ch4.html#cant-live-if-livin-is-without-you">"Currying" chapter</a> of the book Mostly Adequate Guide to Functional Programming, or <a href="https://www.sitepoint.com/currying-in-functional-javascript/">A Beginner’s Guide to Currying</a>, as a more beginner-friendly introduction.</p> +<p>Let’s reconsider:</p> +<ol> +<li>the problem from the 1st, where we had an array of fruits and had to create a function that checks whether the fruit passed to it was a banana, and</li> +<li>the <code>all</code> util from the 4th pattern.</li> +</ol> +<h4 id="check-for-all-conditions-revisited">Check for all conditions, revisited</h4> +<p>Imagine if we had a lot of conditions for <code>isBanana</code>. We could use <code>&amp;&amp;</code> or even <code>all</code>.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">isBanana </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; +</span><span> </span><span style="color:#50fa7b;">isBanana</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) </span><span style="color:#ff79c6;">&amp;&amp; +</span><span> </span><span style="color:#50fa7b;">isSweet</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) </span><span style="color:#ff79c6;">&amp;&amp; +</span><span> </span><span style="color:#50fa7b;">isEcuadorian</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) </span><span style="color:#ff79c6;">&amp;&amp; +</span><span> </span><span style="color:#50fa7b;">isBrazilian</span><span>(</span><span style="color:#ffffff;">fruit</span><span>) +</span><span style="color:#6272a4;">// or +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">isBanana </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">fruit</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; +</span><span> </span><span style="color:#50fa7b;">all</span><span>([ +</span><span> </span><span style="color:#50fa7b;">isYellow</span><span>(</span><span style="color:#ffffff;">fruit</span><span>), +</span><span> </span><span style="color:#50fa7b;">isSweet</span><span>(</span><span style="color:#ffffff;">fruit</span><span>), +</span><span> </span><span style="color:#50fa7b;">isEcuadorian</span><span>(</span><span style="color:#ffffff;">fruit</span><span>), +</span><span> </span><span style="color:#50fa7b;">isBrazilian</span><span>(</span><span style="color:#ffffff;">fruit</span><span>), +</span><span> ]) +</span></code></pre> +<p>It’s meaningful, easy to read, but introduces too much verbosity. The currying technique could help us introduce more meaning without being verbose. With some changes in the <code>all</code> util, that could be boiled down to:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">isBanana </span><span style="color:#ff79c6;">= </span><span style="color:#50fa7b;">all</span><span>([</span><span style="color:#ffffff;">isSweet</span><span>, </span><span style="color:#ffffff;">isYellow</span><span>, </span><span style="color:#ffffff;">isEcuadorian</span><span>, </span><span style="color:#ffffff;">isBrazilian</span><span>]) +</span><span style="color:#6272a4;">// no explicit fruit here, and still works! +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">bananas </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">fruits</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">filter</span><span>(</span><span style="color:#ffffff;">isBanana</span><span>) +</span></code></pre> +<p>Notice we’re not explicitly passing fruit anymore. How do we do that? By making <code>all</code> a curried function. There are some ways to achieve that, here’s one:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">all </span><span style="color:#ff79c6;">= </span><span>(</span><span style="font-style:italic;color:#ffb86c;">conditions</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>(</span><span style="font-style:italic;color:#ffb86c;">currentItem</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; +</span><span> </span><span style="color:#ffffff;">conditions</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">map</span><span>((</span><span style="font-style:italic;color:#ffb86c;">condition</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#50fa7b;">condition</span><span>(</span><span style="color:#ffffff;">currentItem</span><span>))</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">every</span><span>(</span><span style="font-style:italic;color:#66d9ef;">Boolean</span><span>) +</span></code></pre> +<p>It takes the array of conditions and returns a function that takes the current item and calls each condition with that (as <em>argument</em>!). At the end, we check whether they all evaluated to true. It’s not magic, it’s CURRYING!!!11<sup class="footnote-reference"><a href="#2">2</a></sup></p> +<p>That’s, of course, a simplistic implementation, which has costed me an array (from <code>map</code>). What’s important to get is how we play with <strong>function arguments under the hood</strong> to achieve currying.</p> +<p>You can curry your functions using <a href="http://ramdajs.com/docs/#all">Ramda’s <code>curry</code></a> (or Lodash’s, whatever); or, if you’re interested on that as an util, <a href="http://ramdajs.com/docs/#all">Ramda’s <code>all</code></a> and <a href="https://github.com/ramda/ramda/blob/master/source/all.js">its source</a> are really worth-checking!</p> +<h2 id="final-considerations">Final considerations</h2> +<p>By striving for conditionals as expressions other than statements, you write code in a <strong>functional</strong> approach. Code with a clearer sense of what it’s being checked without having to unearth to its foundations. Code that’s easier and faster for people to reason about.</p> +<p><strong>But if your code is fine with an <code>if</code> rather than an object lookup or a ternary operator, just stick to it.</strong></p> +<p>It’d break the whole purpose of this post if those patterns were used for looking smart. However, if refactoring your conditionals with them would lead to a more expressive codebase, go for it! Play with the patterns, <strong>compound them</strong>. Use your creativity to communicate well.</p> +<p>It’s a language, after all.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>A programming paradigm first introduced by Donald Knuth, with the goal of providing an alternative, human, perspective on the programmer’s motivation. <a href="http://www.literateprogramming.com/knuthweb.pdf">Read the article</a>.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p><strong>It may seem more magic than currying sometimes.</strong> JavaScript isn’t a purely functional language, so such techniques aren’t as popular as they are in Haskell community, for instance. Simplicity conflicts with easiness here.</p> +</div> + + + + + UI Components that Abstract Mistakes + 2017-10-14T18:06:00+00:00 + 2017-10-14T18:06:00+00:00 + + + + + Unknown + + + + + + /blog/ui-components-that-abstract-mistakes/ + + <p>2017, October 14th.</p> +<p>A cloudy day <sup class="footnote-reference"><a href="#1">1</a></sup> of Autumn in Berlin, probably something else in the place you live, <em>and</em> you’ve read the same date twice <em>and</em> this introduction actually doesn’t matter. But let me tell you about something that matters.</p> +<p>Everything is made up of <code>&lt;div&gt;</code>s and <code>&lt;span&gt;</code>s again, utterly hidden behind abstractions proudly called components. No one seems to remember <em>(or do they?)</em> the difference between <code>p</code> and <code>span</code>, let alone the point of using <code>section</code> rather than <code>div</code>.</p> +<p>Bad decisions – to not just to say bad and even invalid HTML markup – are buried in components developers find awesome to compose user interfaces with. The web, and people, pay the price.</p> +<hr /> +<h2 id="creating-components">Creating components</h2> +<p class="note">From now on, to explain my point, I'll be assuming some familiarity with <a href="https://reactjs.org/" title="React">React</a> (a JavaScript library), although this applies to any kind of component abstraction.</p> +<p>Let’s say you just started a brand new React web app. You need to create a button at some point, and, because it’s reused in other parts of the app, has custom styles and also a fancy icon, you decide to introduce a component with all that abstracted out. Nice! You could do it like this:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">Button </span><span style="color:#ff79c6;">= </span><span>({ </span><span style="font-style:italic;color:#ffb86c;">onClick</span><span>, </span><span style="font-style:italic;color:#ffb86c;">children </span><span>}) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>( +</span><span> </span><span style="color:#ff79c6;">&lt;</span><span style="color:#ffffff;">span class</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;my-horrible-button&quot; </span><span style="color:#ffffff;">onClick</span><span style="color:#ff79c6;">=</span><span>{</span><span style="color:#ffffff;">onClick</span><span>}</span><span style="color:#ff79c6;">&gt; +</span><span> </span><span style="color:#ff79c6;">&lt;</span><span style="color:#ffffff;">i class</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;my-terrible-font-awesome-icon&quot;</span><span style="color:#ff79c6;">&gt;</span><span>&lt;/i&gt; +</span><span> {</span><span style="font-style:italic;color:#ffb86c;">children</span><span>} +</span><span> </span><span style="color:#ff79c6;">&lt;/</span><span style="color:#ffffff;">span</span><span style="color:#ff79c6;">&gt; +</span><span>) +</span></code></pre> +<p>The user interface is then composed as the following:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="color:#ff79c6;">h1</span><span>&gt;Brazilian Bananas (1 kg)&lt;/</span><span style="color:#ff79c6;">h1</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Sweet and healthy bananas!&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Absolutely the best.&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span>&lt;</span><span style="font-style:italic;color:#66d9ef;">Button </span><span style="color:#50fa7b;">onClick</span><span style="color:#ff79c6;">={</span><span>() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#50fa7b;">alert</span><span>(</span><span style="color:#f1fa8c;">&#39;🍌&#39;</span><span>)</span><span style="color:#ff79c6;">}</span><span>&gt;Buy $0.99&lt;/</span><span style="color:#ff79c6;">button</span><span>&gt; +</span></code></pre> +<p>It looks good! You were born for this, weren’t you?</p> +<p>Quite easy to miss what’s wrong when components are just used like that. A button, isn’t it? The engineering team can easily grasp what that means and what that does, after all.</p> +<p>It could also be a <code>&lt;FormLabel /&gt;</code> or <code>&lt;Paragraph /&gt;</code> as <code>span</code> elements, or <code>div</code>s all over that place. Although they all work, mistakes are abstracted in components.</p> +<p class="note">I specifically talk about markup as the mistake throughout this article, however it could be anything really. Components look inoffensive when you're using them.</p> +<h2 id="the-web-isn-t-your-abstraction">The web isn’t your abstraction</h2> +<p>Now that HTML is all abstracted through JavaScript libraries and frameworks (which is not wrong), I wonder whether developers only went for semantic elements for the sake of making markup more readable for themselves. With React, your <code>&lt;Header&gt;</code> now may be a <code>div</code>. Out of the abstraction, though, you’d think twice before going for a <code>div</code> to make a header – you’d rather use HTML5’s <code>header</code>.</p> +<p><strong>Because of the abstraction, output markup isn’t something we talk that much about anymore.</strong></p> +<p>Did we really get the benefits of HTML5 and why new elements were introduced? Why <code>button</code>? <sup class="footnote-reference"><a href="#2">2</a></sup> What’s <code>header</code> useful for? Why should one use <code>section</code> at all?</p> +<p class="note">By the way, do you know how many occurrences of <code>header</code>, <code>article</code>, <code>section</code> I've found on Netflix's landing page? Zero. It's all div soup.</p> +<p>Matter of fact is that browser engines and people – nothing less than the ones who you really write code for – won’t ever know about your abstractions. A screen reader won’t know your “button” is actually a button<sup class="footnote-reference"><a href="#3">3</a></sup>. (They will definitely get to know the <code>span</code> though, and that won’t help.)</p> +<figure class="text-center"><picture><img src="https://imgs.xkcd.com/comics/tags.png" alt="xkcd, comic #1444"></picture> +<figcaption><a href="http://xkcd.com/1144">xkcd: Tags</a></figcaption></figure> +<p>Also, it’s never been easier to write invalid markup without even realizing it! After React, it seems acceptable to place a <code>button</code> inside an anchor link, and even giant elephants inside <code>span</code>. Has anyone ever thought why they are considered invalid markup in the first place?</p> +<h2 id="don-t-make-it-hard">Don’t make it hard</h2> +<p>Browsers and assistive technologies are smarter than ever<sup class="footnote-reference"><a href="#4">4</a></sup>, indeed, yet they still count on developers to write code they can understand and people can benefit from. By doing so, you make it easy for:</p> +<ol> +<li><strong>people</strong>, who will be able to navigate around the website, skipping over navigation sections or quickly jumping from one article to another<sup class="footnote-reference"><a href="#5">5</a></sup>.</li> +<li><strong>yourself</strong>, so you don’t have to reimplement default browser behaviours.</li> +</ol> +<p>Therefore, please: don’t waste features that technologies try to give users, and developers, out of the box.</p> +<p>Remember who you write code for.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>If I had managed to publish this yesterday, the day would be sunny. I’ve missed the opportunity to make the article seems a little happier.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>The button element was first introduced in HTML4. (<a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button">Source</a>)</p> +</div> +<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup> +<p>What’s wrong with using a non-semantic element as a button? Well, if the button is accessible, nothing really. But doing so demands <a href="https://www.marcozehe.de/2013/04/24/easy-aria-tip-6-making-clickables-accessible/">extra work</a> that nobody is up for, besides that fact that <a href="https://www.nczonline.net/blog/2013/01/29/you-cant-create-a-button/">you can’t actually create a button</a>.</p> +</div> +<div class="footnote-definition" id="4"><sup class="footnote-definition-label">4</sup> +<p>Technologies may even process <code>&lt;span class="tel"&gt;123-456-7890&lt;/span&gt;</code> as a telephone, and allow for automatic dialling of it. See <a href="https://en.wikipedia.org/wiki/Microformat">microformat</a> for more information.</p> +</div> +<div class="footnote-definition" id="5"><sup class="footnote-definition-label">5</sup> +<p>Why not, right? After all, <code>article</code>s are for independent pieces of content, e.g., an user-submitted comment or a forum post. (<a href="https://www.w3.org/TR/html5/sections.html#the-article-element">Source</a>)</p> +</div> + + + + + Tchau + 2017-05-13T16:12:00+00:00 + 2017-05-13T16:12:00+00:00 + + + + + Unknown + + + + + + /blog/tchau/ + + <p class="summary">de ViamĂŁo, Brasil para Berlim, Alemanha. đŸ‡©đŸ‡Ș</p> +<blockquote class="epigraph -default-color"> +<p>– <em>Tu tem que ver o que Ă© pra ti, sabe? Se tu ficar aĂ­, tu provavelmente vai ficar nessa mesma por bastante tempo. É isso que tu quer?</em></p> +<p>– <em>NĂŁo, meu sonho sempre foi morar fora, do paĂ­s.</em></p> +<p>– <strong>O meu tambĂ©m Ă©. Esse Ă© o meu foco, pra sempre. Eu nunca tirei isso da mente.</strong></p> +</blockquote> +<p>A memĂłria parece distante agora, mas nĂŁo faz muito tempo que eu tive essa conversa. 30 de Março de 2016. JĂĄ faz um pouco mais de um ano. FalĂĄvamos de indecisĂ”es, insatisfaçÔes e mudanças, quando sonhos vieram Ă  tona.</p> +<p><strong>Sonhos.</strong> Pessoalmente, penso neles como desejos fixos que habitam a nossa consciĂȘncia junto a outros desejos, mais efĂȘmeros, e que, assim que vocĂȘ os deixa de lado (nem que seja um pouco), inconvenientemente voltam a te atormentar; lembrar que eles ainda estĂŁo lĂĄ e nĂŁo sĂŁo como os outros desejos.</p> +<hr /> +<blockquote> +<p>Esse Ă© o meu foco, pra sempre. Eu nunca tirei isso da mente.</p> +</blockquote> +<p>Palavras minhas. Confesso, me assustam. Ou melhor, me assustavam. O que me assusta mais agora Ă© o fato de eu ter lido isto em menos de um ano depois:</p> +<blockquote> +<p>I’m personally very happy to say that after everything we’ve heard and seen, we think you’re a great match for us and would love for you to join our team here in Berlin.</p> +</blockquote> +<p><em>([
] Pessoalmente, estou muito feliz de dizer que, depois de tudo que nĂłs ouvimos e vimos, achamos que vocĂȘ tem tudo a ver com a gente e gostarĂ­amos que se juntasse ao nosso time aqui em Berlim!)</em></p> +<p>O que seria para sempre o meu foco, o desejo que eu descorri por 30 linhas no meu LG R510 em uma carta de maio de 2012, aquilo que eu nunca havia tirado da mente, naquele momento surgia como uma oportunidade. Eu topei.</p> +<p>Foram vĂĄrios passos antes disso, e eu lembro de estar ansiosa antes de cada um deles. Encontrei pessoas maravilhosas durante o caminho, com um coração tĂŁo grande como o meu. Tanto na vida quanto nessa entrevista em particular.</p> +<p>Nas entrevistas, o processo simplesmente fluiu. Penso e gosto de pensar que Ă© o que acontece quando os aspectos tĂ©cnicos sĂŁo vistos como meros meios necessĂĄrios para aquilo que realmente importa: criar.</p> +<p>Desde aquele momento atĂ© hoje, o dia do meu voo, o tempo pareceu nunca passar em alguns momentos, e, em outros, passar rĂĄpido demais. Mesmo com a percepção confusa do tempo, tenho certeza de que poder enviar a mensagem abaixo Ă© algo que eu nĂŁo imaginava para tĂŁo cedo.</p> +<p class="note"> +<p><em>Just got the call! [
] That’s an important moment of my life for sure. I’m just, you know, happy. Thank you for this.</em></p> +</p> +<p><em>The call</em>. A ligação se referia a do Consulado Geral da Alemanha de Porto Alegre que recebi no dia 8 de maio, dizendo o que esperei 2 semanas (ou toda a minha vida?) para ouvir. <strong>O meu visto estava aprovado.</strong> Ali estava, sem dĂșvidas, um momento importante da minha vida.</p> +<p>Do resto do telefonema, confesso, nĂŁo lembro muito. Minha maior memĂłria desses instantes foi a de andar com o coração cheio atĂ© o centro de Porto Alegre como se fosse a Ășltima vez. E foi, pelo menos por um bom tempo.</p> +<hr /> +<p>Um sonho pode, afinal, terminar de 2 maneiras: sendo abandonado ou realizado.</p> +<p>Meu caso Ă© o segundo, e, sinceramente, nĂŁo estĂĄ fĂĄcil acreditar. Se vocĂȘ me disser que a partir de hoje eu jĂĄ nĂŁo moro mais onde cresci, que meu voo hoje Ă© sĂł de ida, essa informação serĂĄ processada de forma que ela nĂŁo faça sentido na minha realidade. Eu nĂŁo vou acreditar.</p> +<p>Por outro lado, nesse momento da minha vida em que a gratidĂŁo transcende o mĂ©rito, acredito em vĂĄrias outras coisas. A principal Ă© que sou o resultado do fenĂŽmeno que acontece quando a oportunidade encontra o anseio: alguĂ©m, no passado, acreditou em mim; alguĂ©m, no presente, acredita em mim. E eu nĂŁo as deixei decepcionar.</p> +<hr /> +<p>Hoje estou voando para Berlim, a capital da Alemanha, para fazer o que amo na <a href="http://hellofresh.com">HelloFresh</a>, que me ajudou em todo o processo. Sou grata por isso, por tudo.</p> +<p>Quanto Ă  realidade, nĂŁo Ă© que eu nĂŁo tenha medo. Eu tenho. Eu tive medo em todas as vezes que ousei. Desde o primeiro emprego que fui atrĂĄs no Brasil (no tĂ©dio do meu Ensino MĂ©dio), dos projetos alĂ©m do meu conhecimento, atĂ© o meu primeiro emprego fora do Brasil
 eu tive medo em todos eles.</p> +<p>Eu sĂł jamais deixaria o sonho terminar do outro jeito, entĂŁo eu topei tudo mesmo assim.</p> + + + + + Choose Life đŸ‡©đŸ‡Ș + 2017-05-12T19:15:00+00:00 + 2017-05-12T19:15:00+00:00 + + + + + Unknown + + + + + + /blog/choose-life-in-berlin/ + + <p>Choose life. Choose a job. Choose a career. Choose relocation. Choose giving life a <em>fresh</em><sup class="footnote-reference"><a href="#1">1</a></sup> beginning. Choose an one-way flight ticket. Choose fitting your entire life in a 23 kg suitcase. Choose getting rid of all your crap. Choose a higher Human Development Index. Choose being thousands of kilometers far away. Choose devastating your loved ones. Choose different bureaucracies you still don’t understand. Choose calling another place home. Choose not fitting in <em>(you never did anyway!)</em>. Choose saying goodbye to places, food and friends, then choose new places, food, and friends. Choose memories. Choose developing new tastes. Choose being forced to develop social skills. Choose ignorance. Choose mundane and boring activities as exciting adventures. Choose not speaking your mother language. Choose limited self-expression. Choose missing the food from your country, and especially your mum’s. Choose letting part of your heart be elsewhere. Choose adapting 24/7. Choose wondering what the fuck you are doing. And choose getting the answer as soon as you go outside. Choose not understanding jokes from natives. Choose recognising you can do anything, anywhere. Choose not knowing if you should. Choose the bittersweet feeling of moving abroad. Choose to be afraid. Choose your future. Choose life.</p> +<p>But why wouldn’t I want to do a thing like that?</p> +<p>I chose to choose life. And the reasons? There are no reasons. Who needs reasons when you’ve got Berlin?<sup class="footnote-reference"><a href="#2">2</a></sup></p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>See <a href="https://hellofresh.com">HelloFresh</a>, which helped me relocating to Berlin.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>The entire essay is inspired by Mark Renton’s “Choose Life” speech from <a href="http://www.imdb.com/title/tt0117951">Trainspotting</a>, a movie that makes me think a lot about life choices.</p> +</div> + + + + + A Minimal Workspace on macOS + 2017-05-04T19:45:57+00:00 + 2017-05-04T19:45:57+00:00 + + + + + Unknown + + + + + + /blog/a-minimal-workspace-on-macos/ + + <p>Ask me for a screenshot of my desktop and all you get is a wallpaper – if I’m using any. Everything else is hidden, unless actually requested by me.</p> +<p>That’s the way I work on macOS. The minimal way.</p> +<figure class="text-center"><video class="aligncenter" style="padding: 0; width: 100%;" autoplay="autoplay" loop="loop"><source type="video/mp4" src="../../media/2017/macos_desktop.mp4"></video> +<figcaption>My macOS desktop. This + Spotlight = life. 😎</figcaption></figure> +<p>In my workspace, there are no desktop items, app icons, time clock, battery percentage, transition delays, distracting animations, dashboards or context menus.</p> +<p>Too much information makes it easy for me to get stimulated and then distracted. So I like it minimal.</p> +<h2 id="recipe-for-the-minimal-ok-hand">Recipe for the minimal 👌</h2> +<p><strong>Get rid of everything you can</strong>. Hide. Disable. Assume everything is useless, not useful. <em>(I actually use this approach for life.)</em></p> +<p>You’ll get frustrated sometimes, because there are simple things you want so bad to get rid of but then found out it’s impossible unless you hack things. SRLSY GOTTA LOVE APPLE 😍😍😍</p> +<p>Well, let’s begin! Follow the steps below and type the commands in a <strong>terminal</strong>. If you’re not familiar with a terminal, I’m pretty sure it’s possible to find those settings in “System Preferences” as well.</p> +<p><em>(
But I highly recommend you to open a terminal and start typing around because SRSLY USING A TERMINAL IS LIKE KNOWLEDGE AND POWER 4 UR ENTIRE LIFE!!!!!!!!)</em></p> +<h3 id="hide-your-desktop">Hide your desktop</h3> +<p>It’s easier to live without than to live with it. Disable it and it won’t be something you have to clean up anymore!</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">defaults</span><span> write com.apple.finder CreateDesktop</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> false +</span></code></pre> +<h3 id="hide-your-dock">Hide your dock</h3> +<p>It’ll be only shown when you hover it.</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock autohide</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span></code></pre> +<p>Other cool things you can do too to keep your dock clean are:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#6272a4;"># Minimize windows into their application&#39;s icon +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock minimize-to-application</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span><span> +</span><span style="color:#6272a4;"># Wipe all (default) app icons from the Dock +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock persistent-apps</span><span style="font-style:italic;color:#ffb86c;"> -array +</span></code></pre> +<p>Because I initialise apps from Spotlight, I really don’t mind not having any app in my dock. Sometimes I ask myself why do I have a dock at all. đŸ€”</p> +<p>And
 Launchpad. WHY?????? 😭</p> +<h3 id="hide-your-menu-bar">Hide your menu bar</h3> +<p>It’ll be only shown when you hover it.</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">defaults</span><span> write NSGlobalDomain _HIHideMenuBar</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span></code></pre> +<p class="note">I really like this one, but if you feel it's too radical for you, try hiding only menu bar icons with <a href="(http://matthewpalmer.net/vanilla/">Vanilla</a> (recommended) or <a href="https://www.macbartender.com">Bartender</a>.</p> +<h3 id="disable-dashboard">Disable dashboard</h3> +<p>Why does it even exist? 😒</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#6272a4;"># Disable Dashboard +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dashboard mcx-disabled</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span><span> +</span><span style="color:#6272a4;"># Don&#39;t show Dashboard as a Space +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock dashboard-in-overlay</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span></code></pre> +<h3 id="disable-and-or-speed-up-animations">Disable and/or speed up animations</h3> +<p>Saving some time because I don’t think those really add anything to my user experience on macOS.</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#6272a4;"># Disable window animations and Get Info animations +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.finder DisableAllAnimations</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> true +</span><span> +</span><span style="color:#6272a4;"># Remove the auto-hiding Dock delay +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock autohide-delay</span><span style="font-style:italic;color:#ffb86c;"> -float</span><span> 0 +</span><span> +</span><span style="color:#6272a4;"># Remove the animation when hiding/showing the Dock +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock autohide-time-modifier</span><span style="font-style:italic;color:#ffb86c;"> -float</span><span> 0 +</span><span> +</span><span style="color:#6272a4;"># Don&#39;t animate opening applications from the Dock +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock launchanim</span><span style="font-style:italic;color:#ffb86c;"> -bool</span><span> false +</span><span> +</span><span style="color:#6272a4;"># Speed up Mission Control animations +</span><span style="color:#50fa7b;">defaults</span><span> write com.apple.dock expose-animation-duration</span><span style="font-style:italic;color:#ffb86c;"> -float</span><span> 0.1 +</span></code></pre> +<p>Finally, restart system stuff:</p> +<pre data-lang="bash" style="background-color:#282a36;color:#f8f8f2;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#50fa7b;">killall</span><span> Finder</span><span style="color:#ff79c6;">; </span><span style="color:#50fa7b;">killall</span><span> Dock</span><span style="color:#ff79c6;">; </span><span style="color:#50fa7b;">killall</span><span> SystemUIServer +</span></code></pre> +<p>And that’s it! 🎉 Life-changing commands for sure. Now just don’t forget cleaning your actual desk too.</p> +<p>For more on the way I work, <a href="http://github.com/diessica/dotfiles">my dotfiles</a> are worth-checking!</p> +<p class="note">Sorry for using too many emojis. Just shipped this feature here on my blog and I can't help myself! 😬</p> + + + + + I Travelled to Photographs + 2017-04-19T10:13:00+00:00 + 2017-04-19T10:13:00+00:00 + + + + + Unknown + + + + + + /blog/archive/i-travelled-to-photographs/ + + <p>February was ending.</p> +<p>Usually, such thing would mean regular summer days. However, it wasn’t summer or even a regular day – this was something else.</p> +<p>February 25th was winter. In that cold afternoon, I ended up into a place I’ll never forget: photographs from my phone’s gallery.</p> +<hr /> +<p>My steps were slow.</p> +<p>Red bricks erected the walls of houses built on top of an equally red-bricked avenue.</p> +<p>The windows of the houses were made of a wood strategically white-colored to match the brick’s white grouts. With such detail, it was pretty easy to forgive the toughness those bricks carried.</p> +<p>Houses ended themselves in grey roofing shingles. The roofs were all hipped. <em>Houses with hip roofs, gotta love them!</em>, I thought to myself. (Imagine the “V” letter upside down on top of a square – that’s a house with a hip roof.)</p> +<p>Showing a winter that was already leaving, dark trees with dry twigs were in contrast against a white sky – the whitest I’d ever seen in my life. <em>Damn!</em> The whole picture looked like a painting, while the white sky worked as the canvas board on which all that was drawn.</p> +<p>I remember walking and trying to get everything I could, until a freezing wind blew abruptly into my face. It was February, though. From where I come, February meant summer, not freezing winds. Why was February that cold?</p> +<p>In an attempt to clear things up, I told myself what I believed that was true: <em>You’re just looking at photographs from your phone’s gallery. There’s no need to get this excited!</em> Ok. So I was home and looking at the “Wallpapers” album I had on my phone.</p> +<p>A moment later, I found myself facing a large and wonderful canal, in which someone was solitary paddling a boat to somewhere. <em>What a view.</em></p> +<p>Then, self-awareness hit me again: <em>Wait. Isn’t my smartphone in my pocket?</em> How could I be possibly looking at photographs on it?</p> +<p>I immediately started touching my entire body in a desperate hunt for my phone. And there it was. In my fucking coat. It wasn’t really possible for me to see photographs on my phone – that shit was in my pocket all the time.</p> +<p>Besides, why would I be wearing a coat on summer? And, if I was already wearing a coat, how could I be still cold? How inappropriate were my clothes for that weather? Only a person who sensed that winter solely with the eyes would underestimate its coldness like that!</p> +<p>The boat was really leaving through the canal. The view wasn’t photographs. What was all that, then?</p> +<p>I got my phone from my pocket, turned off airplane mode, and opened the Maps app. <em>Come on, where am I?</em></p> +<p>“Noorder Amstelkanaal”, I read. <em>Wow.</em></p> +<p>All of a sudden, February 25th was a cold winter in Amsterdam. My very first one.</p> +<figure class="text-center"><picture><source media="(min-width: 63.125rem)" srcset="../../media/2017/noorder-amstelkanaal.jpg"><source media="(min-width: 45rem)" srcset="../../media/2017/noorder-amstelkanaal.jpg 2x, ../../media/2017/noorder-amstelkanaal_medium.jpg 1x" ><source media="(max-width: 45rem)" srcset="../../media/2017/noorder-amstelkanaal.jpg 2x, ../../media/2017/noorder-amstelkanaal_medium.jpg 1x"><img srcset="../../media/2017/noorder-amstelkanaal.jpg 2x, ../../media/2017/noorder-amstelkanaal_small.jpg 1x" alt="Noorder Amstelkanaal"></picture> +<figcaption>Someone solitary paddling a boat to somewhere in Noorder Amstelkanaal, an Amsterdam's canal.</figcaption></figure> +<p>I guess I travelled to photographs.</p> + + + + + Catalysis + 2017-04-13T11:27:00+00:00 + 2017-04-13T11:27:00+00:00 + + + + + Unknown + + + + + + /blog/catalysis/ + + <p>As a High School student, I remember always finding Chemistry something between the boring and intriguing. Still, it isn’t hard to find myself wondering about the science concepts I’ve learned at that time.</p> +<p>Lately, I’ve been particularly thinking about <em>catalysis</em>.</p> +<hr /> +<p>In Chemistry, catalysis is the acceleration of a reaction due to the participation of a substance – the “catalyst”.</p> +<p>The way a catalyst induces a reaction to happen faster is intriguing. Curiously, it neither gives the reaction more energy nor change its environmental conditions. Catalysts have an even better strategy: they <strong>lower the amount of energy required</strong> for the reaction to take place.</p> +<figure class="text-center"><picture><img src="../../media/2017/catalysis-diagram.png" srcset="../../media/2017/catalysis-diagram_2x.png 2x" alt="Diagrama representando conhecimento como ele realmente Ă©"></picture> +<figcaption>Uncatalyzed reaction (solid) vs. catalyzed reaction (dashed). The highest point is the energy required for the reaction to happen. </figcaption></figure> +<p>In a catalysed reaction, then, the same product is obtained for less energy. Bringing this concept to our lives is quite thought-provoking.</p> +<p>Sometimes it isn’t possible for us to achieve something because it demands <em>more</em> time or energy than what we currently have. To deal with this, we then try looking for them in our lives – which mostly means depriving yourself of things.</p> +<p>However, matter of fact is that optimising isn’t always about getting rid of things in your life. If we think of catalysis, we can manage it differently.</p> +<p>What if the problem weren’t the lack of energy or time, but that we’re in need of <em>too much</em> of them in order to get things done? <strong>Having a catalyst would totally figure it out</strong>. Without something that pushes us forward, we’ll always require more energy for the product we want to get.</p> +<p>At this point, you may think your catalyst is your motivation. Motivation is out of our control though – which makes it a goal, not a source. It’s also too ephemeral, and a catalyst mustn’t ever be consumed by an unique reaction, just like in Chemistry. We can’t count on being motivated!</p> +<p>So it goes more like what <em>habitual and practical</em> things in life would give you productivity for less. Is it everyday meditation? A partner by your side? Self-confidence? Inspiring weekends without thinking of work at all? Eating healthy? Going out for a walk every day?</p> +<p>You have to mind what pushes your forward. Catalysts themselves cannot make a reaction happen that wouldn’t happen on its own, but they sure make it occur under less extreme conditions. It’s an improvement when you’re already motivated.</p> +<p>So, what’s your catalyst?</p> + + + + + Don't Blame it on React or Redux + 2017-03-18T13:49:00+00:00 + 2017-03-18T13:49:00+00:00 + + + + + Unknown + + + + + + /blog/dont-blame-it-on-react-or-redux/ + + <p>What most people don’t know when they first get into Redux is that, just like React, Redux itself is meant to be <strong>simple</strong>. And as seen that simplicity is a goal, both React and Redux <em>won’t</em> and <em>don’t want</em> to tell you how to solve everything.</p> +<p>They won’t tell you how to deal with side effects, or what HTTP request library you should use. That’s completely delegated to the JavaScript ecosystem.</p> +<p><strong>React and Redux alone don’t do much for really complex web applications.</strong></p> +<p>React indirectly delegates state management problems to solutions like Flux. On the other hand, Redux, for instance, delegates dealing with async stuff or even the <em>too-much-boilerplate</em> problem that people complain.</p> +<p>But <strong>what motivates React and Redux to be that way?</strong> Some reasons I can think of are:</p> +<ul> +<li>Both libraries are highly focused on their principles, not the built-in stuff. The efficiency of them is on the <em>why</em> and <em>how</em>, not the <em>what</em>.</li> +<li>They aim to be a great fit for both simple <em>and</em> large applications, so the “plug-in-play” approach is followed. (A framework wouldn’t ever do everything a programmer needs anyway
)</li> +<li>Diversity of solutions. Because React and Redux are more like “plug-in-play”, the “plugins” (tools, libraries, middlewares) will evolve by themselves. For instance: <a href="https://github.com/mzabriskie/axios">axios</a>, a HTTP request library, will evolve in parallel to Redux itself – which certainly make things move forward faster!</li> +</ul> +<hr /> +<p>If your application’s state is messy, don’t blame it on React. If you find yourself writing too much boilerplate, don’t blame it on Redux. <strong>React and Redux don’t really do much</strong>, but this is by design.</p> +<p>React is awesome not just because it makes it possible to turn a large and complex application into simple components.</p> +<p>Redux is awesome not just because it makes it effortless to deal with and share state throughout an application.</p> +<p>They’re also awesome because of <strong>their great and diverse ecosystem</strong>. So, when you buy into React or Redux, it’s better for you to buy into their ecosystem too.</p> + + + + + var that = this? Nah. + 2017-03-15T09:00:00+00:00 + 2017-03-15T09:00:00+00:00 + + + + + Unknown + + + + + + /blog/var-that-this-nah/ + + <p>Tried JavaScript for some minutes? You probably already wrote the following.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">var </span><span style="color:#ffffff;">that </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">this</span><span>; +</span></code></pre> +<p>(Or one of its variants, such as <code>var self = this</code>.)</p> +<p>That’s a pretty common pattern when you found yourself in a situation where:</p> +<ol> +<li>you have a function nested inside of an object’s method, and</li> +<li>you want to access the object’s properties, but</li> +<li>JavaScript’s <code>this</code> is bound in an unexpected way.</li> +</ol> +<hr /> +<p>Workarounding unexpected callback scope is one of the main situations where developers write <code>var self = this</code>.</p> +<p>Let’s assume a piece of code with a callback function.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">function </span><span style="color:#50fa7b;">Requester</span><span>(</span><span style="font-style:italic;color:#ffb86c;">data</span><span>, </span><span style="font-style:italic;color:#ffb86c;">req</span><span>) { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">data</span><span>; +</span><span> +</span><span> </span><span style="color:#ffffff;">req</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">done</span><span>(</span><span style="font-style:italic;color:#8be9fd;">function </span><span>() { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data); </span><span style="color:#6272a4;">// undefined +</span><span> }); +</span><span>} +</span></code></pre> +<p>You’d expect <code>this.data</code> to be the <code>data</code> argument. Yet, JavaScript tells you that it is actually <code>undefined</code>.</p> +<p>So, because Stack Overflow says so, you do the following:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">function </span><span style="color:#50fa7b;">Requester</span><span>(</span><span style="font-style:italic;color:#ffb86c;">data</span><span>, </span><span style="font-style:italic;color:#ffb86c;">req</span><span>) { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">data</span><span>; +</span><span> </span><span style="font-style:italic;color:#8be9fd;">var </span><span style="color:#ffffff;">self </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">this</span><span>; </span><span style="color:#6272a4;">// NOOOOOoOooo +</span><span> +</span><span> </span><span style="color:#ffffff;">req</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">done</span><span>(</span><span style="font-style:italic;color:#8be9fd;">function </span><span>() { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">self</span><span style="color:#ff79c6;">.</span><span>data); +</span><span> }); +</span><span>} +</span></code></pre> +<p>And never stops doing it in your life.</p> +<p>Still do it? I’m flattered to tell you that <strong>you don’t need that extra variable anymore</strong>.</p> +<h2 id="arrow-functions">Arrow functions</h2> +<p>Go with <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">arrow functions</a> instead. Besides having a shorter syntax, arrow functions bind to the parent scope by default.</p> +<p>The scope that was firstly intuitive to you will work as expected now.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">function </span><span style="color:#50fa7b;">Requester</span><span>(</span><span style="font-style:italic;color:#ffb86c;">data</span><span>, </span><span style="font-style:italic;color:#ffb86c;">req</span><span>) { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">data</span><span>; +</span><span> +</span><span> </span><span style="color:#ffffff;">req</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">done</span><span>(() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data); </span><span style="color:#6272a4;">// intuitive as hell! +</span><span> }); +</span><span>} +</span></code></pre> +<p class="note">You can count on them most of the time, but they also have unexpected behaviour in more advanced cases. After all, you're dealing with the `this` keyword. So don't just go around refactoring all anonymous functions into arrow ones and expecting everything to work.</p> +<h2 id="you-may-also-bind">You may also <code>.bind()</code>!</h2> +<p>If for some reason (such as <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Browser_compatibility">no support for IE</a>) you can’t use them, check JavaScript’s <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind"><code>bind</code></a>. It’s not as awesome as arrow functions, but does the job.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">function </span><span style="color:#50fa7b;">Requester</span><span>(</span><span style="font-style:italic;color:#ffb86c;">data</span><span>, </span><span style="font-style:italic;color:#ffb86c;">req</span><span>) { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">data</span><span>; +</span><span> +</span><span> </span><span style="color:#ffffff;">req</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">done</span><span>( +</span><span> </span><span style="font-style:italic;color:#8be9fd;">function </span><span>() { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>data); +</span><span> }</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">bind</span><span>(</span><span style="color:#bd93f9;">this</span><span>) +</span><span> ); +</span><span>} +</span></code></pre> + + + + + Shared Variables Between JavaScript and CSS + 2017-01-15T15:00:00+00:00 + 2017-01-15T15:00:00+00:00 + + + + + Unknown + + + + + + /blog/shared-variables-between-javascript-and-css/ + + <p>Because it assures consistency throughout the project and avoids <a href="https://en.m.wikipedia.org/wiki/Magic_number_(programming)">magic numbers</a>, sharing variables between JavaScript and CSS code may help you to keep your project codebase tidy and easier to reason about.</p> +<p class="note"> +<p>For this article, when talking about CSS, the word “variable” may mean <a href="https://www.w3.org/TR/css-variables/">custom property</a> or <a href="https://www.w3.org/TR/2016/WD-mediaqueries-4-20160126/#custom-mq">custom media query</a>.</p> +</p> +<h2 id="getting-started">Getting Started</h2> +<p>First, create a <strong>object</strong> containing your variables and export it.</p> +<p>My JS file containing the object will be called <code>variables.js</code>.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">export default </span><span>{ +</span><span> mainColor: </span><span style="color:#f1fa8c;">&quot;#000&quot;</span><span>, +</span><span> secondaryColor: </span><span style="color:#f1fa8c;">&quot;#fff000&quot;</span><span>, +</span><span> fullHeight: </span><span style="color:#f1fa8c;">&quot;100vh&quot;</span><span>, +</span><span>}; +</span></code></pre> +<p>No magic is needed to use those variables in your JS files – just <code>import</code> them when you need it. But in order to communicate those variables to your CSS files and use them with <code>var()</code>, some magic is needed.</p> +<p>For this, I will be using <a href="http://cssnext.io/">cssnext</a>, a PostCSS plugin, and injecting that object into our stylesheets as <strong>custom properties</strong>.</p> +<p>Webpack example:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">cssNext </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;postcss-cssnext&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">myVars </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./variables&quot;</span><span>; +</span><span> +</span><span style="font-style:italic;color:#66d9ef;">module</span><span style="color:#ff79c6;">.</span><span style="font-style:italic;color:#66d9ef;">exports </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> </span><span style="color:#6272a4;">// Entry, loaders, plugins... +</span><span> +</span><span> </span><span style="color:#50fa7b;">postcss</span><span>: () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>[ +</span><span> </span><span style="color:#50fa7b;">cssNext</span><span>({ +</span><span> features: { +</span><span> customProperties: { variables: </span><span style="color:#ffffff;">myVars </span><span>}, +</span><span> }, +</span><span> }), +</span><span> ], +</span><span>}; +</span></code></pre> +<p class="note"> +<p>Since I’m just using <a href="https://github.com/MoOx/postcss-cssnext">postcss-cssnext</a> API, it’s also possible to do it with the build tool of your choice. Check <a href="http://cssnext.io/usage/#features">docs on passing options to cssnext features</a>.</p> +</p> +<h2 id="getting-real-world-with-breakpoints">Getting Real-world with Breakpoints</h2> +<p>Sharing breakpoints between JavaScript and your stylesheets is a great real-world example.</p> +<p>It’s time for <code>variables.js</code> to grow then!</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">export </span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">properties </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> mainColor: </span><span style="color:#f1fa8c;">&quot;#000&quot;</span><span>, +</span><span> secondaryColor: </span><span style="color:#f1fa8c;">&quot;#fff000&quot;</span><span>, +</span><span> fullHeight: </span><span style="color:#f1fa8c;">&quot;100vh&quot;</span><span>, +</span><span>}; +</span><span> +</span><span style="color:#ff79c6;">export </span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">mediaQueries </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> secondaryColor: </span><span style="color:#f1fa8c;">&quot;#fff000&quot;</span><span>, +</span><span> desktop: </span><span style="color:#f1fa8c;">&quot;(min-width: 1024px)&quot;</span><span>, +</span><span> tablet: </span><span style="color:#f1fa8c;">&quot;(min-width: 768px)&quot;</span><span>, +</span><span> mobile: </span><span style="color:#f1fa8c;">&quot;(min-width: 320px)&quot;</span><span>, +</span><span>}; +</span></code></pre> +<p>Because it’s not possible to create a media query containing a custom property, we need to inject <code>mediaQueries</code> as <strong>custom media queries</strong>.</p> +<p>Let’s update the previous Webpack example in order to let cssnext to know about both custom media queries and properties.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">cssNext </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;postcss-cssnext&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">properties</span><span>, </span><span style="color:#ffffff;">mediaQueries </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./variables&quot;</span><span>; +</span><span> +</span><span style="font-style:italic;color:#66d9ef;">module</span><span style="color:#ff79c6;">.</span><span style="font-style:italic;color:#66d9ef;">exports </span><span style="color:#ff79c6;">= </span><span>{ +</span><span> </span><span style="color:#6272a4;">// Entry, loaders, plugins... +</span><span> +</span><span> </span><span style="color:#50fa7b;">postcss</span><span>: () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>[ +</span><span> </span><span style="color:#50fa7b;">cssNext</span><span>({ +</span><span> features: { +</span><span> customProperties: { variables: </span><span style="color:#ffffff;">properties </span><span>}, +</span><span> customMedia: { extensions: </span><span style="color:#ffffff;">mediaQueries </span><span>}, +</span><span> }, +</span><span> }), +</span><span> ], +</span><span>}; +</span></code></pre> +<p>Done! Some usage examples for CSS, JS and even React are provided below.</p> +<h3 id="usage">Usage</h3> +<h4 id="css-example">CSS Example</h4> +<p>Using custom properties and custom media queries according to settings from <code>variables.js</code> file.</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#50fa7b;">.banner </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">background</span><span>: </span><span style="color:#6be5fd;">red</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">height</span><span>: </span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--fullHeight</span><span>); </span><span style="color:#6272a4;">/* Custom property */ +</span><span> +</span><span> @media (</span><span style="font-style:italic;color:#66d9ef;">--desktop</span><span>) { +</span><span> </span><span style="color:#6272a4;">/* Custom media query */ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">width</span><span>: </span><span style="color:#bd93f9;">50</span><span style="color:#ff79c6;">%</span><span>; +</span><span> } +</span><span>} +</span></code></pre> +<h4 id="javascript-example">JavaScript example</h4> +<p class="note"> +<p>Example below uses <a href="http://wicky.nillia.ms/enquire.js/">enquire.js</a> library.</p> +</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">enquire </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;enquire.js&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">customMedia </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./variables&quot;</span><span>; +</span><span> +</span><span style="color:#ffffff;">enquire +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">register</span><span>(</span><span style="color:#ffffff;">customMedia</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">tablet</span><span>, () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Matched tablet resolution&quot;</span><span>); +</span><span> }) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">register</span><span>(</span><span style="color:#ffffff;">customMedia</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">mobile</span><span>, () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Matched mobile resolution&quot;</span><span>); +</span><span> }); +</span></code></pre> +<h4 id="react-example">React example</h4> +<p>Rendering a component only on desktop resolutions.</p> +<p class="note"> +<p>Example below uses <a href="https://github.com/contra/react-responsive">react-responsive</a> library.</p> +</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">MediaQuery </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react-responsive&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">customMedia </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./variables&quot;</span><span>; +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">function </span><span style="color:#50fa7b;">DesktopOnlyComponent</span><span>() { +</span><span> </span><span style="color:#6272a4;">/* (min-width: 1024px), according to variables.js */ +</span><span> +</span><span> </span><span style="color:#ff79c6;">return </span><span>( +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">MediaQuery </span><span style="color:#50fa7b;">query</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">customMedia</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">desktop</span><span style="color:#ff79c6;">}</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;My desktop-only component!&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> &lt;/</span><span style="font-style:italic;color:#66d9ef;">MediaQuery</span><span>&gt; +</span><span> ); +</span><span>} +</span></code></pre> +<h2 id="final-words">Final Words</h2> +<p>A non-consistent front-end codebase is just messy.</p> +<p>I really use this technique on everyday work, and it’s a cheap way to significantly improve the quality of the front-end codebase.</p> +<p>So, don’t underestimate it! Besides breakpoints, there are infinite possibilities for this, such as project colors, layout dimensions and other shared stuff that can easily get out of hand while working on a large project.</p> + + + + + How to Exclude CSS, Images, Anything from Unit Tests + 2016-11-19T09:54:29+00:00 + 2016-11-19T09:54:29+00:00 + + + + + Unknown + + + + + + /blog/how-to-exclude-css-images-anything-from-unit-tests/ + + <div class="summary"> +<p>Your app needs all those <code>require</code>, but your unit tests may not.</p> +</div> +<p>When developing web applications, we deal with assets that our JavaScript tests don’t have to be aware of.</p> +<p>If using Webpack, which enables different imports in your JavaScript files, you’ve configured <a href="https://webpack.github.io/docs/loaders.html">loaders</a> that your test runner probably know nothing about. Therefore, that SVG image in your React component and the <code>import</code>ed CSS will both be parsed like JavaScript in your tests. A lot of confusing errors will be thrown, of course.</p> +<p>So let’s learn to exclude anything your unit tests, from styles (CSS, Sass), images (PNG, SVG), to other specific imports (like <a href="https://diessi.ca/blog/svg-images-as-react-components-with-webpack/">SVG images as React components</a>).</p> +<h2 id="hook-your-require-calls">Hook your <code>require()</code> calls</h2> +<p>By intercepting <code>require()</code> calls, you can make your testing framework ignore <strong>what you want</strong> to be ignored <strong>the way you want</strong> it to be ignored.</p> +<p>It’s also useful in isomorphic setups.</p> +<h3 id="return-an-empty-module">Return an empty module</h3> +<p>It all comes to returning an empty module for unwanted imports. It looks like this:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#66d9ef;">module</span><span style="color:#ff79c6;">.</span><span style="font-style:italic;color:#66d9ef;">exports </span><span style="color:#ff79c6;">= </span><span style="color:#f1fa8c;">&quot;&quot;</span><span>; +</span></code></pre> +<h3 id="jest">Jest</h3> +<p>For Jest, configure <a href="https://facebook.github.io/jest/docs/configuration.html#modulenamemapper-object-string-string">moduleNameMapper</a> to return the empty module for specific extensions. Example:</p> +<pre data-lang="json" style="background-color:#282a36;color:#f8f8f2;" class="language-json "><code class="language-json" data-lang="json"><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">jest</span><span style="color:#eeeeee;">&quot;</span><span>: { +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">moduleNameMapper</span><span style="color:#eeeeee;">&quot;</span><span>: { +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#ff79c6;">\\</span><span style="color:#f1fa8c;">.(css|jpg|png)$</span><span style="color:#eeeeee;">&quot;</span><span>: </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">&lt;rootDir&gt;/empty-module.js</span><span style="color:#eeeeee;">&quot; +</span><span> } +</span><span>} +</span></code></pre> +<h3 id="other-testing-frameworks">Other testing frameworks</h3> +<p><a href="https://www.npmjs.com/package/require-hacker">require-hacker</a> is an option for hooking <code>require()</code> calls.</p> +<p class="note"> +<p>You can also use built-in compilers (like moduleNameMapper in Jest or <a href="https://mochajs.org/#compilers">Mocha compilers</a>), or even only import <a href="https://github.com/bkonkle/ignore-styles">ignore-styles</a> into your testing framework (which is preconfigured).</p> +</p> +<p>I’ll stick to require-hacker and custom configuration because there’s more flexibility.</p> +<p>Get it from npm:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">npm</span><span> install require-hacker</span><span style="font-style:italic;color:#ffb86c;"> --save-dev +</span></code></pre> +<h4 id="configure">Configure</h4> +<p>Create a JavaScript file and set custom handlers for specific extensions using require-hacker’s <a href="https://github.com/halt-hammerzeit/require-hacker#hookfile_extension-resolve">hook()</a> method.</p> +<p>Assuming you want to ignore CSS and PNG files, always return an empty module for them:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">requireHacker </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;require-hacker&quot;</span><span>; +</span><span style="color:#ffffff;">requireHacker</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">hook</span><span>(</span><span style="color:#f1fa8c;">&quot;png&quot;</span><span>, () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#f1fa8c;">&#39;module.exports = &quot;&quot;&#39;</span><span>); +</span><span style="color:#ffffff;">requireHacker</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">hook</span><span>(</span><span style="color:#f1fa8c;">&quot;css&quot;</span><span>, () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#f1fa8c;">&#39;module.exports = &quot;&quot;&#39;</span><span>); +</span></code></pre> +<p class="note"> +<p>Because you’re smart, you’ll store all extensions in a variable and <code>forEach</code> them, so there’s no need to repeat yourself. <a href="https://gist.github.com/diessica/e6a6ea601d2b19cdcc6881197b6b5c8d">Example</a>.</p> +</p> +<h4 id="import-into-your-test-runner">Import into your test runner</h4> +<p>Let your favourite testing framework know about the <code>require</code> hacking! Some examples, assuming a <code>ignore-utils.js</code> file:</p> +<h5 id="mocha">Mocha</h5> +<p>Add to your <a href="https://mochajs.org/#mochaopts">mocha.opts</a>, or use the <code>--require</code> flag:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">mocha</span><span style="font-style:italic;color:#ffb86c;"> --require</span><span> ./ignore-utils +</span></code></pre> +<h5 id="ava">ava</h5> +<p>Add to your <code>package.json</code>:</p> +<pre data-lang="json" style="background-color:#282a36;color:#f8f8f2;" class="language-json "><code class="language-json" data-lang="json"><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">ava</span><span style="color:#eeeeee;">&quot;</span><span>: { +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">require</span><span style="color:#eeeeee;">&quot;</span><span>: [ +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">./ignore-utils</span><span style="color:#eeeeee;">&quot; +</span><span> ] +</span><span>} +</span></code></pre> +<p>Now some files will be treated like shit in your JavaScript tests – which is AWESOME!</p> +<h2 id="bonus-react-null-component">Bonus: React null component</h2> +<p>You don’t need to load that boring SVG icon of a house to test that critical feature in a React component, right?</p> +<p><em>Right.</em> In case you’re using <a href="https://github.com/sairion/svg-inline-loader">svg-inline-loader</a>, which transform your SVG files into React components, you cannot just return an empty module because your test case would be actually expecting a React component. Things will break. Annoying errors will be shown.</p> +<p>So, instead of returning an empty module for SVG files, return an empty React component. Let’s set a custom handler for that!</p> +<h3 id="configure-1">Configure</h3> +<p class="note"> +<p>This example uses require-hacker. For Jest, export a React null component and set it in <code>moduleNameMapper</code>.</p> +</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">requireHacker </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;require-hacker&quot;</span><span>; +</span><span> +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">reactNullComponent </span><span style="color:#ff79c6;">= </span><span style="color:#f1fa8c;">` +</span><span style="color:#f1fa8c;"> require(&#39;react&#39;).createClass({ +</span><span style="color:#f1fa8c;"> render() { +</span><span style="color:#f1fa8c;"> return null; +</span><span style="color:#f1fa8c;"> } +</span><span style="color:#f1fa8c;"> }) +</span><span style="color:#f1fa8c;">`</span><span>; +</span><span style="color:#ffffff;">requireHacker</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">hook</span><span>(</span><span style="color:#f1fa8c;">&quot;svg&quot;</span><span>, () </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="color:#f1fa8c;">`module.exports = ${</span><span style="color:#ffffff;">reactNullComponent</span><span style="color:#f1fa8c;">}`</span><span>); +</span></code></pre> +<h2 id="conclusion">Conclusion</h2> +<p>I’ve spent a lot of time figuring out how to make everything work, because:</p> +<ol> +<li>At the beginning, it was quite confusing to get what was clearly going on.</li> +<li>There’s a ton of options out there (Webpack null loaders; <a href="https://github.com/bkonkle/ignore-styles">ignore-styles</a>, which also provide custom handlers; <a href="https://github.com/morlay/babel-plugin-transform-require-ignore">babel-plugin-transform-require-ignore</a>
).</li> +<li>I didn’t want to handle all the ignored extensions the same say.</li> +</ol> +<p>Yeah
 Sometimes our JavaScript unit tests just know too much.</p> + + + + + A Bit on Random Numbers in JavaScript + 2016-11-15T16:50:00+00:00 + 2016-11-15T16:50:00+00:00 + + + + + Unknown + + + + + + /blog/a-bit-on-random-numbers-in-javascript/ + + <p><code>Math.random()</code> is a JavaScript function that outputs a random number in the range <code>[0, 1)</code> (from 0 up to 1, but doesn’t include 1). It’s the main source of randomness in JavaScript.</p> +<p>Although the output looks random, it’s actually not.</p> +<h2 id="behind-the-scenes">Behind the Scenes</h2> +<p><code>Math.random()</code> uses a <strong>pseudo-random number generator</strong> (PRNG). Those algorithms work completely determined by a initial value called “seed”.</p> +<blockquote> +<p>Given a seed, the sequence of random numbers is deterministic.</p> +</blockquote> +<p>Every PRNG requires a seed, which <em>generally</em> is the current system time in milliseconds. Yeah, simple as that.</p> +<p>Speaking of JavaScript language, the PRNG algorithm to deal with the seed is left up to implementors<sup class="footnote-reference"><a href="#1">1</a></sup>. The algorithm powering V8’s <code>Math.random()</code> was very poor quality until last year (2015), and implementations between engines were pretty inconsistent.</p> +<p>But the scenario has changed. Currently, JavaScript Engines such as SpiderMonkey, V8, Webkit and Chakra all implements <a href="https://en.wikipedia.org/wiki/Xorshift">Xorshift128+</a> algorithm<sup class="footnote-reference"><a href="#2">2</a></sup>, faster than the previous one.</p> +<h2 id="secure-randomness">Secure Randomness</h2> +<p>Although randomness was improved in most JavaScript engines, it isn’t trustworthy as seen that standard PRNGs are highly predictable after a certain period. That’s where Web Crypto API shines!</p> +<p><a href="https://www.w3.org/TR/WebCryptoAPI/">Web Cryptography API</a> introduces <code>window.crypto.getRandomValues</code>, a cryptographically secure pseudo-random number generator (CSPNG), whose output is impossible or highly improbable to distinguish from a truly random one.</p> +<h3 id="example">Example</h3> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#6272a4;">// Array containing two 32-bit integers +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">arr </span><span style="color:#ff79c6;">= new </span><span>Int32Array(</span><span style="color:#bd93f9;">2</span><span>); +</span><span> +</span><span style="color:#6272a4;">// Override array integers with random values +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">random </span><span style="color:#ff79c6;">= </span><span style="color:#ffffff;">crypto</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">getRandomValues</span><span>(</span><span style="color:#ffffff;">arr</span><span>); +</span><span> +</span><span style="color:#ff79c6;">for </span><span>(</span><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">i </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">0</span><span>; </span><span style="color:#ffffff;">i </span><span style="color:#ff79c6;">&lt; </span><span style="color:#ffffff;">random</span><span style="color:#ff79c6;">.</span><span>length; </span><span style="color:#ffffff;">i</span><span style="color:#ff79c6;">++</span><span>) { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">random</span><span>[</span><span style="color:#ffffff;">i</span><span>]); +</span><span>} +</span></code></pre> +<p class="note">Of course it comes at a performance cost, so make sure you really need secure random numbers in your program.</a> +<h2 id="conclusion">Conclusion</h2> +<p>If you need apparent randomness–less and speed, you’d probably better off using <code>Math.random()</code>. If you need high-quality randomness, such as in cryptography applications, hashing or statistics, go for a CSPNG such as <code>window.crypto.getRandomValues</code> instead.</p> +<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup> +<p>See <a href="https://tc39.github.io/ecma262/#sec-math.random">ES2015 spec on <code>Math.random()</code></a>.</p> +</div> +<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup> +<p>Sources: <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=322529">SpiderMonkey</a>, <a href="http://v8project.blogspot.com.br/2015/12/theres-mathrandom-and-then-theres.html">V8</a>, <a href="https://bugs.webkit.org/show_bug.cgi?id=151641">Webkit</a>, <a href="https://github.com/Microsoft/ChakraCore/pull/145">Chakra</a>.</p> +</div> + + + + + Horizontal and Vertical Align Anything with CSS + 2016-11-06T19:10:01+00:00 + 2016-11-06T19:10:01+00:00 + + + + + Unknown + + + + + + /blog/horizontal-and-vertical-align-anything-with-css/ + + <p>Using <code>translate()</code> is one of the easiest ways^[Flexbox also provides a great solution. See <a href="https://philipwalton.github.io/solved-by-flexbox/demos/vertical-centering/">Solved by Flexbox: Vertical Centering</a>] to instantly horizontal and vertical align any element with CSS without knowing its dimensions.</p> +<h2 id="vertical-align">Vertical Align</h2> +<p>You probably know the “<a href="http://zerosixthree.se/vertical-align-anything-with-just-3-lines-of-css/">vertical align with just 3 lines of CSS</a>” trick, which uses <code>translateY()</code>.</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#50fa7b;">.my-element </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">position</span><span>: </span><span style="color:#6be5fd;">absolute</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">top</span><span>: </span><span style="color:#bd93f9;">50</span><span style="color:#ff79c6;">%</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">transform</span><span>: </span><span style="color:#8be9fd;">translateY</span><span>(</span><span style="color:#bd93f9;">-50</span><span style="color:#ff79c6;">%</span><span>); +</span><span>} +</span></code></pre> +<h2 id="horizontal-align">Horizontal Align</h2> +<p>But did you know it’s also possible to use <code>translate()</code> to horizontal align elements?</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#50fa7b;">.my-element </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">position</span><span>: </span><span style="color:#6be5fd;">absolute</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">left</span><span>: </span><span style="color:#bd93f9;">50</span><span style="color:#ff79c6;">%</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">transform</span><span>: </span><span style="color:#8be9fd;">translateX</span><span>(</span><span style="color:#bd93f9;">-50</span><span style="color:#ff79c6;">%</span><span>); +</span><span>} +</span></code></pre> +<h2 id="vertical-and-horizontal-align">Vertical and Horizontal Align</h2> +<p>​ Mixing both, we can horizontal and vertical align anything!</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#50fa7b;">.my-element </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">position</span><span>: </span><span style="color:#6be5fd;">absolute</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">left</span><span>: </span><span style="color:#bd93f9;">50</span><span style="color:#ff79c6;">%</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">top</span><span>: </span><span style="color:#bd93f9;">50</span><span style="color:#ff79c6;">%</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">transform</span><span>: </span><span style="color:#8be9fd;">translateX</span><span>(</span><span style="color:#bd93f9;">-50</span><span style="color:#ff79c6;">%</span><span>) </span><span style="color:#8be9fd;">translateY</span><span>(</span><span style="color:#bd93f9;">-50</span><span style="color:#ff79c6;">%</span><span>); +</span><span>} +</span></code></pre> +<p class="note"> +<p>See <a href="http://output.jsbin.com/dusesi">JSBin</a>.</p> +</p> + + + + + A Better ES2015+ and JSX Workflow in VS Code + 2016-10-30T00:00:00+00:00 + 2016-10-30T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/a-better-es2015-and-jsx-workflow-in-vs-code/ + + <p>Lately I’ve been trying <a href="https://code.visualstudio.com">VS Code</a>, a code editor based on <a href="http://electron.atom.io/">Electron</a>. Since then, it really surprised me and it’s been a nice coding experience.</p> +<h2 id="but">But
</h2> +<p>By default, JS syntax highlighting and ES2015+ and JSX support don’t work as expected.</p> +<p>I’ve tried to workaround it by using:</p> +<ol> +<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.js-atom-grammar">Atom grammar</a>. JSX support was pretty bad.</li> +<li>A <a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.typescript-javascript-grammar">development branch of VS Code colorization</a>, which is delivered as an extension. Finally got JSX to work properly, but syntax highlighting was still missing something.</li> +</ol> +<p>So, no success.</p> +<h2 id="improving-your-vs-code-workflow">Improving your VS Code workflow</h2> +<p>After much trial and error, I came up with a better JS workflow in VS Code.</p> +<h3 id="1-fix-js-syntax-highlighting">1. Fix JS syntax highlighting</h3> +<p>Install the <a href="https://marketplace.visualstudio.com/items?itemName=joshpeng.sublime-babel-vscode">Sublime Babel extension</a> and make sure you’re using one of the suggested color themes. (I like <a href="https://marketplace.visualstudio.com/items?itemName=joshpeng.theme-charcoal-oceanicnext">Charcoal Oceanic Next</a>!)</p> +<h3 id="2-use-javascript-react-in-js-files">2. Use “JavaScript React” in .js files</h3> +<p>VS Code only uses “JavaScript React” syntax in <code>.jsx</code> files. Add the following to your User (or Workspace) Settings:</p> +<pre data-lang="json" style="background-color:#282a36;color:#f8f8f2;" class="language-json "><code class="language-json" data-lang="json"><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">files.associations</span><span style="color:#eeeeee;">&quot;</span><span>: { +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">*.js</span><span style="color:#eeeeee;">&quot;</span><span>: </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">javascriptreact</span><span style="color:#eeeeee;">&quot; +</span><span>} +</span></code></pre> +<h3 id="3-enable-emmet-for-jsx">3. Enable Emmet for JSX</h3> +<p>(That’s a plus!)</p> +<p>VS Code uses Emmet by default, but doesn’t enable it for <code>.jsx</code> files. Add the following to your User Settings:</p> +<pre data-lang="json" style="background-color:#282a36;color:#f8f8f2;" class="language-json "><code class="language-json" data-lang="json"><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">emmet.syntaxProfiles</span><span style="color:#eeeeee;">&quot;</span><span>: { +</span><span> </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">javascript</span><span style="color:#eeeeee;">&quot;</span><span>: </span><span style="color:#eeeeee;">&quot;</span><span style="color:#f1fa8c;">jsx</span><span style="color:#eeeeee;">&quot; +</span><span>} +</span></code></pre> +<h2 id="let-s-improve-vs-code">Let’s improve VS Code!</h2> +<p>There has been <a href="https://code.visualstudio.com/updates#_preview-typescript-javascript-grammar">improvements for JS grammar</a> already, but it’s still not perfect.</p> +<p>Fortunately, VS Code is an <strong><a href="https://github.com/Microsoft/vscode">open source project</a></strong> and can be improved by developers like us! Let’s not leave it like this. Give useful feedback and help!</p> +<p>Happy coding!</p> + + + + + I'm Tired of Beautiful-Looking User Interfaces + 2016-10-23T12:50:35+00:00 + 2016-10-23T12:50:35+00:00 + + + + + Unknown + + + + + + /blog/i-m-tired-of-beautiful-looking-interfaces/ + + <div class="summary"> +<p>What if the user interface is more beautiful-looking than <strong>usable</strong>, <strong>understandable</strong>, and <strong>intuitive</strong>?</p> +</div> +<p>The visual aspects of an user interface play an essential role in organising information. Once you’ve got the resources, however, that turns out to be the easiest part of an Interface Design process.</p> +<p>Sure we like things that look nice, but looking nice doesn’t compensate a bad product design. <strong>Visual communication should not compensate flaws.</strong></p> +<p>If you spend most of the time looking for visual inspiration rather than conducting research, doing usability tests, and studying metrics such as business goals and conversion rates, you will probably come up with a interface that only looks beautiful.</p> +<p>And I’m tired of beautiful-looking interfaces.</p> + + + + + Encadeamento de MĂ©todos em JavaScript + 2016-08-06T16:11:32+00:00 + 2016-08-06T16:11:32+00:00 + + + + + Unknown + + + + + + /blog/encadeamento-de-metodos-em-javascript/ + + <p>Popular em diversas bibliotecas JavaScript, o encadeamento de mĂ©todos (<em>“method chaining”</em>) Ă© uma tĂ©cnica usada para invocar diversos mĂ©todos em um mesmo objeto.</p> +<p>Com o objetivo de <strong>melhorar a legibilidade do cĂłdigo</strong>, a tĂ©cnica Ă© vastamente utilizada na API da jQuery, o que certamente influenciou na popularidade da biblioteca.</p> +<p>Se vocĂȘ jĂĄ utilizou jQuery, o estilo do cĂłdigo abaixo pode ser familiar:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#50fa7b;">$</span><span>(</span><span style="color:#f1fa8c;">&quot;#my-element&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">css</span><span>(</span><span style="color:#f1fa8c;">&quot;background&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;purple&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">height</span><span>(</span><span style="color:#bd93f9;">100</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">animate</span><span>({ height: </span><span style="color:#bd93f9;">250 </span><span>}) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">find</span><span>(</span><span style="color:#f1fa8c;">&quot;input&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">fadeIn</span><span>(</span><span style="color:#bd93f9;">200</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">val</span><span>(</span><span style="color:#f1fa8c;">&quot;&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">end</span><span>(); +</span></code></pre> +<p class="note"> +<p>No exemplo acima, uma Ășnica declaração faz vĂĄrias coisas. No entanto, uma boa prĂĄtica com <em>method chaining</em> Ă© <strong>fazer somente uma ação por declaração</strong>. ;-)</p> +</p> +<p>Perceba que vĂĄrios mĂ©todos sĂŁo invocados no objeto <code>$('#my-element')</code>, sem a necessidade de repetĂ­-lo. JĂĄ sem <em>Method Chaining</em>, Ă© necessĂĄrio fazer a referĂȘncia diversas vezes:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">myElement </span><span style="color:#ff79c6;">= </span><span style="color:#50fa7b;">$</span><span>(</span><span style="color:#f1fa8c;">&quot;#my-element&quot;</span><span>); +</span><span style="color:#ffffff;">myElement</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">css</span><span>(</span><span style="color:#f1fa8c;">&quot;background&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;purple&quot;</span><span>); +</span><span style="color:#ffffff;">myElement</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">height</span><span>(</span><span style="color:#bd93f9;">100</span><span>); +</span><span style="color:#ffffff;">myElement</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">fadeIn</span><span>(</span><span style="color:#bd93f9;">200</span><span>); +</span></code></pre> +<h2 id="exemplo">Exemplo</h2> +<p>Vamos criar um contador <code>Counter</code>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#ff79c6;">class </span><span>Counter { +</span><span> </span><span style="font-style:italic;color:#8be9fd;">constructor</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">0</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#50fa7b;">increase</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">+= </span><span style="color:#bd93f9;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#50fa7b;">decrease</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">-= </span><span style="color:#bd93f9;">1</span><span>; +</span><span> } +</span><span> +</span><span> </span><span style="color:#50fa7b;">log</span><span>() { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value); +</span><span> } +</span><span>} +</span></code></pre> +<p>Agora, vamos instanciar um contador e usar seus mĂ©todos:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">counter </span><span style="color:#ff79c6;">= new </span><span>Counter(); +</span><span style="color:#ffffff;">counter</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">increase</span><span>(); +</span><span style="color:#ffffff;">counter</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">log</span><span>(); </span><span style="color:#6272a4;">// =&gt; 1 +</span><span style="color:#ffffff;">counter</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">decrease</span><span>(); +</span><span style="color:#ffffff;">counter</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">log</span><span>(); </span><span style="color:#6272a4;">// =&gt; 0 +</span></code></pre> +<p>Perceba que Ă© necessĂĄrio fazer vĂĄrias declaraçÔes para interagir com a instĂąncia, o que prejudica a legibilidade do cĂłdigo.</p> +<p>E se tentarmos usar <em>Method Chaining</em>
</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">new </span><span>Counter()</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">increase</span><span>()</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">log</span><span>(); +</span><span style="color:#6272a4;">// &gt; TypeError: Cannot read property &#39;log&#39; of undefined +</span></code></pre> +<p>Perceba que <code>log()</code> estĂĄ sendo executado em <code>new Counter().increase()</code>, que, por sua vez, estĂĄ retornando <code>undefined</code>. Portanto, ainda nĂŁo Ă© possĂ­vel interagir com <code>Counter</code> dessa forma.</p> +<h2 id="como-encadear-metodos">Como Encadear MĂ©todos</h2> +<p>Para evitar a repetição do objeto, Ă© necessĂĄrio que seus mĂ©todos retornem o prĂłprio objeto.</p> +<p>Veja este exemplo com Promises:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#50fa7b;">getJSON</span><span>(</span><span style="color:#f1fa8c;">&quot;users.json&quot;</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">then</span><span>(</span><span style="color:#6be5fd;">JSON</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">parse</span><span>) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">then</span><span>((</span><span style="font-style:italic;color:#ffb86c;">response</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Olha o JSON!&quot;</span><span>, </span><span style="color:#ffffff;">response</span><span>)) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">catch</span><span>((</span><span style="font-style:italic;color:#ffb86c;">error</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Falhou!&quot;</span><span>, </span><span style="color:#ffffff;">error</span><span>)); +</span></code></pre> +<p>Isso sĂł Ă© possĂ­vel pois os mĂ©todos <code>then()</code> and <code>catch()</code> sempre retornam outras promises. Assim, podemos dizer que as Promises sĂŁo <strong>fluent APIs</strong>, tal como a jQuery.</p> +<h3 id="quem-lembra-do-this">Quem Lembra do <code>this</code>?</h3> +<p>Para os mĂ©todos serem encadeados, serĂĄ necessĂĄrio retornar o contexto (<code>this</code>) em cada mĂ©todo.</p> +<blockquote> +<p>Em JavaScript, <code>this</code> sempre se refere ao contexto de execução de função.</p> +</blockquote> +<p>No caso de um mĂ©todo, que Ă© uma função de um objeto, refere-se ao prĂłprio objeto.</p> +<h4 id="exemplo-com-method-chaining-pattern">Exemplo com <em>Method Chaining Pattern</em></h4> +<p>Para implementar o encadeamento de mĂ©todos na classe <code>Counter</code>, apenas retornamos seu contexto a cada mĂ©todo:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#ff79c6;">class </span><span>Counter { +</span><span> </span><span style="font-style:italic;color:#8be9fd;">constructor</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">0</span><span>; +</span><span> } +</span><span> </span><span style="color:#50fa7b;">increase</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">+= </span><span style="color:#bd93f9;">1</span><span>; +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#bd93f9;">this</span><span>; </span><span style="color:#6272a4;">// Aqui! +</span><span> } +</span><span> </span><span style="color:#50fa7b;">decrease</span><span>() { +</span><span> </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value </span><span style="color:#ff79c6;">-= </span><span style="color:#bd93f9;">1</span><span>; +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#bd93f9;">this</span><span>; </span><span style="color:#6272a4;">// Aqui! +</span><span> } +</span><span> </span><span style="color:#50fa7b;">log</span><span>() { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>value); +</span><span> </span><span style="color:#ff79c6;">return </span><span style="color:#bd93f9;">this</span><span>; </span><span style="color:#6272a4;">// E aqui! +</span><span> } +</span><span>} +</span></code></pre> +<p>Agora, ao executar <code>new Counter().increase()</code>, o retorno jĂĄ nĂŁo serĂĄ mais <code>undefined</code>.</p> +<p>
E, portanto, Ă© possĂ­vel fazer <em>method chaining</em>!</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">new </span><span>Counter() +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">increase</span><span>() +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">log</span><span>() </span><span style="color:#6272a4;">// =&gt; 1 +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">decrease</span><span>() +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">log</span><span>(); </span><span style="color:#6272a4;">// =&gt; 0 +</span></code></pre> +<h2 id="conclusao">ConclusĂŁo</h2> +<p>No universo de APIs orientadas a objetos, o encadeamento de mĂ©todos Ă© uma tĂ©cnica incrĂ­vel se o seu objetivo Ă© tornar o cĂłdigo mais expressivo e fluente.</p> +<p>No geral, <em>fluent APIs</em> sĂŁo sim interessantes de se entender e implementar, e vocĂȘ pode ter certeza disso analisando o primeiro exemplo com jQuery do inĂ­cio deste artigo. É fantĂĄstico! Mas Ă© importante entender que <strong>o encadeamento de mĂ©todos nem sempre tornarĂĄ as coisas mais fĂĄceis</strong> (debugar, por exemplo, se torna mais difĂ­cil), e, portanto, a maneira aparentemente “mĂĄgica” com que elas funcionam nĂŁo deve ser sempre levada em consideração.</p> + + + + + SVG Images as React Components with Webpack + 2016-08-02T22:00:00+00:00 + 2016-08-02T22:00:00+00:00 + + + + + Unknown + + + + + + /blog/svg-images-as-react-components-with-webpack/ + + <p>If you’ve ever tried to load inline SVG (using <a href="https://github.com/sairion/svg-inline-loader">svg-inline-loader</a>) into React, you know it seriously hurts people’s eyes.</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./icons/remove.svg&quot;</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">RemoveButton </span><span style="color:#ff79c6;">= </span><span>() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>( +</span><span> &lt;</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">div </span><span style="color:#50fa7b;">dangerouslySetInnerHTML</span><span style="color:#ff79c6;">={</span><span>{ __html: </span><span style="color:#ffffff;">IconRemove </span><span>}</span><span style="color:#ff79c6;">} </span><span>/&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">span</span><span>&gt;Remove&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span>); +</span></code></pre> +<p>So what if it looked like this instead?</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./icons/remove.svg&quot;</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">RemoveButton </span><span style="color:#ff79c6;">= </span><span>() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>( +</span><span> &lt;</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">IconRemove </span><span>/&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">span</span><span>&gt;Remove&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span>); +</span></code></pre> +<p>Much better, don’t you think?</p> +<p>That’s what <a href="https://github.com/jhamlet/svg-react-loader">svg-react-loader</a> does. It <strong>process your SVG file and returns a React component</strong>, which is compiled with Babel (more on this below).</p> +<h2 id="using-the-loader">Using the Loader</h2> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">npm</span><span> install svg-react-loader</span><span style="font-style:italic;color:#ffb86c;"> --save-dev +</span></code></pre> +<p class="note"> +<p>Refer to <a href="https://webpack.github.io/docs/using-loaders.html#usage">Webpack docs</a> for more information on loaders usage. Also, make sure you have installed <a href="https://github.com/jhamlet/svg-react-loader#dependencies">svg-react-loader’s dependencies</a>.</p> +</p> +<h3 id="1-in-module-request">1. In Module Request</h3> +<p>The simplest method, although the configuration convention is preferred. Using svg-react-loader and <a href="https://github.com/babel/babel-loader">babel-loader</a>, import your icon just like:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;babel!svg-react!./icons/remove.svg&quot;</span><span>; +</span></code></pre> +<h3 id="2-in-webpack-config-file-recommended">2. In Webpack Config File (Recommended)</h3> +<p>Add in your Webpack configuration file’s <code>loaders</code> array.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span>{ +</span><span> test: </span><span style="color:#f1fa8c;">/</span><span style="color:#ff79c6;">\.</span><span style="color:#f1fa8c;">svg</span><span style="color:#ff79c6;">$</span><span style="color:#f1fa8c;">/</span><span>, +</span><span> loader: </span><span style="color:#f1fa8c;">&#39;babel!svg-react&#39; +</span><span>} +</span></code></pre> +<p>Import your icon just like:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./icons/remove.svg&quot;</span><span>; +</span></code></pre> +<h2 id="usage-examples">Usage Examples</h2> +<p>Loader in module request method (1):</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;babel!svg-react!./icons/remove.svg&quot;</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">RemoveButton </span><span style="color:#ff79c6;">= </span><span>() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>( +</span><span> &lt;</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">IconRemove </span><span>/&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">span</span><span>&gt;Remove&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span>); +</span></code></pre> +<p>Loader in Webpack config file method (2):</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">IconRemove </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;./icons/remove.svg&quot;</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#50fa7b;">RemoveButton </span><span style="color:#ff79c6;">= </span><span>() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span>( +</span><span> &lt;</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">IconRemove </span><span>/&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">span</span><span>&gt;Remove&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">button</span><span>&gt; +</span><span>); +</span></code></pre> +<h2 id="a-note-on-svg-loaders">A Note on SVG Loaders</h2> +<p>Sometimes, we don’t want all of our SVG files to be loaded as React components. If you use a SVG in a <code>img</code> element, for example, it may lead to conflicts. Fortunately, you can avoid them by being more specific in <code>test</code> regular expression:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span>{ +</span><span> test: </span><span style="color:#f1fa8c;">/</span><span style="color:#ff79c6;">\.</span><span style="color:#f1fa8c;">inline</span><span style="color:#bd93f9;">.</span><span style="color:#f1fa8c;">svg</span><span style="color:#ff79c6;">$</span><span style="color:#f1fa8c;">/</span><span>, +</span><span> loader: </span><span style="color:#f1fa8c;">&#39;babel!svg-react&#39; +</span><span>}, +</span><span>{ +</span><span> test: </span><span style="color:#f1fa8c;">/</span><span style="color:#ff79c6;">\.</span><span style="color:#f1fa8c;">jpe</span><span style="color:#ff79c6;">?</span><span style="color:#f1fa8c;">g</span><span style="color:#ff79c6;">$|\.</span><span style="color:#f1fa8c;">gif</span><span style="color:#ff79c6;">$|\.</span><span style="color:#f1fa8c;">png</span><span style="color:#ff79c6;">$|^</span><span style="color:#f1fa8c;">(?!</span><span style="color:#bd93f9;">.</span><span style="color:#ff79c6;">*\.</span><span style="color:#f1fa8c;">inline</span><span style="color:#ff79c6;">\.</span><span style="color:#f1fa8c;">svg</span><span style="color:#ff79c6;">$</span><span style="color:#f1fa8c;">)</span><span style="color:#bd93f9;">.</span><span style="color:#ff79c6;">*\.</span><span style="color:#f1fa8c;">svg</span><span style="color:#ff79c6;">$</span><span style="color:#f1fa8c;">/</span><span>, +</span><span> loader: </span><span style="color:#f1fa8c;">&#39;url&#39; +</span><span>} +</span></code></pre> +<p>Now, only SVG files ending with <code>.inline.svg</code> will be loaded as React components. You’re good to go!</p> + + + + + A Cascata das VariĂĄveis do CSS + 2016-05-30T22:00:00+00:00 + 2016-05-30T22:00:00+00:00 + + + + + Unknown + + + + + + /blog/a-cascata-das-variaveis-do-css/ + + <p style="text-align: center"><a href="http://caniuse.com/#feat=css-variables">Suporte</a> | <a href="https://www.w3.org/TR/css-variables/">Especificação</a></p> +<p>Muito embora todos os seres humanos do Planeta Terra tenham odiado sua sintaxe, as variĂĄveis finalmente chegaram ao CSS – e elas sĂŁo mais poderosas do que vocĂȘ imagina!</p> +<h2 id="motivacao">Motivação</h2> +<p>O desenvolvimento de grandes aplicaçÔes web implica inevitavelmente em grandes folhas de estilo, que devem ser organizadas de forma que facilite a manutenção. Muitos valores definidos para propriedades sĂŁo repetidos, quando poderiam ser reutilizados e padronizados, de forma compartilhada, pela folha de estilo.</p> +<p>Nesse contexto, surgem as variĂĄveis no CSS, tambĂ©m chamadas de <em>Custom Properties</em> – pois, tecnicamente, Ă© isso que elas sĂŁo.</p> +<h2 id="definicao">Definição</h2> +<p>As <em>Custom Properties</em> sĂŁo propriedades CSS customizadas (ou seja, vocĂȘ configura o seu valor) iniciadas com <code>--</code>, de nome <em>case-sensitive</em>, e que sĂŁo utilizadas no documento atravĂ©s da função <code>var()</code>. Por serem propriedades, Ă© importante compreender que seu comportamento Ă© idĂȘntico ao de uma propriedade qualquer do CSS (guarde essa informação!).</p> +<h3 id="exemplo">Exemplo</h3> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span>:root { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--colorPrimary</span><span>: </span><span style="color:#6be5fd;">purple</span><span>; +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">a </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">color</span><span>: </span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--colorPrimary</span><span>); +</span><span>} +</span></code></pre> +<p>(Eu nĂŁo conheço ninguĂ©m que gosta da ideia esplĂȘndida do <code>--</code>. Mas elas nĂŁo vĂŁo deixar de iniciar com <code>--</code> se vocĂȘ reclamar. Inclusive, <a href="http://www.xanthir.com/blog/b4KT0">isso jĂĄ foi discutido o suficiente</a>.)</p> +<h2 id="a-funcao-var">A função <code>var()</code></h2> +<p>Quem viabiliza o uso de <em>Custom Properties</em>? Ela:</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">var</span><span>( &lt;</span><span style="color:#ff79c6;">custom-property-name</span><span>&gt; [, &lt;</span><span style="color:#50fa7b;">declaration-value</span><span>&gt; ]? ) +</span></code></pre> +<p>O primeiro parĂąmetro Ă© o nome da propriedade, e o segundo, opcional, Ă© o valor a ser usado como <em>fallback</em> caso o primeiro argumento seja invĂĄlido (por exemplo: uma variĂĄvel com <code>20px</code> sendo usada como valor de um <code>background</code>, ou variĂĄvel inexistente).</p> +<h2 id="escopo">Escopo</h2> +<p>Cascata, especificidade, herança
 Esses conceitos sĂŁo muito importantes para entender o poder das variĂĄveis do CSS – e do CSS no geral, eu diria.</p> +<p>Aqui, uma das informaçÔes mais importantes deste artigo: As <em>Custom Properties</em> seguem <strong>regras de cascata</strong> tal como qualquer outra propriedade do CSS.</p> +<p>Por isso, quando quisermos que a variĂĄvel esteja disponĂ­vel “globalmente” (para todos os seletores), a declaramos no seletor <code>:root</code>, que Ă© o prĂłprio documento HTML. Isso acontece pois <strong>o efeito cascata do CSS permite que todos seus descendentes herdem a propriedade.</strong> Legal, nĂ©?</p> +<p>A propriedade customizada, tal como qualquer outra propriedade, pode ser sobreescrita atravĂ©s de seletores. Seu valor serĂĄ definido de acordo com a <strong>especifidade</strong> deles.</p> +<p class="note"> +<p>A implementação de <em>Custom Properties</em> do CSSNext nĂŁo segue regras de cascata. Apenas variĂĄveis declaradas no <code>:root</code> sĂŁo vĂĄlidas. :-(</p> +</p> +<h3 id="exemplo-1">Exemplo</h3> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span>:root { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--bgColor</span><span>: </span><span style="color:#6be5fd;">indianred</span><span>; +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--bgColor</span><span>: </span><span style="color:#6be5fd;">darkseagreen</span><span>; +</span><span>} +</span><span> +</span><span style="color:#50fa7b;">#wow </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--bgColor</span><span>: </span><span style="color:#6be5fd;">darkcyan</span><span>; +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">* </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">background-color</span><span>: </span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--bgColor</span><span>); +</span><span>} +</span></code></pre> +<p>Nesse caso:</p> +<ul> +<li>Todos os elementos sĂŁo vermelhos.</li> +<li>Exceto elementos <code>div</code> e seus filhos, que seriam verdes.</li> +<li>Exceto o elemento com id <code>wow</code> e seus filhos, que seriam ciano.</li> +</ul> +<p>As Ășltimas versĂ”es do Firefox e Chrome jĂĄ implementaram as variĂĄveis nativas do CSS. Se estiver utilizando algum desses navegadores, o exemplo abaixo ilustrarĂĄ o funcionamento do CSS acima.</p> +<p><a class="jsbin-embed" href="http://jsbin.com/meboki/edit?html,output">JS Bin on jsbin.com</a><script src="http://static.jsbin.com/js/embed.min.js?3.35.12"></script></p> +<h2 id="manipulando-variaveis-css-com-javascript">Manipulando variĂĄveis CSS com JavaScript</h2> +<p>Outra informação valiosa sobre as variĂĄveis do CSS Ă© a possibilidade de acessĂĄ-las e alterĂĄ-las via JavaScript, usando a interface <a href="https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration"><code>CSSStyleDeclaration</code></a> para interagir com propriedades.</p> +<h3 id="exemplo-2">Exemplo</h3> +<p>Considerando:</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span>:root { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--my-color</span><span>: </span><span style="color:#6be5fd;">darkcyan</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">background-color</span><span>: </span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--my-color</span><span>); +</span><span>} +</span></code></pre> +<p>VocĂȘ pode obter o valor da propriedade <code>--my-color</code>, atravĂ©s do <code>window.getComputedStyle()</code> e <code>getPropertyValue()</code>.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">myColor </span><span style="color:#ff79c6;">= </span><span style="color:#50fa7b;">getComputedStyle</span><span>(document</span><span style="color:#ff79c6;">.</span><span>body)</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">getPropertyValue</span><span>(</span><span style="color:#f1fa8c;">&quot;--my-color&quot;</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">myColor</span><span>); </span><span style="color:#6272a4;">// =&gt; darkcyan +</span></code></pre> +<p>VocĂȘ pode alterar o valor da variĂĄvel, atravĂ©s do <code>setProperty()</code> do <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style">objeto <code>style</code></a>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span>document</span><span style="color:#ff79c6;">.</span><span>body</span><span style="color:#ff79c6;">.</span><span>style</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">setProperty</span><span>(</span><span style="color:#f1fa8c;">&quot;--my-color&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;tomato&quot;</span><span>); +</span></code></pre> +<p class="note"> +<p>Conheça o <code>CSSStyleDeclaration</code> abrindo o DevTools e digitando <code>getComputedStyle(document.body)</code> no console.</p> +</p> +<h2 id="curiosidades">Curiosidades</h2> +<ul> +<li>VocĂȘ nĂŁo pode armazenar nomes de propriedades do CSS como <em>Custom Properties</em>.</li> +</ul> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--myProperty</span><span>: overflow; +</span><span> var(</span><span style="font-style:italic;color:#66d9ef;">--myProperty</span><span>): </span><span style="color:#6be5fd;">hidden</span><span>; </span><span style="color:#6272a4;">/* Erro de sintaxe */ +</span><span>} +</span></code></pre> +<p>
Em compensação, vocĂȘ pode armazenar qualquer outra coisa (e usĂĄ-las com JavaScript!):</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">--</span><span>foo: </span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ffffff;">x </span><span style="color:#ff79c6;">&gt; </span><span style="color:#bd93f9;">5</span><span>) </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span>width </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">10</span><span>; +</span></code></pre> +<ul> +<li>VocĂȘ nĂŁo pode formar valores com variĂĄveis.</li> +</ul> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--myContainerWidth</span><span>: </span><span style="color:#bd93f9;">300</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">width</span><span>: </span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--myContainerWidth</span><span>) px; </span><span style="color:#6272a4;">/* Valor invĂĄlido */ +</span><span> </span><span style="color:#6272a4;">/* =&gt; 300 px, em vez de 300px */ +</span><span>} +</span></code></pre> +<p>
Ao menos que vocĂȘ use <code>calc()</code>:</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">--myContainerWidth</span><span>: </span><span style="color:#bd93f9;">300</span><span>; +</span><span> </span><span style="font-style:italic;color:#66d9ef;">width</span><span>: </span><span style="color:#8be9fd;">calc</span><span>(</span><span style="color:#8be9fd;">var</span><span>(</span><span style="font-style:italic;color:#66d9ef;">--myContainerWidth</span><span>) </span><span style="color:#ff79c6;">* </span><span style="color:#bd93f9;">1</span><span style="color:#ff79c6;">px</span><span>); </span><span style="color:#6272a4;">/* =&gt; width: 300px; */ +</span><span>} +</span></code></pre> +<h2 id="consideracoes-finais">ConsideraçÔes Finais</h2> +<p>As <em>Custom Properties</em> abriram novas possibilidades para o uso de variĂĄveis em folhas de estilo. Depois de diversas especificaçÔes e sintaxes (<a href="https://www.w3.org/TR/2013/WD-css-variables-1-20130620/#var-">nem sempre foi <code>--</code></a>, acredite!), elas estĂŁo finalmente em fase de implementação nos navegadores.</p> +<p>Tem interesse em se aprofundar em outras novas funcionalidades do CSS? Acompanhe a sĂ©rie <a href="/blog/o-css-do-futuro/">O CSS do Futuro</a>!</p> + + + + + O CSS do Futuro + 2016-05-29T23:21:51+00:00 + 2016-05-29T23:21:51+00:00 + + + + + Unknown + + + + + + /blog/o-css-do-futuro/ + + <div class="summary"> +<p>JĂĄ existem <a href="https://drafts.csswg.org/">especificaçÔes</a> garantindo funcionalidades incrĂ­veis para o CSS: variĂĄveis; uma nova sintaxe para <em>media queries</em>; <em>nesting</em>; novos seletores, valores e propriedades. E vocĂȘ pode usĂĄ-las, <strong>hoje</strong>.</p> +</div> +<p>Neste artigo, introduzo uma sĂ©rie de artigos relacionados Ă s principais funcionalidades do CSS do futuro, alĂ©m da ferramenta <a href="http://cssnext.io/">CSSNext</a>, que permite que vocĂȘ as utilize sem esperar o suporte do navegador.</p> +<p>(A fins didĂĄticos, Ă© possĂ­vel assemelhar o CSSNext ao <a href="https://babeljs.io/">Babel</a>, que, por sua vez, tambĂ©m permite desenvolver com o JavaScript do futuro ao transpilar o cĂłdigo JavaScript da prĂłxima geração para um cĂłdigo suportado pelos navegadores atuais.)</p> +<p>Ao final desse artigo, vocĂȘ saberĂĄ como desenvolver, hoje, com o CSS do futuro.</p> +<hr /> +<h2 id="introducao-ao-postcss">Introdução ao PostCSS</h2> +<p>O CSSNext estĂĄ relacionado com PostCSS. Mas o que Ă© o PostCSS, afinal?</p> +<p>O <a href="https://github.com/postcss/postcss">PostCSS</a> Ă© apenas uma ferramenta que permite (prĂ© ou pĂłs) processar o CSS atravĂ©s de plugins em JavaScript. Um desses plugins Ă© o CSSNext – assim como, por exemplo, o <a href="https://github.com/postcss/autoprefixer">Autoprefixer</a>, que trabalha na etapa de pĂłs-processamento do CSS, adicionando <em>vendor prefixes</em>.</p> +<p>A transformação de estilos Ă© viabilizada de forma integralmente <strong>agnĂłstica</strong>: nada Ă© dito sobre como e com o que serĂĄ feito. Com o PostCSS, vocĂȘ Ă© responsĂĄvel pelo workflow de processamento do estilo. É possĂ­vel utilizar <a href="https://github.com/jonathantneal/precss">funcionalidades prĂ©-processadas</a> e/ou <a href="https://github.com/postcss/sugarss">sintaxe do Sass</a>, <a href="https://github.com/ben-eb/cssnano">minificar</a> e adicionar <em>vendor prefixes</em> – tudo de forma “plugĂĄvel”!</p> +<p>Como o PostCSS nunca Ă© utilizado sozinho, o prĂłximo passo Ă© plugar o CSSNext a ele.</p> +<h2 id="como-usar-o-cssnext">Como usar o CSSNext</h2> +<p>Se vocĂȘ quiser apenas testar as funcionalidades dos novos mĂłdulos do CSS, vocĂȘ pode <a href="http://cssnext.io/playground">brincar com o CSSNext no navegador</a>.</p> +<h3 id="no-workflow">No workflow</h3> +<p>Em um ambiente de desenvolvimento, Ă© necessĂĄrio usĂĄ-lo com o PostCSS. A <a href="http://cssnext.io/setup/#usage">documentação do CSSNext</a> guia vocĂȘ para configurĂĄ-lo em seu workflow, seja com Webpack, Browserify, Gulp, Grunt, [
], ou interface de linha de comando.</p> +<p>Em todos os casos, a configuração se resume a passar um <em>array</em> com os processadores desejados para o PostCSS. Nesse caso, o processador a ser plugado Ă© apenas o <a href="https://www.npmjs.com/package/postcss-cssnext">postcss-cssnext</a>:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">$</span><span> npm install postcss-cssnext</span><span style="font-style:italic;color:#ffb86c;"> --save-dev +</span></code></pre> +<h2 id="principais-funcionalidades">Principais Funcionalidades</h2> +<p>Aprofunde-se nas principais funcionalidades do CSS do Futuro atravĂ©s dos artigos abaixo. Abra o <a href="http://cssnext.io/playground/">playground do CSSNext</a> e bons estudos!</p> +<ul> +<li><a href="/blog/a-cascata-das-variaveis-do-css/">A Cascata das VariĂĄveis do CSS</a></li> +<li>Uma Nova Sintaxe Para Media Queries</li> +<li>Seletores CSS em Um Novo NĂ­vel</li> +<li>Manipulando Cores Com CSS</li> +</ul> + + + + + Mass Deleting Files from Slack + 2016-04-17T00:10:15+00:00 + 2016-04-17T00:10:15+00:00 + + + + + Unknown + + + + + + /blog/mass-deleting-files-from-slack/ + + <p>Slack comes with limited file storage, so you eventually run out of space. Deleting files isn’t easy though: there is no way to <strong>bulk delete</strong> them using the web interface.</p> +<p><strong>Slack forces you to delete one by one.</strong></p> +<p>And although Slack can force humans, it can’t force JavaScript. So JavaScript to the rescue!</p> +<h2 id="how-to-delete-multiple-files-from-slack">How to delete multiple files from Slack</h2> +<p>In order to free up space, you’ll need;</p> +<ul> +<li><a href="https://nodejs.org/">Node.js</a> version 5 or later;</li> +<li>A Slack token, which you can get from <a href="https://api.slack.com/docs/oauth-test-tokens">Slack API docs</a>;</li> +<li>A terminal.</li> +</ul> +<h3 id="installing">Installing</h3> +<p>Open your terminal and install <code>slack-delete-files</code> package globally using Node Package Manager:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">$</span><span> npm install</span><span style="font-style:italic;color:#ffb86c;"> -g</span><span> slack-delete-files +</span></code></pre> +<h3 id="running">Running</h3> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">$</span><span> slack-delete-files +</span></code></pre> +<p class="note"> +<p>You’ll be asked for your Slack token and whether you want to delete <em>all files</em> or only <em>files older than 30 days</em>.</p> +</p> +<h3 id="done">Done!</h3> +<p>Your space is probably back!</p> +<p>After deleting, you can uninstall the package:</p> +<pre data-lang="sh" style="background-color:#282a36;color:#f8f8f2;" class="language-sh "><code class="language-sh" data-lang="sh"><span style="color:#50fa7b;">$</span><span> npm uninstall</span><span style="font-style:italic;color:#ffb86c;"> -g</span><span> slack-delete-files +</span></code></pre> +<p><a href="https://github.com/diessica/slack-delete-files">Contribute on GitHub</a>.</p> + + + + + A FantĂĄstica Diversidade do Front-end + 2016-04-09T15:10:00+00:00 + 2016-04-09T15:10:00+00:00 + + + + + Unknown + + + + + + /blog/a-fantastica-diversidade-do-front-end/ + + <p class="summary">Os diferentes perfis de desenvolvedores front-end Ă© um tĂłpico que frequente em fĂłruns de discussĂŁo. Quais perfis o mercado espera? Como posso me definir enquanto desenvolvedor(a) front-end?</p> +<p>Vi, recentemente, uma <a href="https://www.facebook.com/careers/jobs/a0I1200000IALJQ/">vaga no Facebook para Front-end Engineer com foco em Acessibilidade</a>. Pensei “Foco em acessibilidade? Que especĂ­fico!”, e, segundos depois, todas as discussĂ”es que jĂĄ tive sobre os perfis de desenvolvedores front-end me vieram Ă  mente.</p> +<p>Falar sobre esse assunto Ă© falar sobre <strong>como interpretar vagas de emprego sem entrar em desespero</strong>.</p> +<h2 id="mesmo-papel-diversas-habilidades">Mesmo Papel, Diversas Habilidades</h2> +<p>Estuda Motion Design a fim de desenvolver nĂŁo sĂł sites, mas experiĂȘncias fantĂĄsticas? Estuda UX Design e prĂĄticas de Acessibilidade a fim de desenvolver produtos que engajam o mĂĄximo de pessoas possĂ­vel? Estuda padrĂ”es de arquitetura de software a fim de desenvolver aplicaçÔes web complexas e escalĂĄveis no client-side?</p> +<p>VocĂȘ pode estudar e gostar todos; estudar mais um mais do que o outro; trabalhar com um, mas tender a outro; e pode atĂ© mesmo nĂŁo focar em nenhum dos que eu citei acima. Em qualquer uma das possibilidades, vocĂȘ provavelmente <strong>nĂŁo deixarĂĄ de ser um profissional da ĂĄrea de front-end</strong> – mas terĂĄ, com certeza, um mercado especĂ­fico e uma carreira que se basearĂŁo nas suas escolhas profissionais.</p> +<p><strong>Existe uma diversidade incrĂ­vel de habilidades na ĂĄrea de desenvolvimento front-end.</strong></p> +<p><strong>Somos o intermediĂĄrio entre o back-end e o design</strong>, mas nosso papel Ă© transformar o web design em uma experiĂȘncia real. Essa (grande) responsabilidade faz com que desenvolvamos diversas habilidades, e algumas sĂŁo inegavelmente desenvolvidas em maior ou menor nĂ­vel. Nesse desnĂ­vel, encontramos de <em>Motion Designers</em> a <em>JavaScript Developers</em>, cada um com seu espaço em times e projetos especĂ­ficos.</p> +<p>E nĂŁo hĂĄ nada de errado nisso. O surgimento dessas especializaçÔes – que podem (e devem) ser escolhidas por vocĂȘ – Ă© apenas um resultado da complexidade atual do desenvolvimento front-end.</p> +<h2 id="confie-nas-suas-habilidades">Confie nas Suas Habilidades</h2> +<p>(ou “VocĂȘ NĂŁo Precisa Ser o Candidato Perfeito Para Todas as Vagas de Front-end Existentes”.)</p> +<p>Por que eu disse que <em>falar sobre esse assunto Ă© falar sobre como interpretar vagas de emprego sem entrar em desespero</em>?</p> +<p>Pense: VocĂȘ Ă© experiente, estuda com frequĂȘncia, mas, ocasionalmente, procura vagas de emprego e se vĂȘ insuficiente. Ok, convenhamos, a possibilidade existe: vocĂȘ nĂŁo estar atingindo os requisitos mĂ­nimos das vagas pode sim ser um sinal de que algo estĂĄ errado. Mas provavelmente nĂŁo Ă© o caso.</p> +<p><strong>Talvez vocĂȘ esteja procurando vagas para um perfil que nĂŁo Ă© o seu.</strong> NĂŁo precisamos aceitar ter expertises variadas como Ă© exigido; afinal, muitas vagas na ĂĄrea de TI viram piada justamente por esse motivo. Desde que vocĂȘ entenda a multidisciplinaridade como mais valiosa que qualquer disciplina, apenas abrace o que prefere e se aprofunde, torne-se uma referĂȘncia nisso.</p> +<p>No fim, suas preferĂȘncias moldarĂŁo vocĂȘ como profissional. Elas farĂŁo com que vocĂȘ seja incluĂ­do(a) ou excluĂ­do(a) de vĂĄrias oportunidades, o que, por consequĂȘncia, moldarĂĄ sua carreira.</p> +<p>Estude o que gosta, reconheça suas preferĂȘncias, confie nas suas habilidades, e, entĂŁo, procure vagas sem entrar em desespero.</p> +<h2 id="perfis-de-desenvolvedores-front-end">Perfis de Desenvolvedores Front-end</h2> +<p>No <a href="https://github.com/frontendbr/forum/issues/32">fĂłrum do Front-end Brasil</a>, foi proposta a divisĂŁo de separar profissionais de front-end que desenvolvem a camada de apresentação dos que arquitetam aplicaçÔes que interagem com back-end. Concordo com a divisĂŁo. Tenho uma visĂŁo bem definida, com base nas exigĂȘncias atuais do mercado internacional.</p> +<h3 id="dois-perfis-uma-proposta">Dois Perfis: Uma Proposta</h3> +<h4 id="front-end-developer">Front-end Developer</h4> +<p>A ponte entre o design e o front-end. (“UI Developer” Ă© um nome alternativo.)</p> +<h5 id="habilidades">Habilidades</h5> +<ul> +<li>ProficiĂȘncia em HTML semĂąntico, CSS e JavaScript a nĂ­vel de desenvolvimento da camada de apresentação da aplicação.</li> +<li>PrincĂ­pios e boas prĂĄticas de User Experience Design.</li> +<li>PrincĂ­pios e boas prĂĄticas de Acessibilidade.</li> +<li>ProficiĂȘncia em metodologias de organização do CSS como OOCSS, SMACSS e BEM.</li> +<li>NoçÔes de User Interface Design.</li> +<li>NoçÔes de Motion Design.</li> +<li>NoçÔes de back-end, geralmente a nĂ­vel de integração com CMS.</li> +</ul> +<h5 id="responsabilidades">Responsabilidades</h5> +<ul> +<li>Planejamento e desenvolvimento da camada de apresentação da aplicação.</li> +<li>Implementação do <em>live styleguide</em>, junto ao designer.</li> +<li>Metodologia e estrutura a ser usada no CSS.</li> +<li>Participação no processo de Design (pois <a href="http://bradfrost.com/blog/post/development-is-design/"><em>Development is Design</em></a>).</li> +</ul> +<h4 id="front-end-engineer">Front-end Engineer</h4> +<p>A ponte entre o front-end e o back-end. (Dependendo do projeto, “JavaScript Developer” pode ser mais apropriado.)</p> +<h5 id="habilidades-1">Habilidades</h5> +<ul> +<li>ProficiĂȘncia em HTML e CSS, mas sua especialização Ă© JavaScript.</li> +<li>ProficiĂȘncia em Design Patterns e padrĂ”es de arquitetura de software.</li> +<li>Conhecimento de modelo cliente-servidor, HTTP, REST.</li> +<li>PrincĂ­pios e boas prĂĄticas de Performance.</li> +<li>PrincĂ­pios e boas prĂĄticas de Segurança.</li> +<li>NoçÔes de estratĂ©gias de desenvolvimento, como Integração ContĂ­nua (CI).</li> +</ul> +<h5 id="responsabilidades-1">Responsabilidades</h5> +<ul> +<li>Planejamento e desenvolvimento da aplicação JavaScript.</li> +<li>Automatização das tarefas.</li> +<li><em>Tooling</em> da aplicação.</li> +<li>Implementação de uma metodologia de testes.</li> +</ul> +<p class="note"> +<p>NĂŁo concordo com o nome “Front-end Designer”, <a href="http://bradfrost.com/blog/post/frontend-design/">sugerido pelo Brad Frost</a>. Ainda que desenvolvedores front-end participem do processo de design, tornar funcional a camada de apresentação Ă© uma etapa do desenvolvimento de software – nĂŁo do design. O fato do desenvolvimento front-end ser erroneamente considerado mais programação do que design, quando deveria ser os dois, Ă© um argumento que nĂŁo justifica o nome.</p> +</p> +<h3 id="qual-deles">
Qual Deles?</h3> +<p>Normalmente temos um pouco dos dois, mas sempre um mais do que o outro. Nesse caso, uma boa maneira de explicitar o seu papel sem desmerecer o outro Ă© falar sobre suas habilidades, em vez de se apegar a um rĂłtulo.</p> +<p><strong>Dificilmente um rĂłtulo resumirĂĄ todo o seu conhecimento.</strong></p> +<p>Eu nĂŁo me apego a isso, por exemplo. Mesmo exercendo a função de Front-end Engineer atualmente, continuo me denominando “Front-end Developer”.</p> +<h2 id="a-vaga-ideal-para-suas-habilidades">A Vaga Ideal Para Suas Habilidades</h2> +<p>É utĂłpico esperar que todos desenvolvedores front-end sejam bons UX Designers, Motion Designers, JavaScript Developers
 Isso nĂŁo existe. As empresas procuram diferentes perfis de desenvolvedores front-end. <strong>E elas nem sempre sabem disso.</strong></p> +<p>As empresas nĂŁo simplesmente procuram um Front-end Developer ou um Front-end Engineer. Existem vagas bastante hĂ­bridas, como Front-end Engineers <em>com foco</em> em UX ou Acessibilidade, ou atĂ© mesmo Front-end Developers <em>com noçÔes</em> de arquiteturas como MVC. Plenamente possĂ­vel e vĂĄlido!</p> +<p>Cabe a vocĂȘ identificar se Ă© ideal Ă  vaga de emprego que quer se candidatar e se suas habilidades sĂŁo compatĂ­veis com a expectativa da empresa. À empresa, cabe a identificação do seu perfil, a fim de alocar vocĂȘ em um projeto e time que explorem suas habilidades.</p> +<p>É o cenĂĄrio perfeito, pelo menos.</p> +<h2 id="lembre-se-da-nossa-essencia">Lembre-se da Nossa EssĂȘncia</h2> +<p>Independente de como vocĂȘ se posiciona e rotula, dos projetos que trabalha e do caminho que quer seguir, o front-end nĂŁo deixarĂĄ de orbitar ao redor da trinca <strong>HTML, CSS</strong> e <strong>JavaScript</strong>.</p> +<p>Enquanto vocĂȘ possuir interesse nessas trĂȘs linguagens, os seus outros interesses apenas moldarĂŁo o seu caminho profissional.</p> +<p>E, temos sorte: na ĂĄrea de front-end, a diversidade de caminhos Ă© fantĂĄstica.</p> + + + + + 5 Bibliotecas Essenciais para Desenvolver React Apps + 2016-03-21T23:00:00+00:00 + 2016-03-21T23:00:00+00:00 + + + + + Unknown + + + + + + /blog/5-bibliotecas-essenciais-para-desenvolver-react-apps/ + + <p>O conjunto de ferramentas, boilerplates e bibliotecas disponĂ­veis formam um ecossistema incrĂ­vel em torno do React.</p> +<p>No meio de tudo, existem ferramentas que sĂŁo comuns – e essenciais – a diversas aplicaçÔes, independente de suas arquiteturas. Cito cinco delas.</p> +<h2 id="1-classnames">1. <a href="https://www.npmjs.com/package/classnames">classnames</a></h2> +<p>Muitas vezes, no React, um estado representarĂĄ um comportamento visual do componente (“selecionado”, “pressionado”, “focado”), normalmente associado a uma classe CSS.</p> +<p>Um botĂŁo e seus estados <em>disabled</em> e <em>hovered</em>, por exemplo, ficariam assim:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="color:#ff79c6;">button +</span><span> </span><span style="color:#50fa7b;">type</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;submit&quot; +</span><span> </span><span style="color:#50fa7b;">onMouseOver</span><span style="color:#ff79c6;">={...} +</span><span> </span><span style="color:#50fa7b;">className</span><span style="color:#ff79c6;">={</span><span style="color:#50fa7b;">classNames</span><span>(</span><span style="color:#f1fa8c;">&#39;button&#39;</span><span>, </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">props</span><span style="color:#ff79c6;">.</span><span>className, { +</span><span> </span><span style="color:#f1fa8c;">&#39;button--disabled&#39;</span><span>: </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">state</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">isDisabled</span><span>, +</span><span> </span><span style="color:#f1fa8c;">&#39;button--hovered&#39;</span><span>: </span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">state</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">isHovered +</span><span> })</span><span style="color:#ff79c6;">} +</span><span>/&gt; +</span></code></pre> +<p>Perceba que o Classnames facilita a manipulação condicional de classes com React, removendo vĂĄrios blocos de <code>if</code>/<code>else</code> do seu cĂłdigo.</p> +<h2 id="2-react-router">2. <a href="https://www.npmjs.com/package/react-router">react-router</a></h2> +<p>Se vocĂȘ estĂĄ desenvolvendo uma <em>Single-page Application</em>, vocĂȘ precisarĂĄ sincronizar a interface do usuĂĄrio com a URL.</p> +<p>O React Router Ă© a melhor solução de rotas para aplicaçÔes desenvolvidas com React, e isso se deve bastante a sua API declarativa e pensada para componentes.</p> +<p>Considere a seguinte configuração de rotas:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">render </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react-dom&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">Router</span><span>, </span><span style="color:#ffffff;">Route</span><span>, </span><span style="color:#ffffff;">browserHistory </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;react-router&quot;</span><span>; +</span><span> +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">App </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;components/App&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">Homepage </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;screens/Homepage&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">About </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;screens/About&quot;</span><span>; +</span><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">Contact </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;screens/Contact&quot;</span><span>; +</span><span> +</span><span style="color:#50fa7b;">render</span><span>( +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Router </span><span style="color:#50fa7b;">history</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">browserHistory</span><span style="color:#ff79c6;">}</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Route </span><span style="color:#50fa7b;">path</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;/&quot; </span><span style="color:#50fa7b;">component</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">App</span><span style="color:#ff79c6;">}</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">IndexRoute </span><span style="color:#50fa7b;">component</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">Homepage</span><span style="color:#ff79c6;">} </span><span>/&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Route </span><span style="color:#50fa7b;">path</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;about&quot; </span><span style="color:#50fa7b;">component</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">About</span><span style="color:#ff79c6;">} </span><span>/&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Route </span><span style="color:#50fa7b;">path</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;contact&quot; </span><span style="color:#50fa7b;">component</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">Contact</span><span style="color:#ff79c6;">} </span><span>/&gt; +</span><span> &lt;/</span><span style="font-style:italic;color:#66d9ef;">Route</span><span>&gt; +</span><span> &lt;/</span><span style="font-style:italic;color:#66d9ef;">Router</span><span>&gt;, +</span><span> document</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">getElementById</span><span>(</span><span style="color:#f1fa8c;">&quot;react-root&quot;</span><span>) +</span><span>); +</span></code></pre> +<p>Perceba que hĂĄ uma instĂąncia inicial da rota e outras rotas aninhadas, formando uma hierarquia. Essa hierarquia Ă© a essĂȘncia do React Router.</p> +<p>Considere que temos um App (<code>App.js</code>):</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">React</span><span>, { </span><span style="color:#ffffff;">Component </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&#39;react&#39; +</span><span style="color:#ff79c6;">import </span><span>{ </span><span style="color:#ffffff;">IndexLink</span><span>, </span><span style="color:#ffffff;">Link </span><span>} </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&#39;react-router&#39; +</span><span> +</span><span style="font-style:italic;color:#ff79c6;">class </span><span>App </span><span style="color:#ff79c6;">extends </span><span style="text-decoration:underline;font-style:italic;color:#8be9fd;">Component </span><span>{ +</span><span> </span><span style="color:#50fa7b;">render</span><span>() { +</span><span> </span><span style="color:#ff79c6;">return </span><span>( +</span><span> &lt;</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">nav</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">IndexLink </span><span style="color:#50fa7b;">to</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;/&quot;</span><span>&gt;Homepage&lt;/</span><span style="color:#ff79c6;">li</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Link </span><span style="color:#50fa7b;">to</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;/about&quot;</span><span>&gt;About&lt;/</span><span style="font-style:italic;color:#66d9ef;">Link</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">Link </span><span style="color:#50fa7b;">to</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;/contact&quot;</span><span>&gt;Contact&lt;/</span><span style="font-style:italic;color:#66d9ef;">Link</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">nav</span><span>&gt; +</span><span> +</span><span> &lt;</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> </span><span style="color:#ff79c6;">{</span><span style="color:#bd93f9;">this</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">props</span><span style="color:#ff79c6;">.</span><span style="color:#ffffff;">children</span><span style="color:#ff79c6;">} +</span><span> &lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> ) +</span><span> } +</span><span>} +</span><span> +</span><span style="color:#ff79c6;">export default </span><span style="color:#ffffff;">App +</span></code></pre> +<p class="note"> +<p><strong>Dica</strong>: O componente acima nĂŁo tem um estado prĂłprio, portanto, ele Ă© um <em>Pure Component</em> (ou <em>Dumb Component</em>). Componentes sob estas condiçÔes podem – e devem – ser transformados em <em>Stateless Functional Components</em>. ^[Sugiro a leitura de <a href="https://medium.com/@joshblack/stateless-components-in-react-0-14-f9798f8b992d">Functional Stateless Components in React 0.14</a>]</p> +</p> +<p>Uma explicação rĂĄpida: Todas as subrotas da rota do componente <code>App</code> (os <code>&lt;Route&gt;</code> dentro de <code>&lt;Route&gt;</code>) terĂŁo seus componentes transferidos como props para o componente <code>App</code> (e por isso o <code>this.props.children</code>) ao entrar na rota atravĂ©s do <code>&lt;Link&gt;</code>.</p> +<p>A <a href="https://github.com/reactjs/react-router/tree/1.0.x/docs">documentação do React Router</a> dispensa quaisquer outras explicaçÔes!</p> +<h2 id="3-react-helmet">3. <a href="https://www.npmjs.com/package/react-helmet">react-helmet</a></h2> +<p>Dificilmente vocĂȘ usarĂĄ o React Router sem o Helmet. O Helmet te dĂĄ, no prĂłprio componente, o controle do <code>head</code> do documento.</p> +<p>Um caso de uso simples Ă© alterar o tĂ­tulo do documento, Ăștil quando a aplicação entra em uma nova rota:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="font-style:italic;color:#66d9ef;">Helmet </span><span style="color:#50fa7b;">title</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;Carrinho de Compras&quot; </span><span>/&gt; +</span></code></pre> +<h2 id="4-jsx-control-statements">4. <a href="https://www.npmjs.com/package/jsx-control-statements">jsx-control-statements</a></h2> +<p>JSX facilita a escrita da marcação do componente e torna seu cĂłdigo mais fĂĄcil de ler e entender. Mas e quando a renderização do componente Ă© condicional? E quando renderizamos componentes dinamicamente?</p> +<p>Seu cĂłdigo termina provavelmente assim:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> </span><span style="color:#ff79c6;">{</span><span style="color:#ffffff;">todos</span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">map</span><span>(</span><span style="font-style:italic;color:#8be9fd;">function </span><span>(</span><span style="font-style:italic;color:#ffb86c;">todo</span><span>, </span><span style="font-style:italic;color:#ffb86c;">index</span><span>) { +</span><span> </span><span style="color:#ff79c6;">return </span><span>&lt;</span><span style="font-style:italic;color:#66d9ef;">TodoItem </span><span style="color:#50fa7b;">data</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">todo</span><span style="color:#ff79c6;">} </span><span style="color:#50fa7b;">key</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">index</span><span style="color:#ff79c6;">} </span><span>/&gt;; +</span><span> })</span><span style="color:#ff79c6;">} +</span><span>&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span></code></pre> +<p>E assim:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt;</span><span style="color:#ff79c6;">{</span><span style="color:#ffffff;">condition </span><span style="color:#ff79c6;">&amp;&amp; </span><span>&lt;</span><span style="color:#ff79c6;">span</span><span>&gt;&lt;/</span><span style="color:#ff79c6;">span</span><span>&gt;</span><span style="color:#ff79c6;">}</span><span>&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span></code></pre> +<p>Ou de uma das vĂĄrias outras formas: condicionais inline, operaçÔes ternĂĄrias, funçÔes para renderizar componentes condicionalmente
 PrĂĄticas que, em grande escala, podem prejudicar a legibilidade do cĂłdigo. E Ă© na <strong>legibilidade</strong> que o jsx-control-statements vence.</p> +<p>O primeiro exemplo, por exemplo, ficaria assim:</p> +<pre data-lang="tsx" style="background-color:#282a36;color:#f8f8f2;" class="language-tsx "><code class="language-tsx" data-lang="tsx"><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">For </span><span style="color:#50fa7b;">each</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;todo&quot; </span><span style="color:#50fa7b;">index</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;index&quot; </span><span style="color:#50fa7b;">of</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">todos</span><span style="color:#ff79c6;">}</span><span>&gt; +</span><span> &lt;</span><span style="font-style:italic;color:#66d9ef;">TodoItem </span><span style="color:#50fa7b;">data</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">todo</span><span style="color:#ff79c6;">} </span><span style="color:#50fa7b;">key</span><span style="color:#ff79c6;">={</span><span style="color:#ffffff;">index</span><span style="color:#ff79c6;">} </span><span>/&gt; +</span><span> &lt;/</span><span style="font-style:italic;color:#66d9ef;">For</span><span>&gt; +</span><span>&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span></code></pre> +<h2 id="5-axios-ou-fetch-api">5. <a href="https://www.npmjs.com/package/axios">axios</a> ou Fetch API</h2> +<p>NĂŁo Ă© uma dependĂȘncia apenas de aplicaçÔes React, mas vocĂȘ provavelmente vai precisar de um cliente HTTP. (<strong>Um cliente HTTP de gente adulta</strong>, que nĂŁo Ă© o <code>$.ajax</code>.) Existem duas Ăłtimas opçÔes: <a href="https://www.npmjs.com/package/axios">axios</a> e o fetch (“<a href="https://fetch.spec.whatwg.org/">WHATWG Fetch API</a>”).</p> +<h3 id="axios">axios</h3> +<p>Uma biblioteca maravilhosa.</p> +<p>A API do axios Ă© completa: tĂȘm interceptadores de requisição, mĂșltiplas requisiçÔes em paralelo
 E suas requisiçÔes retornam lindas promises.</p> +<p>Fazendo uma requisição <code>POST</code>:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#ff79c6;">import </span><span style="color:#ffffff;">axios </span><span style="color:#ff79c6;">from </span><span style="color:#f1fa8c;">&quot;axios&quot;</span><span>; +</span><span> +</span><span style="color:#ffffff;">axios +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#50fa7b;">post</span><span>( +</span><span> </span><span style="color:#f1fa8c;">&quot;/api/pets&quot;</span><span>, +</span><span> { name: </span><span style="color:#f1fa8c;">&quot;Bard&quot;</span><span>, cat: </span><span style="color:#bd93f9;">false </span><span>}, +</span><span> { headers: { </span><span style="color:#f1fa8c;">&quot;X-Custom-Header&quot;</span><span>: </span><span style="color:#f1fa8c;">&quot;foobar&quot; </span><span>} } +</span><span> ) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">then</span><span>(() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Pet salvo com sucesso!&quot;</span><span>)) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">catch</span><span>((</span><span style="font-style:italic;color:#ffb86c;">response</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">response</span><span>)); +</span></code></pre> +<h3 id="fetch-api">Fetch API</h3> +<p>O fetch, por outro lado, jĂĄ Ă© um <em><a href="https://fetch.spec.whatwg.org/">living standard</a></em>, e, nesse momento, tem suporte bĂĄsico nos navegadores Firefox, Chrome e Opera. É recomendado, no entanto, o uso de um <a href="https://www.npmjs.com/package/isomorphic-fetch">polyfill</a>, por ser uma tecnologia ainda experimental.</p> +<p>A mesma requisição <code>POST</code> ficaria assim:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="color:#50fa7b;">fetch</span><span>(</span><span style="color:#f1fa8c;">&quot;/api/pets&quot;</span><span>, { +</span><span> method: </span><span style="color:#f1fa8c;">&quot;post&quot;</span><span>, +</span><span> headers: { </span><span style="color:#f1fa8c;">&quot;X-Custom-Header&quot;</span><span>: </span><span style="color:#f1fa8c;">&quot;foobar&quot; </span><span>}, +</span><span> body: { name: </span><span style="color:#f1fa8c;">&quot;Bard&quot;</span><span>, cat: </span><span style="color:#bd93f9;">false </span><span>}, +</span><span>}) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">then</span><span>(() </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Pet salvo com sucesso!&quot;</span><span>)) +</span><span> </span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">catch</span><span>((</span><span style="font-style:italic;color:#ffb86c;">response</span><span>) </span><span style="font-style:italic;color:#8be9fd;">=&gt; </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">response</span><span>)); +</span></code></pre> +<p class="note"> +<p>VocĂȘ pode saber mais sobre o Fetch API no <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Mozilla Developer Network</a>.</p> +</p> +<h2 id="consideracoes">ConsideraçÔes</h2> +<p>Embora eu tenha citado apenas cinco, existem diversas bibliotecas e componentes que descomplicam o processo de desenvolvimento de uma aplicação com React. Sem dĂșvidas, Ă© um dos ecossistemas mais relevantes que front-end jĂĄ teve.</p> +<p>Destaco que nĂŁo cobri um tĂłpico que, quando se trata de React, Ă© bastante pertinente: formulĂĄrios. <strong>Lidar com formulĂĄrios no React Ă© complicado.</strong> Nesse primeiro momento, resolvi deixar o tema de lado para nĂŁo fugir da proposta do artigo.</p> + + + + + O Til no JavaScript + 2015-10-31T00:00:00+00:00 + 2015-10-31T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/o-til-no-javascript/ + + <p class="summary"> +<p>Incompreendido, o operador til (<code>~</code>) Ă© um mistĂ©rio que ninguĂ©m discute. Primeiro, pois Ă© um operador bitwise, e, segundo, pois seus casos de uso sĂŁo bastante misteriosos
</p> +</p> +<h2 id="voce-consegue-dizer">VocĂȘ consegue dizer
</h2> +<p>em <strong>valor</strong> e <strong>tipo de dado</strong>, o que serĂĄ impresso no console nas situaçÔes abaixo?</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span style="color:#f1fa8c;">&quot;1&quot;</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#bd93f9;">8.2</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#bd93f9;">false</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span style="color:#f1fa8c;">&quot;5.9&quot;</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span>{}); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~-</span><span style="color:#bd93f9;">5.5</span><span>); +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#f1fa8c;">&quot;Tudo bem?&quot;</span><span>); +</span></code></pre> +<p>NĂŁo sabe? <em>Well
</em></p> +<h2 id="o-operador-til">O operador til</h2> +<p>Ou melhor, o operador <em>bitwise NOT</em>.</p> +<p>É importante falar isso pois Ă© importante entender o que <em>bitwise</em> significa. Operadores bitwise sĂŁo especiais em JavaScript: eles tratam todos seus operandos como uma sequĂȘncia de 32 bits (0 e 1) – ou seja, trabalham com <strong>representaçÔes binĂĄrias</strong> (nĂŁo decimais, como de praxe) de nossos operandos, e nos entregam valores nĂșmericos como se nada tivesse acontecido.</p> +<p>O <em>NOT</em> significa que todos os bits do operando serĂŁo invertidos (0 vira 1, 1 vira 0). Parece inĂștil quando nĂŁo estamos trabalhando com nĂșmeros binĂĄrios, mas as aplicaçÔes criativas tornam o operador mais interessante.</p> +<h3 id="regras-do">Regras do <code>~</code></h3> +<ol> +<li>Quando a expressĂŁo Ă© <code>null</code> ou <code>undefined</code>
 0.</li> +<li>Objetos sĂŁo convertidos para strings.</li> +<li>Strings sĂŁo convertidas para nĂșmeros, se possĂ­vel. Quando nĂŁo Ă© possĂ­vel
 0.</li> +<li>Valores booleanos sĂŁo tratados como nĂșmeros (0 para <code>false</code>, 1 para <code>true</code>).</li> +<li><em>Floating-points</em> sĂŁo convertidos excluindo a parte fracionada.</li> +<li>Todo nĂșmero inteiro <em>n</em> Ă© convertido para -(n + 1).</li> +</ol> +<p>As duas Ășltimas regras sĂŁo as mais importantes, pois elas implicam nas principais aplicaçÔes do operador. JĂĄ temos a resposta de alguns:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#bd93f9;">8.2</span><span>); </span><span style="color:#6272a4;">// =&gt; -9 +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#bd93f9;">false</span><span>); </span><span style="color:#6272a4;">// =&gt; -1 +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#f1fa8c;">&quot;Tudo bem?&quot;</span><span>); </span><span style="color:#6272a4;">// =&gt; -1 +</span></code></pre> +<p class="note"> +<p>Os nĂșmeros foram convertidos de acordo com a fĂłrmula -(n + 1). -9 Ă© resultado de - 8 - 1, por exemplo.</p> +</p> +<h3 id="dupla-negacao">Dupla negação</h3> +<p>Podemos usar dois operadores til (<em>double bitwise NOT</em>). Aqui, basta entender o trabalho do outro til: reinverter os bits.</p> +<p>Considerando <code>~n</code>, como anteriormente, temos -(n + 1) = <strong>- n - 1</strong>. Considerando <code>~~n</code>, temos -[-(n + 1)] = <strong>n + 1</strong>.</p> +<p>Perceba que as equaçÔes, quando somadas, se anulam. Pois essa Ă© a grande sacada de usar dois operadores til! Temos, entĂŁo:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span style="color:#f1fa8c;">&quot;1&quot;</span><span>); </span><span style="color:#6272a4;">// =&gt; 1 +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span style="color:#f1fa8c;">&quot;5.9&quot;</span><span>); </span><span style="color:#6272a4;">// =&gt; 5 +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~</span><span>{}); </span><span style="color:#6272a4;">// =&gt; 0 +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ff79c6;">~~-</span><span style="color:#bd93f9;">5.5</span><span>); </span><span style="color:#6272a4;">// =&gt; -5 +</span></code></pre> +<h2 id="aplicacoes">AplicaçÔes</h2> +<h3 id="truncar-numeros">Truncar nĂșmeros</h3> +<p>Pelo fato do operador converter removendo a parte fracionada, utilizĂĄ-lo para truncar nĂșmeros de forma fĂĄcil Ă© a aplicação mais comum:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">data </span><span style="color:#ff79c6;">= </span><span style="color:#bd93f9;">7.8926152</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">integer </span><span style="color:#ff79c6;">= ~~</span><span style="color:#ffffff;">data</span><span>; +</span><span> +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">integer</span><span>); </span><span style="color:#6272a4;">// =&gt; 7 +</span></code></pre> +<p class="note"> +<p>Embora o <code>~~</code> tenha sido, por muito tempo, usado no lugar de <code>Math.floor()</code>, o mĂ©todo mais parecido com ele que temos em JavaScript hoje Ă© o <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/trunc"><code>Math.trunc()</code></a> do ES2015.</p> +</p> +<h3 id="converter-string-para-numero">Converter string para nĂșmero</h3> +<p>Uma aplicação simples que se baseia em uma das regras de funcionamento do til: converter strings para nĂșmeros sempre que possĂ­vel; afinal, Ă© com nĂșmeros que o operador trabalha.</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">data </span><span style="color:#ff79c6;">= </span><span style="color:#f1fa8c;">&quot;2&quot;</span><span>; +</span><span style="font-style:italic;color:#8be9fd;">const </span><span style="color:#ffffff;">dataAsNumber </span><span style="color:#ff79c6;">= ~~</span><span style="color:#ffffff;">data</span><span>; +</span><span> +</span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#ffffff;">dataAsNumber</span><span>); </span><span style="color:#6272a4;">// =&gt; 2 +</span></code></pre> +<h3 id="verificar-a-existencia-de-um-item-no-array">Verificar a existĂȘncia de um item no array</h3> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">women </span><span style="color:#ff79c6;">= </span><span>[</span><span style="color:#f1fa8c;">&quot;Ada Lovelace&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;Joan of Arc&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;Marie Curie&quot;</span><span>]; +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#ff79c6;">~</span><span style="color:#ffffff;">women</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">indexOf</span><span>(</span><span style="color:#f1fa8c;">&quot;Ada Lovelace&quot;</span><span>)) { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Ada Lovelace was such an important woman!&quot;</span><span>); +</span><span>} +</span></code></pre> +<p>É difĂ­cil de compreender humanamente que o <code>if</code> estĂĄ verificando se Ada Lovelace estĂĄ incluĂ­da no array <code>women</code>, mas Ă© exatamente isso que estĂĄ acontecendo. VocĂȘ entendeu a razĂŁo pela qual isso funciona?</p> +<p class="note"> +<p>PoderĂ­amos verificar sem o <code>~</code>, mas nĂŁo funcionaria em casos em que o item do array Ă© o primeiro (Ă­ndice zero, e 0 retorna <code>false</code> como booleano). O operador til viabiliza essa verificação, em razĂŁo da conversĂŁo de um nĂșmero inteiro <em>n</em> para -(n + 1).</p> +</p> +<p>O equivalente humano, utilizando <a href="https://lodash.com/">Lodash</a> (<code>_</code>), seria:</p> +<pre data-lang="js" style="background-color:#282a36;color:#f8f8f2;" class="language-js "><code class="language-js" data-lang="js"><span style="font-style:italic;color:#8be9fd;">let </span><span style="color:#ffffff;">women </span><span style="color:#ff79c6;">= </span><span>[</span><span style="color:#f1fa8c;">&quot;Ada Lovelace&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;Joan of Arc&quot;</span><span>, </span><span style="color:#f1fa8c;">&quot;Marie Curie&quot;</span><span>]; +</span><span> +</span><span style="color:#ff79c6;">if </span><span>(</span><span style="color:#50fa7b;">_</span><span>(</span><span style="color:#ffffff;">women</span><span>)</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">contains</span><span>(</span><span style="color:#f1fa8c;">&quot;Ada Lovelace&quot;</span><span>)) { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">console</span><span style="color:#ff79c6;">.</span><span style="color:#8be9fd;">log</span><span>(</span><span style="color:#f1fa8c;">&quot;Ada Lovelace was such an important woman!&quot;</span><span>); +</span><span>} +</span></code></pre> +<h2 id="performance">Performance</h2> +<p>Usar <code>~~</code> em vez de <code>Math.floor</code> ou <code>Math.trunc</code> Ă© geralmente mais rĂĄpido. Dependendo da <em>JavaScript engine</em> do navegador e do caso de uso, no entanto, pode nĂŁo fazer muita diferença e atĂ© ser mais lento. Veja o <a href="http://jsperf.com/tilde-vs-floor">teste no JSPerf</a>.</p> +<p>De qualquer forma, a pĂ©ssima performance de quem lĂȘ um cĂłdigo com o desumano <code>~</code> pode nĂŁo valer o ganho de performance – que Ă© ignorĂĄvel de tĂŁo mĂ­nimo – em uma aplicação.</p> +<h2 id="consideracoes">ConsideraçÔes</h2> +<p>No geral, operadores bitwise, principalmente <code>~</code>, <code>|</code> e <code>&amp;</code>, possuem aplicaçÔes interessantes e bastante criativas.</p> +<p>Quanto ao <code>~~</code>, nĂŁo acredito que chegarĂĄ a se popularizar como aconteceu com o <code>!!</code>, que converte para um valor booleano. Em anos, a prĂĄtica com til nunca se tornou realmente popular, talvez pelo fato de ser um operador bitwise – e, portanto, pouco compreendido – e ter casos de uso bastante excĂȘntricos.</p> +<p>Ficam Ă  tĂ­tulo de curiosidade suas aplicaçÔes bastante criativas. ;-)</p> + + + + + O Que HĂĄ de Errado com a "Cultura jQuery" + 2015-09-20T09:56:05+00:00 + 2015-09-20T09:56:05+00:00 + + + + + Unknown + + + + + + /blog/o-que-ha-de-errado-com-a-cultura-jquery/ + + <p class="summary">Este nĂŁo Ă© um artigo sobre jQuery. Este Ă© um artigo sobre ferramentas, sim, mas Ă©, principalmente, um artigo sobre <b>anĂĄlise</b> e o protagonismo do desenvolvedor front-end nesse processo.</p> +<h2 id="resumo">Resumo</h2> +<p><strong>AplicaçÔes variam.</strong> Aprenda a definir a arquitetura da sua aplicação. Aprenda a reconhecer a necessidade de uma SPA (<em>Single Page Application</em>).</p> +<p>A “cultura jQuery” te afasta de tudo isso, e, portanto, distancia vocĂȘ do seu papel enquanto desenvolvedor front-end.</p> +<hr> +<h2 id="introducao">Introdução</h2> +<p>Se existe uma cultura nas agĂȘncias digitais do Brasil que Ă© unĂąnime, Ă© a cultura do jQuery. NĂŁo a cultura de utilizar todo o poder da biblioteca, no entanto, mas o hĂĄbito intrĂ­nseco de importar o <code>jqueryX.X.X.min.js</code> em todo projeto.</p> +<p>(Sim, em 2015.)</p> +<p>Sobre o que hĂĄ de errado, serei sucinta, pois, para esse artigo, espero um pĂșblico-alvo preguiçoso e acomodado.</p> +<h2 id="o-que-ha-de-errado">O que hĂĄ de errado</h2> +<p>
em usar jQuery em 2015? O que hĂĄ de errado em importar jQuery ao iniciar o meu projeto?</p> +<p>Analisando superficialmente, <strong>nada</strong>.</p> +<p>Mas isso tem dado brecha a uma zona de conforto profunda e, na minha experiĂȘncia, com raĂ­zes difĂ­ceis de arrancar. Essa cultura se expande e transcende aquilo que lhe deu origem. Portanto, perceba:</p> +<p><strong>Este nĂŁo Ă© um artigo sobre jQuery.</strong></p> +<p>A comunidade de AngularJS Ă© um exemplo de que isso nĂŁo Ă© sobre jQuery. Muitos migraram dele ao Angular sem abandonar a cultura. O resultado? Bem, muito tem sido dito sobre cĂłdigo Angular legado, que ninguĂ©m quer dar manutenção. A escolha errada jĂĄ foi feita, e isso Ă© demasiadamente penoso para a manutenção de uma aplicação complexa.</p> +<p>O fato Ă© que a <strong>cultura nĂŁo mudou.</strong> Ainda se adota biblioteca ou framework em escala sem pensar duas vezes.</p> +<h2 id="aprendendo-a-evitar">Aprendendo a evitar</h2> +<p><strong>Deve-se saber quando abranger uma visĂŁo holĂ­stica do projeto, e quando separar responsabilidades.</strong></p> +<p>A separação de responsabilidades se daria pela anĂĄlise dos requisitos da aplicação e dos desafios gerados, que trazem consigo o que chamo de “subproblemas” (<em>necessidades que surgem durante a anĂĄlise do desafio</em>), que devem ser solucionados separadamente. A visĂŁo holĂ­stica ajudaria a estruturar os componentes de forma consistente em um sistema, definindo uma arquitetura.</p> +<p>Falando de desenvolvimento front-end moderno (e, portanto, falando de front-end <strong>modular</strong> e de unidades encapsuladas e independentes, os componentes), essa separação de responsabilidades torna-se ainda mais fĂĄcil! Vejamos, abaixo, alguns subproblemas que surgem durante a anĂĄlise de requisitos, apenas para exemplificar o que quero dizer quando trato a decisĂŁo de ferramentas como uma solução para um subproblema.</p> +<p class="note"> +<p>Os exemplos a seguir nĂŁo explicam o front-end modular na prĂĄtica. Adianto, no entanto, ferramentas como <a href="http://browserify.org/">Browserify</a> ou <a href="https://webpack.github.io/">Webpack</a>, que fazem parte do <em>tooling</em> necessĂĄrio.</p> +</p> +<h3 id="1-resiquicoes-ajax">1. ResiquiçÔes Ajax</h3> +<p><strong>Subproblema</strong>: escrever Ajax em JavaScript Ă© pouco intuitivo, difĂ­cil de ler e escrever.</p> +<p><strong>Solução possĂ­vel</strong>: encapsular, no componente um mĂłdulo como <a href="https://github.com/ded/reqwest">Reqwest</a> e <a href="https://github.com/jakutis/httpinvoke">httpinvoke</a>. VocĂȘ pode, inclusive, utilizar <em>apenas</em> o Ajax do <a href="https://www.npmjs.com/package/jquery">jQuery</a> (e nĂŁo o jQuery inteiro!).</p> +<h3 id="2-manipulacao-excessiva-do-dom">2. Manipulação excessiva do DOM</h3> +<p><strong>Subproblemas</strong>: manipular DOM com JavaScript pode ser bastante exaustivo. TambĂ©m, manipular em um nĂ­vel excessivo Ă© extremamente custoso para a performance da aplicação.</p> +<p><strong>Solução possĂ­vel</strong>: <a href="https://github.com/Matt-Esch/virtual-dom">Virtual DOM</a>, que estĂĄ embutido em bibliotecas como <a href="https://facebook.github.io/react/">React</a> e <a href="https://lhorie.github.io/mithril/">Mithril</a>. Ou, se precisar mesmo do DOM, considere pacotes como <a href="https://github.com/ded/qwery">qwery</a> ou <a href="https://github.com/bevacqua/dominus">Dominus</a>, junto com <a href="https://www.npmjs.com/package/domready">domready</a>.</p> +<p class="note"> +<p>E se precisĂĄssemos de Ajax no React, por exemplo? <a href="http://facebook.github.io/react/docs/tutorial.html#getting-started">Este mau exemplo</a> na documentação do React importa o jQuery inteiro. Como vocĂȘ faria? ;-)</p> +</p> +<h3 id="sobre-arquitetura">Sobre arquitetura</h3> +<p>Esse tĂłpico deve ser tratado durante a visĂŁo holĂ­stica do projeto, isso Ă©, da aplicação enquanto sistema de componentes. O <strong>subproblema</strong> seria a necessidade de estrutura que uma aplicação requere.</p> +<p>Para isso, vocĂȘ nĂŁo precisa usar aquilo que Ă© tradicional (diretamente: <strong>vocĂȘ nĂŁo precisa usar MVC</strong>). Existem outras implementaçÔes de arquiteturas que nĂŁo a implementação feita pelo seu framework amado. Existem outras arquiteturas que nĂŁo <em>Model-View-Controller</em>.</p> +<p>Basicamente? Tenha um conhecimento decente de arquiteturas front-end (sugiro abrir a mente com <a href="https://facebook.github.io/react/blog/2014/05/06/flux.html">Flux</a>, que jĂĄ possui bastante materiais e implementaçÔes da arquitetura disponĂ­veĂ­s), e nĂŁo um conhecimento aprofundado de MVC.</p> +<h2 id="conclusao">ConclusĂŁo</h2> +<p>Conheça o projeto e saiba como analisar seus requisitos. O resultado deve ser uma descrição explĂ­cita da sua aplicação, com subproblemas jĂĄ reconhecidos e, entĂŁo, soluçÔes possĂ­veis, todas envolvidas por uma solução possĂ­vel maior, que Ă© a da arquitetura (definida durante a anĂĄlise holĂ­stica). Parece chato, mas vira hĂĄbito e acaba funcionando muito bem.</p> +<p><strong>Lembre-se de que existem habilidades que a documentação de uma ferramenta <em>nunca</em>_ te ajudarĂĄ a desenvolver.</strong></p> +<p>Com o tempo, vocĂȘ vai saber quando adotar um framework especĂ­fico em escala, quando optar por bibliotecas monolĂ­ticas, e terĂĄ, inclusive, seus preferidos a ponto de nĂŁo ter sempre que definir soluçÔes possĂ­veis para subproblemas que aplicaçÔes tĂȘm em comum.</p> +<p>(Em alguns projetos, vocĂȘ enxergarĂĄ padrĂ”es, por exemplo: <a href="https://github.com/ded/qwery">qwery</a>, <a href="https://www.npmjs.com/package/domready">domready</a> e <a href="https://www.npmjs.com/package/lodash">lodash</a> sĂŁo usados juntos frequentemente.)</p> +<p>Um dia, no entanto, suas ferramentas falharĂŁo, outras ferramentas se adaptĂŁo melhor Ă  realidade de seus projetos, e, entĂŁo, o ciclo de anĂĄlise recomeça. E vocĂȘ jĂĄ sabe como proceder.</p> +<h3 id="seja-curioso">Seja curioso</h3> +<p>No mais, seja curioso sobre arquiteturas de software, padrĂ”es de projeto, <em>tooling</em> — basta ser leitor(a). Seja curioso tambĂ©m sobre opiniĂ”es, principalmente quando elas tratam de desafios que ainda nĂŁo tivemos. A <strong>visĂŁo crĂ­tica</strong> Ă© ideal para abandonar a cultura jQuery.</p> +<p><strong>O estudo permite que as soluçÔes possĂ­veis surjam mais intuitivamente.</strong></p> +<p>A prĂĄtica virĂĄ com os desafios, e nesses desafios Ă© que deve entrar o seu protagonismo de apresentar soluçÔes possĂ­veis.</p> +<h2 id="notas">Notas</h2> +<p>Esse Ă© um rascunho de pensamentos que venho acumulando hĂĄ algum tempo em razĂŁo de experiĂȘncias de trabalho que tive, e confesso que eles podem ter sido apresentados de forma confusa, embora eu tenha me esforçado. Mas isso aqui nĂŁo era para ser receita de bolo, de verdade! AtĂ© mesmo os exemplos citados nĂŁo devem passar de exemplos.</p> +<p>A minha abordagem possui falhas, e uma deles Ă© que exige de quem desenvolve um conhecimento vasto de ferramentas, quando se usava apenas uma para tudo. (Para isso, recomendo um recurso disponĂ­vel no <a href="https://www.npmjs.com">npm</a> e mecanismos de busca: a busca.)</p> +<p>Mas perceba que o conhecimento vasto Ă© apenas de ferramentas. O conhecimento exigido pelas ferramentas em si acaba sendo menor do que o exigido por aquelas <em>all-in-one</em> como jQuery e AngularJS. O fato de encapsularmos dependĂȘncias considerando a necessidade de cada componente no front-end Ă© um modo de mantermos a curva de aprendizagem fragmentada.</p> +<p>De acordo com o que venho experimentando, desenvolver essa mentalidade tem retornado experiĂȘncias maravilhosas e, inclusive, gerado menos cĂłdigo legado. Basta apenas aplicĂĄ-la Ă  Engenharia de Software com bom senso.</p> +<h2 id="conteudo-sugerido">ConteĂșdo sugerido</h2> +<p>Os complementos abaixo sĂŁo apenas para despertar a curiosidade em relação aos conceitos apresentados neste artigo, e nĂŁo devem substituir o estudo necessĂĄrio para deixar de lado, na prĂĄtica, a “cultura jQuery”.</p> +<ul> +<li><a href="https://jsperf.com/virtual-dom-vs-real-dom">JSPerf: Real DOM vs Virtual DOM</a></li> +<li><a href="http://www.ebaytechblog.com/2014/10/02/dont-build-pages-build-modules/">Don’t Build Pages, Build Modules</a></li> +<li><a href="http://www.infoq.com/news/2014/05/facebook-mvc-flux">MVC Does Not Scale, Use Flux Instead</a></li> +<li><a href="https://medium.com/@milankinen/good-bye-flux-welcome-bacon-rx-23c71abfb1a7">Goodbye Flux, welcome Bacon/rx?</a></li> +<li>E, humildemente, o meu prĂłprio blog, pois pretendo falar mais sobre arquiteturas de aplicação e front-end modular (que adoro!) na teoria e prĂĄtica.</li> +</ul> +<hr /> +<p><strong>Se vocĂȘ entendeu a razĂŁo pela qual a “cultura jQuery” distancia vocĂȘ do seu papel, a mensagem foi entregue com sucesso.</strong></p> + + + + + A Guide to Favicons and Touch Icons + 2015-09-06T10:53:00+00:00 + 2015-09-06T10:53:00+00:00 + + + + + Unknown + + + + + + /blog/a-guide-to-favicons-and-touch-icons/ + + <div class="summary"> +<p>Favicon is a simplified visual element associated with a particular website, page or event, which you once found only in your browser’s address bar or bookmarks. Nowadays, the scenario is different: <strong>they are everywhere</strong>.</p> +</div> +<h2 id="introduction">Introduction</h2> +<p>Favicons provide a important visual indicator to people, and help them to easily associate your content (which can be a <em>website</em>, a <em>particular page</em> or even <em>events</em> like a new message) when browsing.</p> +<p>Formerly, they, also called shortcut icons or bookmark icons, were just tiny pieces of art designed to help users to browse through their tabs or bookmarks. Today, shortcut icons can also provide an app-like link on operational systems (Windows 8, Android, OS X and so on), and should therefore be considered for achieving a pleasant cross-platform experience.</p> +<p>This is a guide for using favicons today, the right way. At the end of this article, I’m sure you’ll be excited about SVG favicons.</p> +<!-- If you don't want to understand such a thing, just [jump to the bulletproof solutions](#Bulletproof_favicons). --> +<h2 id="usage">Usage</h2> +<p>Favicons in different dimensions are needed, so devices and browsers can pick the picture that fits best based on <code>sizes</code> attribute (little exception for Mozilla Firefox, which always gets the last favicon declared and scale it if necessary).</p> +<p>The images are not requested when not used. As said, browsers will get only what fits them best, therefore it’s important to provide the favicon in the required dimensions to avoid ugly scaled images.</p> +<h3 id="general">General</h3> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span style="color:#6272a4;">&lt;!-- I&#39;m lazy --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon.png&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Browser tabs --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-16x16.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;16x16&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Safari on OS X, IE10 Metro --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-32x32.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;32x32&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Google TV --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-96x96.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;96x96&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Chrome on Android --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-192x192.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;192x192&quot; </span><span>/&gt; +</span></code></pre> +<p class="note"> +<p>No need for <code>type="image/png"</code> when using HTML5.</p> +</p> +<p>You’ll need to provide a manifest in order to Chrome on Android’s icon to work properly. See <a href="https://gist.github.com/diessica/44ddce58c6094ce64d1d"><code>manifest.json</code> example</a>.</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;manifest&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;manifest.json&quot; </span><span>/&gt; +</span></code></pre> +<h4 id="lacking-of-png-support-on-ie-a-workaround">Lacking of PNG support on IE: a workaround</h4> +<p>Internet Explorer until version 11 and Safari don’t support PNG favicons. However, you can provide a fallback for IE up to 9:</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span style="color:#6272a4;">&lt;!--[if IE]&gt; &lt;link rel=&quot;shortcut icon&quot; href=&quot;favicon.ico&quot; /&gt; &lt;![endif]--&gt; +</span></code></pre> +<p class="note"> +<p>Notice the <code>shortcut</code>, which is a non-standard. Also, providing this fallback within a conditional comment is necessary; otherwise Chrome will use the ICO favicon, even if it supports PNG ones.</p> +</p> +<p><strong>I don’t recommend it</strong>, though, because IE 10 doesn’t support conditional comments (so it won’t get any favicon, as seen that it doesn’t support PNG too), and also because it encourages the use of the non-standard and confusing <code>shortcut</code>.</p> +<p>Luckily, you can workaround everything just placing a <code>favicon.ico</code> in the root directory (the browser will look for it <em>automagically</em>). Then <code>link</code> only the PNG favicon and don’t worry.</p> +<h3 id="web-clip-bookmarks">Web Clip bookmarks</h3> +<p>iOS users can add websites to their home screen – shortcuts called “Web Clip bookmarks”. The default icon is a thumbnail screenshot of the page, but developers can specify one instead.</p> +<p>You will need to provide a lot of dimensions in order to support both new devices and older (iOS6 and prior), however.</p> +<p>There’s a no-HTML way and a HTML way to provide those icons. It’s up to you.</p> +<h4 id="no-html-touch-icon-file">No-HTML: Touch Icon file</h4> +<p>Add a <code>apple-touch-icon-*.png</code> file, where <code>*</code> is the size to the root directory, instead. iOS Safari will look for the appropriate icon size, and if it doesn’t find any that fits best, it’ll use <code>apple-touch-icon.png</code>.</p> +<h4 id="link-tags">Link tags</h4> +<p>You can reuse the image of another favicon specifying a <code>href</code> (not possible while using the solution above).</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span style="color:#6272a4;">&lt;!-- Non-retina iPhone pre iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;57x57&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-57x57.png&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Non-retina iPad pre iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;60x60&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-60x60.png&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;72x72&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-72x72.png&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Non-retina iPad iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;76x76&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-76x76.png&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Retina iPhone pre iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link +</span><span> </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; +</span><span> </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;114x114&quot; +</span><span> </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-114x114.png&quot; +</span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Retina iPhone iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link +</span><span> </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; +</span><span> </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;120x120&quot; +</span><span> </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-120x120.png&quot; +</span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Retina iPad pre iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link +</span><span> </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; +</span><span> </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;144x144&quot; +</span><span> </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-144x144.png&quot; +</span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Retina iPad iOS 7 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link +</span><span> </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; +</span><span> </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;152x152&quot; +</span><span> </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-152x152.png&quot; +</span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- iOS 8 --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link +</span><span> </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon&quot; +</span><span> </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;180x180&quot; +</span><span> </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;apple-touch-icon-180x180.png&quot; +</span><span>/&gt; +</span></code></pre> +<p class="note"> +<p>Using <code>apple-touch-icon-precomposed</code> instead of <code>apple-touch-icon</code>, which prevents iOS icons defaults like rounded corners and reflective shine, isn’t necessary, as seen that there isn’t <em>shiny effects</em> on iOS 7 and up anymore.</p> +</p> +<h3 id="windows-tiles">Windows Tiles</h3> +<p>Tiles are icons that appear on the Start screen, linked as apps. By default, the image on the tile is the website’s favicon or a default IE11 logo.</p> +<p class="note">To cover a wide range of devices, use an image 1.8 times the standard tile size so the image can be scaled up or down as needed.</p> +<p>There’s a no-HTML way and a HTML way to provide those icons. It’s up to you, again.</p> +<h4 id="no-html-browser-config-file">No-HTML: Browser config file</h4> +<p>Provide a <code>browserconfig.xml</code> file and save it at the root of your server. Internet Explorer 11 will automatically read the file when the user pins the website. See <a href="https://gist.github.com/diessica/73a4d53cd26b4d35f410"><code>browserconfig.xml</code> example</a>.</p> +<h4 id="metadata-tags">Metadata tags</h4> +<p><code>msapplication-TileColor</code> is the background color of the tile, and <code>msapplication-TileImage</code> is the icon, which can be tiny (70 × 70px), square (150 × 150px), wide (310 × 150px) or large (310 × 310px).</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span style="color:#6272a4;">&lt;!-- Windows Tile --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-TileColor&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;#000&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-TileImage&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;tile-icon.png&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Different Windows Tiles (optional) --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-square70x70logo&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;tile-icon_tiny.png&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-square150x150logo&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;tile-icon_square.png&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-wide310x150logo&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;tile-icon_wide.png&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">meta </span><span style="color:#50fa7b;">name</span><span>=</span><span style="color:#f1fa8c;">&quot;msapplication-square310x310logo&quot; </span><span style="color:#50fa7b;">content</span><span>=</span><span style="color:#f1fa8c;">&quot;tile-icon_large.png&quot; </span><span>/&gt; +</span></code></pre> +<h2 id="bulletproof-favicons">Bulletproof favicons</h2> +<ul> +<li>For Touch Icons, add <code>apple-touch-icon.png</code> and <code>apple-touch-icon-*.png</code> files, where <code>*</code> is the size, to the root directory.</li> +<li>For IE support, add a <code>favicon.ico</code> file with both 16 × 16px and 32 × 32px resources to the root directory.</li> +<li>For Windows Tiles, add a <code>browserconfig.xml</code> to the root directory.</li> +<li>For Chrome on Android icon, add a <code>manifest.json</code> to the root directory.</li> +<li>Add the following HTML to <code>&lt;head&gt;</code>:</li> +</ul> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span style="color:#6272a4;">&lt;!-- Chrome on Android --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-192x192.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;192x192&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;manifest&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;manifest.json&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Google TV --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-96x96.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;96x96&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Safari on OS X, IE10 Metro --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-32x32.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;32x32&quot; </span><span>/&gt; +</span><span> +</span><span style="color:#6272a4;">&lt;!-- Browser tabs --&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon-16x16.png&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;16x16&quot; </span><span>/&gt; +</span></code></pre> +<p class="note"> +<p>Order matters here! Mozilla Firefox ignores <code>sizes</code> and always get the last favicon for the browser tabs. :-(</p> +</p> +<p>Or you can add all the favicons through <code>meta</code> and <code>link</code> tags.</p> +<h2 id="favicon-as-svg">Favicon as SVG</h2> +<p class="note"> +<p>Not encouraged as an unique solution, as seen that isn’t <a href="http://caniuse.com/#feat=link-icon-svg">widely supported</a> yet.</p> +</p> +<p>I’m excited about this:</p> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">link </span><span style="color:#50fa7b;">rel</span><span>=</span><span style="color:#f1fa8c;">&quot;icon&quot; </span><span style="color:#50fa7b;">href</span><span>=</span><span style="color:#f1fa8c;">&quot;favicon.svg&quot; </span><span style="color:#50fa7b;">sizes</span><span>=</span><span style="color:#f1fa8c;">&quot;any&quot; </span><span style="color:#50fa7b;">type</span><span>=</span><span style="color:#f1fa8c;">&quot;image/svg+xml&quot; </span><span>/&gt; +</span></code></pre> +<h2 id="final-words">Final words</h2> +<p>I’m sure you are now excited about SVG support for favicons. Providing a lot of different images is quite boring.</p> +<p>I encourage you to support favicons everywhere (or at least retina-ready ones), but unfortunately there’s no human-friendly way to do it nowadays. Use <a href="https://www.npmjs.com/package/favicons">favicons package</a> on npm or, if you are not comfortable with the command line, refer to <a href="http://realfavicongenerator.net">RealFaviconGenerator</a>.</p> +<p>Don’t be lazy.</p> +<h2 id="references">References</h2> +<ul> +<li><a href="https://developer.android.com/training/tv/index.html#favicons">Android Documentation</a></li> +<li><a href="https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html">Apple Documentation</a></li> +<li><a href="http://realfavicongenerator.net/faq">RealFaviconGenerator FAQ</a></li> +<li><a href="https://mathiasbynens.be/notes/touch-icons">Everything you always wanted to know about touch icons</a></li> +<li><a href="http://caniuse.com/#feat=link-icon-svg">SVG favicons support</a></li> +<li><a href="http://caniuse.com/#feat=link-icon-png">PNG favicons support</a></li> +<li><a href="http://iconhandbook.co.uk/reference/chart/">Icon handbook</a></li> +<li><a href="https://msdn.microsoft.com/en-us/library/dn455106.aspx">Creating custom tiles for IE11 websites</a></li> +</ul> + + + + + Como Eu Vi a BrazilJS 2015 + 2015-08-26T02:10:32+00:00 + 2015-08-26T02:10:32+00:00 + + + + + Unknown + + + + + + /blog/como-eu-vi-a-braziljs-2015/ + + <p>É mais experiente que volto de mais uma BrazilJS, evento que acontece na cidade onde nasci desde <a href="http://braziljs.com.br/2012">2012</a>. Aqui, compartilho nĂŁo um relatĂłrio tĂ©cnico das palestras, nĂŁo acusaçÔes do que foi ruim ou bom, mas minhas visĂ”es, em conjunto, sobre a conferĂȘncia e a comunidade.</p> +<p>Importante observar que <strong>nĂŁo</strong> seleciono aqui a “nata” do evento. NĂŁo Ă© minha intenção desmerecer qualquer acontecimento. Meu objetivo com esse texto Ă© somente compartilhar o meu ponto de vista sobre o que penso que deve ser comentado.</p> +<h2 id="o-primeiro-dia">O primeiro dia</h2> +<p>O meu dia começou localizando onde seria o evento. Neste ano, foi no BarraShoppingSul; um shopping que, considerando os outros da cidade, Ă© de difĂ­cil acesso mesmo para quem mora hĂĄ alguns quilĂŽmetros de Porto Alegre.</p> +<p>O Centro de ConvençÔes, ao menos, foi fĂĄcil de achar, e o <em>check-in</em> ocorreu como esperado: pontual. As meninas que forneceram minha credencial estavam de Ăłtimo humor — e olha que era um dos primeiros horĂĄrios da manhĂŁ de sexta! Ano passado, o meu <em>check-in</em> foi feito pelo Jaydson, o que fez eu me perguntar onde estaria ele, se nĂŁo credenciando os participantes do evento.</p> +<p>
E, na verdade, ele tinha se tornado um Power Ranger junto com o Felipe. E Power Rangers nĂŁo fazem <em>check-in</em>. Descobri isso da pior maneira.</p> +<h3 id="uma-abertura-idiota">Uma abertura idiota</h3> +<p>Dois desenvolvedores, os organizadores desse evento que trouxe mais de mil pessoas para o mesmo lugar, brincando de “lutinha” na frente de todo mundo, vestidos de Power Rangers sĂł porque o JavaScript fez 20 anos. <strong>Essa foi a abertura da BrazilJS</strong>, e eu nĂŁo mudaria nada.</p> +<p>Muita gente riu. Muita gente aplaudiu. Eu ri e aplaudi, e aplaudiria de novo, pois, sim, brincaram, mas tambĂ©m fizeram um trabalho muito sĂ©rio. Ainda vestidos de Power Rangers, falaram um pouco da histĂłria da conferĂȘncia e das expectativas para esse ano, finalizando com uma mensagem sobre a importĂąncia da diversidade e, sobretudo, do respeito.</p> +<p>Os eventos que se seguiram mostraram que, sim, o trabalho era sĂ©rio.</p> +<h3 id="christian-heillman">Christian Heillman</h3> +<blockquote> +<p>We are there for them. Not they for us.</p> +</blockquote> +<p>Com uma camiseta do Brasil, Christian chegou com um dos assuntos mais importantes na atualidade, e que estĂĄ dando muito o que falar: <em>pushing the web forward</em>. Palavras de protagonismo, reiteração do <strong>nosso papel</strong>, motivação para acreditar na web e no nosso trabalho, e, o mais importante: como isso deve ser feito. Falou, claro, sobre o ECMAScript 6, sobre o Babel, e fez uma anĂĄlise de como resolvemos os problemas atualmente.</p> +<blockquote> +<p>We all know the DOM is slow, terrible and to blame for all our problems. Did we allot it to say that way and still be a problem as we <strong>abstracted its issues away?</strong></p> +</blockquote> +<p>Acredito que essa essa frase foi pesada para muita gente, principalmente em quem estĂĄ deprimido de tanto <em>estudar</em> soluçÔes. Christian mostra que, ao trabalharmos com web, nĂŁo somos apenas desenvolvedores ou designers (ao menos nĂŁo deverĂ­amos ser). Somos tambĂ©m <strong>web makers</strong>, e esse Ă© o principal problema de simplesmente abstrair e deixar para lĂĄ.</p> +<p>É fĂĄcil entender a razĂŁo dessa abordagem. Heillman trabalha no time de desenvolvimento do Microsoft Edge, o novo e surpreendente navegador padrĂŁo do Windows 10, e esse Ă© o ponto de vista dele enquanto <em>browser maker</em>: somos a representação mĂĄxima do protagonismo, e, por isso, desenvolver nĂŁo deve limitar-se a <em>frameworks</em> ou <em>libraries</em>. Estamos em uma posição em que inovar sempre que possĂ­vel Ă© visto como uma contribuição, e ele ensina a entender esse ponto de vista desde a analogia feita logo nos primeiros slides. NĂŁo devemos esperar que a inovação venha apenas de grandes companhias.</p> +<p>NĂŁo disse para pararmos de usar ES6 com Babel. NĂŁo disse para usarmos ES6 em produção e beber ĂĄgua de coco na praia. Mas nĂŁo Ă© mentira que existem casos em que podemos, se assim desejarmos, relatar o que estĂĄ de errado e o que faz falta, e Ă© justamente aĂ­ que o nosso protagonismo Ă© mĂĄximo.</p> +<p>Os argumentos foram reĂșnidos, as situaçÔes em que podemos nos tornar <em>web makers</em> foram apresentadas, e tudo em prol de provar o nosso protagonismo.</p> +<blockquote> +<p>You are a creator of the next web!</p> +</blockquote> +<p>Sem dĂșvidas, uma das melhores palestras que jĂĄ assisti na minha vida. É difĂ­cil relatar uma interpretação detalhada sobre a mensagem do Christian, mas, aos que jĂĄ se sentiram no dever de fazer a web um lugar melhor alguma vez e nunca deixaram de acreditar nessa mĂ­dia, acho que essas minhas palavras foram mais que o suficiente para compreender o pensamento dele. Simples e sensacional.</p> +<h3 id="use-lowlevel">Use lowlevel</h3> +<p>Tive dificuldades em acompanhar o raciocĂ­nio do Douglas Campos algumas vezes, e noto que isso se deu em razĂŁo de ele nĂŁo estar falando a lĂ­ngua nativa. NĂŁo entro aqui no mĂ©rito das palestras em InglĂȘs ou PortuguĂȘs (para mim tanto faz desde que o palestrante consiga passar a mensagem de forma fluente na lĂ­ngua escolhida), mas reforço a importĂąncia de fazer a escolha certa, pois a tua escolha afeta um pĂșblico que estĂĄ confiando na tua capacidade enquanto transmissor.</p> +<p>Douglas falou sobre compiladores, e engajou os desenvolvedores a entender <em>how things work under the hood</em>, explorando conceitos como AST (<em>Abstract Syntax Tree</em>), um assunto que estĂĄ finalmente chamando a atenção em JavaScript, tanto que nĂŁo foi a primeira vez que foi abordado na BrazilJS.</p> +<p>Acredito que o questionamento que o palestrante buscou provocar no pĂșblico nĂŁo teve ĂȘxito. Os 30 minutos, infelizmente, nĂŁo foram bem aproveitados e nĂŁo atenderam Ă s perguntas que o Douglas tentou provocar e responder. Ficou a sensação de uma mensagem subentendida, no entanto:</p> +<blockquote> +<p>It’s really important for us to take a look at the things we don’t necessarily like.</p> +</blockquote> +<h3 id="javascript-at-spotify">JavaScript at Spotify</h3> +<p>Felipe Ribeiro juntou os desafios encontrados durante a transição do Spotify (nativo com C++ para hĂ­brido), e o resultado foi uma palestra bastante completa sobre arquitetura e engenharia de software. Diversificou bastante a programação da conferĂȘncia, e mostrou que devemos analisar a necessidade de re-escrita de cĂłdigo em uma aplicação complexa sob uma Ăłtica criteriosa que equilibra <strong>utilidade</strong>, <strong>valor</strong> e <strong>esforço necessĂĄrio</strong>.</p> +<h4 id="desafios">Desafios</h4> +<p>Os desafios foram bastante interessantes. Um deles foi o <strong>gerenciamento de memĂłria</strong> no Spotify, jĂĄ que se trata de uma aplicação que nĂŁo Ă© descartada com a mesma frequĂȘncia de um site. Outro, a <strong>organização do cĂłdigo</strong>, que era excessivamente fragmentado, o que prejudicava a padronização (diferentes versĂ”es de mĂłdulos), manutenção (atualização em “efeito cascata”) e integração contĂ­nua do projeto.</p> +<h4 id="releases">Releases</h4> +<p>O Spotify estabeleceu uma cultura colaborativa de testes (sempre gostei dessa abordagem!). Os empregados usam somente versĂ”es experimentais da aplicação, ajudando a testar e agilizar os <em>hotfixes</em>. O release Ă© gradual, e Ă© distribuĂ­do na medida em que a versĂŁo vai apresentando estabilidade aos usuĂĄrios que jĂĄ possuem acesso.</p> +<h3 id="a-saga-dos-12-topicos-de-acessibilidade">A saga dos 12 tĂłpicos de acessibilidade</h3> +<p>A primeira vez que conheci o Reinaldo Ferraz foi no Front in POA em 2012. Na Ă©poca, acessibilidade era mais novidade para as pessoas do que Sass. Todos conheciam Sass, ninguĂ©m conhecia WCAG.</p> +<p>Lembro de ter sido uma das palestras mais marcantes e diferentes do evento, e nĂŁo foi diferente na BrazilJS. Esta foi a mensagem que ficou:</p> +<blockquote><p>"Aplicar tĂ©cnicas de acessibilidade em um site com usabilidade ruim Ă© como passar batom em um porco. NĂŁo importa o quanto vocĂȘ passe, ele continuarĂĄ sendo um porco."</p><footer>— <cite><a href="http://webaim.org/blog/accessibility-lipstick-on-a-usability-pig/">Acessibility Lipstick on a Usability Pig</a></cite></footer></blockquote> +<h3 id="500-days-of-open-source">500 days of open source</h3> +<p>Uma palestra que dividiu bastante o pĂșblico. Na verdade, acredito que o Raphael Amorim deu o melhor dele para fazer o discurso significar exatamente o que ele queria que significasse. O Raphael sabe se comunicar muito bem, e paciĂȘncia foi o Ășnico requisito para captar a mensagem.</p> +<p>Vi muita dedicação na apresentação que ele fez. Organizou os aprendizados e os desafios de seguir Ă  risca <a href="http://ejohn.org/blog/write-code-every-day/">a proposta do John Resig</a>, e os apresentou mostrando que “preencher grade de contribuiçÔes” ou “se sentir no dever todo dia” nĂŁo Ă© o suficiente para progredir. Inclusive, para quem acredita que isso Ă© o suficiente, apresentou o <a href="https://github.com/avinassh/rockstar">Rockstar</a>.</p> +<p>Esse tipo de palestra Ă© <strong>essencial</strong>, e eu nĂŁo estou disposta a discutir isso com ninguĂ©m. Havia mais de mil pessoas no mesmo lugar, e, por mais que nĂŁo pareça, Ă© uma minoria que contribui ou gerencia algum projeto open source, e tambĂ©m Ă© uma minoria que contribui hĂĄ tempo o suficiente para passar por todos os desafios que o Raphael passou. Foi uma palestra sobre open source, mas tambĂ©m sobre esforço e saber o que estĂĄ te movendo para se esforçar mais: <strong>criar</strong>.</p> +<p>(Entendi o trocadilho no nome, a propĂłsito.)</p> +<h3 id="david-bryant">David Bryant</h3> +<blockquote> +<p>Happy birthday, JavaScript!</p> +</blockquote> +<p>Terminou o primeiro dia de BrazilJS tal como o Christian o iniciou: fazendo-nos acreditar no que trabalhamos. David Bryant, que faz parte do <a href="https://www.mozilla.org/en-US/about/leadership/"><em>leadership team da Mozilla</em></a>, falou sobre a evolução do JavaScript atĂ© o seu aniversĂĄrio de 20 anos, e em como devemos acreditar na web em detrimento da plataforma nativa. Para isso, lembrou da palestra Nick Desaulniers, anterior a dele, que mostrava quanto esforço tem sido feito para que a web alcance a plataforma nativa.</p> +<p>David, representando a Mozilla, deixou Ăłbvia a mensagem: <em>a web Ă© a melhor plataforma</em>.</p> +<h2 id="o-segundo-dia">O segundo dia</h2> +<h3 id="what-can-you-build-with-a-log">What can you build with a log</h3> +<p>James começa explicando sua motivação: a impermancĂȘncia e a centralização do conteĂșdo sĂŁo coisas negativas da web. O que podemos fazer sobre isso? UĂ©, abrir o Vim, e construir meu cliente torrent, Flickr, Twitter
</p> +<p>O Substack Ă© uma pessoa extremamente simples e humilde. É impossĂ­vel nĂŁo achĂĄ-lo, no mĂ­nimo, adorĂĄvel. Um dos <em>live codings</em> mais fluĂ­dos e espontĂąneos que jĂĄ assisti.</p> +<h3 id="reduce-seu-novo-melhor-amigo">Reduce: seu novo melhor amigo</h3> +<p>A Ju Gonçalves explicou o uso do <code>reduce()</code> na prĂĄtica. (Na prĂĄtica mesmo, para sair da BrazilJS usando, caso nunca tenha usado.)</p> +<p>O tema escolhido complementou muito bem a palestra de programação funcional do Jacob Page, anterior a dela. O formato ficou perfeito para 30 minutos (a propĂłsito, a ideia de abordar apenas o <code>reduce()</code> foi muito legal!), e deu para aprofundar bastante em algo que deve fazer parte do dia a dia. SĂł fiquei com a sensação de que 5 minutos a mais ajudariam ela a guiar os exemplos com mais calma. O tempo estava bastante inflexĂ­vel nesse quesito.</p> +<p>Enfim, a Ju sabe o que faz. NĂŁo a conhecia pessoalmente ainda, mas conheço o trabalho e o entusiasmo dela e apostaria nela de longe, tal como a organização da conferĂȘncia, sem dĂșvidas, fez.</p> +<h3 id="ecmascript-6-o-que-ha-de-novo-o-que-mudou-o-que-tem-de-bacana-ou-de-estranho">ECMAScript 6: O que HĂĄ de Novo, O que Mudou, O que tem de Bacana ou de Estranho!</h3> +<p>TĂ­tulo engraçado.</p> +<p>Quem foi na BrazilJS do ano passado sabe muito bem quem Ă© Jonathan Sampson. Em 2014, <a href="https://youtu.be/MMOZOkGfGGg?t=80">ele deu um nĂł na cabeça do Daniel Filho</a> ao falar PortuguĂȘs durante a entrevista.</p> +<p>No entanto, ano passado ele palestrou em InglĂȘs. Neste ano, ele falou sobre o ES6 totalmente em <strong>PortuguĂȘs</strong>, e fez muita gente rir com coisas simples, como, por exemplo, referir-se aos que nĂŁo entendiam <em>hoisting</em> de variĂĄveis como “<strong>chorĂ”es</strong> do Stack Overflow”, ou atĂ© mesmo perguntar como se traduz <em>replace</em> (todo mundo sabe que Ă© “substchitutituir”, no caso).</p> +<h3 id="javascript-robotics-a-nodebots-show">JavaScript Robotics: A NodeBots show</h3> +<p>JuliĂĄn Duque Ă© uma pessoa admirĂĄvel. Eu fico realmente muito alegre vendo o envolvimento dele com projetos como a <a href="http://nodeschool.io">NodeSchool</a>. Pelo tĂłpico da palestra, dĂĄ para ver como ele acredita bastante em JavaScript.</p> +<p>Como o <a href="https://twitter.com/seldo/status/635195901951107072">Laurie disse</a>, o trabalho feito foi sensacional. Mereceu todos os aplausos recebidos, tanto pela apresentação quanto pelos projetos paralelos que organizou.</p> +<p>E <a href="https://twitter.com/julian_duque/status/635209141217296385">ele fala PortuguĂȘs</a> (nĂŁo sĂł no Twitter).</p> +<h3 id="brendan-eich">Brendan Eich</h3> +<p>NĂŁo estive na BrazilJS 2012, entĂŁo esse foi o meu primeiro encontro com aquele conhecemos como <strong>criador do JavaScript</strong>.</p> +<p>A palestra dele foi engraçada, motivacional e tambĂ©m tĂ©cnica. Falou sobre como foi criar o JavaScript em 10 dias, deu explicaçÔes sobre o <a href="http://www.wtfjs.com/">wtfjs</a>, e mostrou o quanto valeu a pena acreditar no JavaScript.</p> +<p>Terminou com a frase que foi a grande mensagem da BrazilJS 2015: <em>always bet on JS</em>.</p> +<h2 id="o-fim">O fim</h2> +<p>O evento acabou com um show de rock e cerveja artesanal. NĂŁo sou uma pessoa agitada, nem gosto de beber cerveja, nem queria me arriscar a chegar tarde em casa (voltaria de ĂŽnibus), entĂŁo me limitei a finalizar meu dia indo falar com o Daniel Filho, que estava com outras duas pessoas, o Leonardo Balter e o <a href="http://igorapa.com/fui-aprender-ingles.html">Igor-que-foi-aprender-InglĂȘs</a>.</p> +<p>(Conversar com o Leonardo faz bem para a mente, pois ele nĂŁo sĂł se dispĂ”e a te ouvir como tambĂ©m te recebe bem. Se um dia encontrĂĄ-lo, inicie uma conversa, talvez vocĂȘ ganhe um grande amigo.)</p> +<p>Saindo do BarraShoppingSul, lembro que, fora do shopping, aquele Ă© um lugar deserto. <strong>Deserto</strong>. Em direção a parada, com meu computador na mochila, encontro um homem que promete nĂŁo me assaltar e que sĂł quer dinheiro para ir para casa. Dou o que tenho para ajudar, e ele insiste que eu dĂȘ mais, afirmando <em>saber</em> que eu tenho mais. Nego gentilmente, e entro no T4 para ir embora logo. E, aos que nĂŁo conhecem Porto Alegre, o T4 Ă© simplesmente <a href="http://zh.clicrbs.com.br/rs/porto-alegre/noticia/2014/12/a-rotina-do-t4-o-onibus-campeao-de-assaltos-em-porto-alegre-4658335.html">o ĂŽnibus mais inseguro da cidade</a>.</p> +<p>Era um assaltante. Isso foi me dito no ĂŽnibus por uma moça, que disse tambĂ©m que tive sorte de nĂŁo ter sido assaltada. NĂŁo entendi o que me salvou, se foi a distĂąncia que mantive do homem, se foi o fato de eu nĂŁo estar desatenta no celular
 Enfim, cheguei em casa bem e feliz com os dois dias que se passaram.</p> +<h2 id="notas-sobre-o-espaco">Notas sobre o espaço</h2> +<ul> +<li>O lugar onde a conferĂȘncia ocorreu Ă© legal, pareceu bem mais aberto que o Bourbon Country e nĂŁo distancia as pessoas de quem palestra. O Teatro do Bourbon Country Ă© confortĂĄvel, exageradamente belo, possui uma Ăłtima acĂșstica; mas, alĂ©m de enjoar, valoriza muito quem estĂĄ palestrando, pois Ă© um espaço para dar palestras e nada mais. Todo o networking que acontece ali Ă© fora de onde as palestas ocorrem.</li> +<li>O espaço nĂŁo Ă© mais aberto no sentido de <strong>nĂŁo te sufocar</strong>. O local fica no subsolo do shopping, portanto, nĂŁo hĂĄ acesso fĂĄcil e sem demora a rua, como havia no Bourbon Country. Lembro bem de ver o sol na BrazilJS do ano passado. Parece pouco, mas Ă© muito importante quando se fica dois dias no mesmo lugar, com luz artificial e tal. Isso simplesmente dĂĄ muita abertura para acelerar a fadiga, ainda mais que vocĂȘ acaba comendo no shopping pela facilidade (pois a Ășnica coisa que tem no bairro do Barra Ă© o prĂłprio Barra, sĂ©rio), entĂŁo vocĂȘ nunca sai dali. Sinceramente, durante essa BrazilJS, eu esqueci que orbitĂĄvamos ao redor de uma estrela chamada Sol. (Esse parĂĄgrafo Ă© muito pessoal, realmente nĂŁo espero que ninguĂ©m concorde comigo com meus exageros, e de nenhuma forma exijo que sejam levados em consideração.)</li> +<li>Muitas pessoas levam notebooks e o Espaço BrazilJS foi uma Ăłtima ideia para lidar com isso. Conciliou o Ăștil (reconferir palestras, programar durante <em>coffee break</em>) ao agradĂĄvel (nĂŁo ficar no computador durante palestras). É muito legal ter um lugar para ficar com o notebook, embora eu nĂŁo recomende levar caso vĂĄ embora de ĂŽnibus, como vivenciei.</li> +</ul> +<h2 id="notas-finais">Notas finais</h2> +<ul> +<li>Foi difĂ­cil comer e beber no primeiro dia. Percebi que, em vez de as pessoas organizarem-se em filas, muitas ficavam no entorno da mesa do <em>coffee break</em>, e isso dificultou muito o fluxo. No segundo dia, no entanto, foi bem mais organizado.</li> +<li>Os organizadores nĂŁo param. EstĂŁo sempre envolvidos com o evento, resolvendo pendĂȘncias e atendendo a feedbacks. Houve dedicação integral por parte do Daniel, Felipe e Jaydson em fazer uma conferĂȘncia confortĂĄvel para todos. O segundo dia nĂŁo foi mais tranquilo porque simplesmente foi e a a conferĂȘncia deste ano nĂŁo foi mais diversa porque simplesmente foi. Agradeço a eles por isso.</li> +<li>Percebi uma mudança de formato em vĂĄrios aspectos neste ano, e a principal delas foi a <strong>redução da duração das palestras</strong>. Bastante notĂĄvel. 30 minutos por padrĂŁo, e aproximadamente 1 hora para <em>keynotes</em>. Gostei bastante, jĂĄ que possibilitou uma transição bem saudĂĄvel entre assuntos e palestrantes, o que ajuda muito a digerir o conteĂșdo. A BrazilJS dura 2 dias inteiros que terminam cansativos, e Ă© fato que isso acelera o cansaço, mesmo quando a apresentação estĂĄ muito interessante.</li> +<li>Quanto mais eu comia o chocolate da Mozilla, mais eu queria. Tive de comer 7 seguidos para satisfazer o meu consumo desenfreado de açĂșcar. E nĂŁo recomendo para ninguĂ©m.</li> +<li>A quantidade de homens Ă© avassaladora. Embora as iniciativas em apoio Ă  diversidade tenham sido realmente efetivas (vi, por exemplo, mais mulheres neste ano), sabe-se bem que uma mulher na BrazilJS Ă© <strong>uma mulher em meio a homens</strong>. É o que a proporção permite afirmar.</li> +<li>NĂŁo havia camisetas da BrazilJS para mim, e isso me deixou um pouco triste, pois elas estavam muito bonitas neste ano. Segundo o Eu Compraria, a confecção foi apenas de versĂ”es masculinas da camiseta. No entanto, o problema nĂŁo Ă© a versĂŁo ser masculina, o problema Ă© que o tamanho P da versĂŁo masculina Ă© gigante em mim. AtĂ© a vendedora ficou com dĂł da minha situação. :-(</li> +<li>O BarraShoppingSul Ă© um shopping completo e muito espaçoso, mas o bairro onde ele estĂĄ Ă© bastante inseguro e difĂ­cil de acessar caso vocĂȘ nĂŁo esteja vindo de carro.</li> +<li>O Daniel Filho Ă© um apresentador muito legal.</li> +<li>A BrazilJS 2015 foi Ăłtima, e isso me deixa bastante ansiosa para a conferĂȘncia de 2016.</li> +</ul> +<p>AtĂ© o prĂłximo ano!</p> + + + + + Multiline Sass Comments + 2015-08-17T00:00:00+00:00 + 2015-08-17T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/multiline-sass-comments/ + + <p>Since the beginning of this year, I’ve created a lot of different boilerplates for projects. Working as a freelancer makes you challenge yourself everyday to find out what fits better while working. Currently, it’s sometimes Stylus, sometimes Sass.</p> +<p>Stylus is flexible, and I love it. Sass isn’t, but it’s cool anyway. Sometimes I find it hard to bear its inflexibility, though.</p> +<p>On GitHub, there’s a closed <a href="https://github.com/sass/sass/issues/338">issue about multiline comments on Sass</a> (<em>a Stylus feature!</em>), where I shared a solution for multiline Sass comments. A lot of people still don’t agree.</p> +<p>I just want people on community to know it, because it needs to be discussed.</p> +<h2 id="solution">Solution</h2> +<p>Start writing the comment as if it were single-line (<code>//</code>), then just follow its indentation. <a href="https://github.com/sass/sass/issues/338#issuecomment-131855911">Example</a>.</p> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span>// Multine comment +</span><span> Indent the </span><span style="color:#ff79c6;">text +</span><span> And this will be </span><span style="color:#ff79c6;">a</span><span> comment too +</span></code></pre> +<p>Is it available on Sass docs? Let me know!</p> + + + + + Desmitificando Seletores Complexos + 2013-11-28T00:00:00+00:00 + 2013-11-28T00:00:00+00:00 + + + + + Unknown + + + + + + /blog/desmitificando-seletores-complexos/ + + <p>Se existem recursos no CSS que a total compreensĂŁo se restringe a uma parcela de desenvolvedores, esses sĂŁo os combinadores filhos (&gt;), irmĂŁos adjacentes (+) e adjacentes gerais (~).</p> +<p>Sem dĂșvidas, esses 3 combinadores sĂŁo tĂŁo poderosĂ­ssimos quanto mal-explicados. É importante compreendĂȘ-los integralmente e hĂĄ dois bons motivos para isso: o seletor descendente nĂŁo dĂĄ conta de tudo e, o Ăłbvio: o CSS estĂĄ evoluindo.</p> +<h2 id="x-y">X &gt; Y</h2> +<blockquote> +<p>Todo filho Ă© necessariamente descendente, mas nem todo descendente Ă© necessariamente filho.</p> +<footer>— <cite>Eu, sobre famĂ­lia</cite></footer> +</blockquote> +<p>Para que Y seja alvo da seleção, nĂŁo importa a posição; basta que seja descendente direto de X - isso Ă©, filho. Em outras palavras, basta que esteja interno diretamente ao elemento pai - e seja somente descendente dele. Isso quer dizer que Y nĂŁo serĂĄ alvo caso esteja interno a um elemento Z, mesmo que este esteja interno a X. Por essa razĂŁo o combinador “&gt;” Ă© tambĂ©m chamado de <strong>direto</strong>, pois nĂŁo admite elementos internos indiretamente.</p> +<h3 id="seletor-descendente-vs-seletor-filho">Seletor descendente vs. seletor filho</h3> +<p>Lembrando da frase dita no inĂ­cio desse tĂłpico, vocĂȘ jĂĄ entende a diferença. Enquanto o <strong>descendente</strong> (X Y) herda as propriedades aos elementos direta e indiretamente internos (filhos, netos, bisnetos
), o alvo do <strong>combinador filho</strong> sĂŁo os filhos unicamente diretos - sim, falar isso Ă© redundante. O que faz todo sentido, afinal, um filho Ă© tanto filho quanto descendente; e o neto, bisneto, trineto nĂŁo Ă© um filho, mas Ă© descendente.</p> +<h4 id="na-pratica">Na prĂĄtica</h4> +<p>Imaginemos um artigo e seus respectivos parĂĄgrafos. Dentro desse artigo, haverĂĄ uma seção de informaçÔes que nĂŁo estarĂĄ diretamente relacionada ao artigo. Como o que se quer destacar Ă© a leitura do artigo, seus parĂĄgrafos terĂŁo mais ĂȘnfase de alguma forma.</p> +<h5 id="html">HTML</h5> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">article</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">h1</span><span>&gt;TĂ­tulo do artigo&lt;/</span><span style="color:#ff79c6;">h1</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Primeiro parĂĄgrafo&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Segundo parĂĄgrafo&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">aside</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">h2</span><span>&gt;InformaçÔes&lt;/</span><span style="color:#ff79c6;">h2</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit.&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> &lt;/</span><span style="color:#ff79c6;">aside</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Terceiro parĂĄgrafo&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span>&lt;/</span><span style="color:#ff79c6;">article</span><span>&gt; +</span></code></pre> +<h5 id="css">CSS</h5> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">article </span><span>&gt; </span><span style="color:#ff79c6;">p </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">font-style</span><span>: </span><span style="color:#6be5fd;">italic</span><span>; +</span><span>} +</span></code></pre> +<p>Assim, somente os parĂĄgrafos que sĂŁo filhos diretos do elemento <strong>article</strong> serĂŁo estilizados.</p> +<h2 id="x-y-1">X + Y</h2> +<p>Se para ser alvo do seletor filho a posição era irrelevante, para ser alvo de um <strong>seletor irmĂŁo adjacente</strong> sua posição Ă© critĂ©rio decisivo. O elemento Y deve ser o primeiro elemento apĂłs X, com ambos dentro de um mesmo elemento Z (pai). O nome, portanto, Ă© bem autoexplicativo: sĂŁo <strong>irmĂŁos</strong> por possuĂ­rem o mesmo pai (no caso, Z) e <strong>adjacentes</strong> por estarem necessariamente prĂłximos.</p> +<h4 id="na-pratica-1">Na prĂĄtica 1</h4> +<p>Supondo um artigo constituĂ­do por um tĂ­tulo e 3 parĂĄgrafos. O primeiro parĂĄgrafo apĂłs o tĂ­tulo servirĂĄ como uma introdução ao artigo e, portanto, deve ser destacado com um aumento no tamanho da fonte.</p> +<h5 id="html-1">HTML</h5> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">article</span><span>&gt; +</span><span> </span><span style="color:#6272a4;">&lt;!-- Z --&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">h1</span><span>&gt;TĂ­tulo do artigo&lt;/</span><span style="color:#ff79c6;">h1</span><span>&gt; +</span><span> </span><span style="color:#6272a4;">&lt;!-- X --&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit.&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> </span><span style="color:#6272a4;">&lt;!-- Y --&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Debitis sint aperiam numquam nisi animi porro in reprehenderit!&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span> &lt;</span><span style="color:#ff79c6;">p</span><span>&gt;Magnam atque placeat fuga sed eligendi maxime neque labore. Doloribus?&lt;/</span><span style="color:#ff79c6;">p</span><span>&gt; +</span><span>&lt;/</span><span style="color:#ff79c6;">article</span><span>&gt; +</span></code></pre> +<h5 id="css-1">CSS</h5> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">h1 </span><span>+ </span><span style="color:#ff79c6;">p </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">font-size</span><span>: </span><span style="color:#bd93f9;">20</span><span style="color:#ff79c6;">px</span><span>; +</span><span>} +</span></code></pre> +<h4 id="na-pratica-2">Na prĂĄtica 2</h4> +<p>O <strong>checkbox hack</strong> funciona com o uso do combinador irmĂŁo adjacente.</p> +<h4 id="html-2">HTML</h4> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">input </span><span style="color:#50fa7b;">type</span><span>=</span><span style="color:#f1fa8c;">&quot;checkbox&quot; </span><span style="color:#50fa7b;">id</span><span>=</span><span style="color:#f1fa8c;">&quot;hider&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt;Hide me if you can!&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">label </span><span style="color:#50fa7b;">for</span><span>=</span><span style="color:#f1fa8c;">&quot;hider&quot;</span><span>&gt;Esconder div&lt;/</span><span style="color:#ff79c6;">label</span><span>&gt; +</span></code></pre> +<h4 id="css-2">CSS</h4> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">input</span><span>[</span><span style="color:#50fa7b;">type</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;checkbox&quot;</span><span>] { +</span><span> </span><span style="font-style:italic;color:#66d9ef;">display</span><span>: </span><span style="color:#6be5fd;">none</span><span>; </span><span style="color:#6272a4;">/* Esconde o checkbox */ +</span><span>} +</span><span style="color:#ff79c6;">input</span><span>:checked + </span><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">display</span><span>: </span><span style="color:#6be5fd;">none</span><span>; </span><span style="color:#6272a4;">/* Quando o checkbox for checado, a div serĂĄ escondida */ +</span><span>} +</span></code></pre> +<h2 id="x-y-2">X ~ Y</h2> +<p>Seletor do <strong>CSS 3</strong>, o combinador <strong>adjacente geral</strong> tem uma definição bem semelhante ao irmĂŁo adjacente. Para que Y seja alvo, os elementos X e Y devem ser filhos de um mesmo elemento (irmĂŁos) e X deve preceder Y, direta ou indiretamente - isso Ă©, para que Y seja alvo, esse precedimento nĂŁo precisa ser imediato.</p> +<h4 id="na-pratica-3">Na prĂĄtica</h4> +<p>Esse combinador contorna algumas inflexibilidades do <strong>combinador irmĂŁo adjacente</strong>. Ainda com o exemplo do <strong>checkbox hack</strong>, podemos personalizar o elemento de forma nĂŁo tĂŁo especĂ­fica quanto Ă  sua posição:</p> +<h4 id="html-3">HTML</h4> +<pre data-lang="html" style="background-color:#282a36;color:#f8f8f2;" class="language-html "><code class="language-html" data-lang="html"><span>&lt;</span><span style="color:#ff79c6;">input </span><span style="color:#50fa7b;">type</span><span>=</span><span style="color:#f1fa8c;">&quot;checkbox&quot; </span><span style="color:#50fa7b;">id</span><span>=</span><span style="color:#f1fa8c;">&quot;shower&quot; </span><span>/&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">label </span><span style="color:#50fa7b;">for</span><span>=</span><span style="color:#f1fa8c;">&quot;shower&quot;</span><span>&gt;Mostrar div&lt;/</span><span style="color:#ff79c6;">label</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt;Hide me if you can!&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span><span>&lt;</span><span style="color:#ff79c6;">div</span><span>&gt;Hide me too if you can!&lt;/</span><span style="color:#ff79c6;">div</span><span>&gt; +</span></code></pre> +<h4 id="css-3">CSS</h4> +<pre data-lang="css" style="background-color:#282a36;color:#f8f8f2;" class="language-css "><code class="language-css" data-lang="css"><span style="color:#ff79c6;">input</span><span>[</span><span style="color:#50fa7b;">type</span><span style="color:#ff79c6;">=</span><span style="color:#f1fa8c;">&quot;checkbox&quot;</span><span>], +</span><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">display</span><span>: </span><span style="color:#6be5fd;">none</span><span>; </span><span style="color:#6272a4;">/* Esconde o checkbox e a div, por padrĂŁo */ +</span><span>} +</span><span style="color:#ff79c6;">input</span><span>:checked ~ </span><span style="color:#ff79c6;">div </span><span>{ +</span><span> </span><span style="font-style:italic;color:#66d9ef;">display</span><span>: </span><span style="color:#6be5fd;">block</span><span>; </span><span style="color:#6272a4;">/* Quando o checkbox for checado, a div aparecerĂĄ */ +</span><span>} +</span></code></pre> +<h2 id="conclusao">ConclusĂŁo</h2> +<p>As linguagens CSS e HTML foram documentadas para serem intuitivas: os elementos formam famĂ­lias com outros elementos pais, filhos, descendentes, irmĂŁos
. Isso fica claro no nome dos seletores, que tĂȘm papel importante na compreensĂŁo do combinador; afinal, caso o desenvolvedor entenda que irmĂŁos tem o mesmo pai e que filhos sĂŁo descendentes diretos do pai, ele poderĂĄ tirar um bom proveito do nome dos combinadores para compreender seus funcionamentos.</p> +<blockquote> +<p>[
] In both cases, non-element nodes (e.g. text between elements) are ignored when considering adjacency of elements.<footer> <cite><span>W3C</span>, sobre <a href="http://www.w3.org/TR/css3-selectors/">Selectors Level 3</a></cite></footer></p> +</blockquote> +<p>HĂĄ uma grande confusĂŁo - e com razĂŁo - entre os seletores irmĂŁos adjacentes e irmĂŁos gerais. Essa confusĂŁo se origina nĂŁo sĂł de suas classificaçÔes como <a href="http://www.w3.org/TR/css3-selectors/#sibling-combinators">seletores de combinação</a>, mas em seus comportamento e definição semelhantes. Tanto Ă© verdade que o combinador adjacente geral (~) se comportarĂĄ muitas vezes como um irmĂŁo adjacente (+), com a diferença de que o adjacente geral Ă© menos exigente quanto Ă  posição do elemento-alvo.</p> +<p>O uso serĂĄ, portanto, facultativo em diversas situaçÔes. E, nesse caso, a minha recomendação Ă© dar prioridade ao combinador adjacente, visto que Ă© um seletor do CSS 2.1 e, portanto, compatĂ­vel com uma maior gama de browsers. :-)</p> +<h2 id="referencias">ReferĂȘncias</h2> +<ul> +<li><strong>W3C</strong>. <a href="http://www.w3.org/TR/CSS21/selector.html">Selectors</a></li> +<li><strong>W3C</strong>. <a href="http://www.w3.org/TR/css3-selectors/">Selectors Level 3</a>, 29 setembro de 2011</li> +</ul> + + + + diff --git a/blog/5-bibliotecas-essenciais-para-desenvolver-react-apps/index.html b/blog/5-bibliotecas-essenciais-para-desenvolver-react-apps/index.html new file mode 100644 index 0000000..f204b19 --- /dev/null +++ b/blog/5-bibliotecas-essenciais-para-desenvolver-react-apps/index.html @@ -0,0 +1,79 @@ +5 Bibliotecas Essenciais para Desenvolver React Apps | DiĂ©ssica Gurskas
diessi.caBlog
March 21, 2016

5 Bibliotecas Essenciais para Desenvolver React Apps

O conjunto de ferramentas, boilerplates e bibliotecas disponĂ­veis formam um ecossistema incrĂ­vel em torno do React.

No meio de tudo, existem ferramentas que sĂŁo comuns – e essenciais – a diversas aplicaçÔes, independente de suas arquiteturas. Cito cinco delas.

1. classnames

Muitas vezes, no React, um estado representará um comportamento visual do componente (“selecionado”, “pressionado”, “focado”), normalmente associado a uma classe CSS.

Um botĂŁo e seus estados disabled e hovered, por exemplo, ficariam assim:

<button
+  type="submit"
+  onMouseOver={...}
+  className={classNames('button', this.props.className, {
+    'button--disabled': this.state.isDisabled,
+    'button--hovered': this.state.isHovered
+  })}
+/>
+

Perceba que o Classnames facilita a manipulação condicional de classes com React, removendo vårios blocos de if/else do seu código.

2. react-router

Se vocĂȘ estĂĄ desenvolvendo uma Single-page Application, vocĂȘ precisarĂĄ sincronizar a interface do usuĂĄrio com a URL.

O React Router é a melhor solução de rotas para aplicaçÔes desenvolvidas com React, e isso se deve bastante a sua API declarativa e pensada para componentes.

Considere a seguinte configuração de rotas:

import React from "react";
+import { render } from "react-dom";
+import { Router, Route, browserHistory } from "react-router";
+
+import App from "components/App";
+import Homepage from "screens/Homepage";
+import About from "screens/About";
+import Contact from "screens/Contact";
+
+render(
+  <Router history={browserHistory}>
+    <Route path="/" component={App}>
+      <IndexRoute component={Homepage} />
+      <Route path="about" component={About} />
+      <Route path="contact" component={Contact} />
+    </Route>
+  </Router>,
+  document.getElementById("react-root")
+);
+

Perceba que hĂĄ uma instĂąncia inicial da rota e outras rotas aninhadas, formando uma hierarquia. Essa hierarquia Ă© a essĂȘncia do React Router.

Considere que temos um App (App.js):

import React, { Component } from 'react'
+import { IndexLink, Link } from 'react-router'
+
+class App extends Component {
+  render() {
+    return (
+      <div>
+        <nav>
+          <IndexLink to="/">Homepage</li>
+          <Link to="/about">About</Link>
+          <Link to="/contact">Contact</Link>
+        </nav>
+
+        <div>
+          {this.props.children}
+        </div>
+      </div>
+    )
+  }
+}
+
+export default App
+

Dica: O componente acima nĂŁo tem um estado prĂłprio, portanto, ele Ă© um Pure Component (ou Dumb Component). Componentes sob estas condiçÔes podem – e devem – ser transformados em Stateless Functional Components. ^[Sugiro a leitura de Functional Stateless Components in React 0.14]

Uma explicação råpida: Todas as subrotas da rota do componente App (os <Route> dentro de <Route>) terão seus componentes transferidos como props para o componente App (e por isso o this.props.children) ao entrar na rota através do <Link>.

A documentação do React Router dispensa quaisquer outras explicaçÔes!

3. react-helmet

Dificilmente vocĂȘ usarĂĄ o React Router sem o Helmet. O Helmet te dĂĄ, no prĂłprio componente, o controle do head do documento.

Um caso de uso simples Ă© alterar o tĂ­tulo do documento, Ăștil quando a aplicação entra em uma nova rota:

<Helmet title="Carrinho de Compras" />
+

4. jsx-control-statements

JSX facilita a escrita da marcação do componente e torna seu código mais fåcil de ler e entender. Mas e quando a renderização do componente é condicional? E quando renderizamos componentes dinamicamente?

Seu cĂłdigo termina provavelmente assim:

<div>
+  {todos.map(function (todo, index) {
+    return <TodoItem data={todo} key={index} />;
+  })}
+</div>
+

E assim:

<div>{condition && <span></span>}</div>
+

Ou de uma das vĂĄrias outras formas: condicionais inline, operaçÔes ternĂĄrias, funçÔes para renderizar componentes condicionalmente
 PrĂĄticas que, em grande escala, podem prejudicar a legibilidade do cĂłdigo. E Ă© na legibilidade que o jsx-control-statements vence.

O primeiro exemplo, por exemplo, ficaria assim:

<div>
+  <For each="todo" index="index" of={todos}>
+    <TodoItem data={todo} key={index} />
+  </For>
+</div>
+

5. axios ou Fetch API

NĂŁo Ă© uma dependĂȘncia apenas de aplicaçÔes React, mas vocĂȘ provavelmente vai precisar de um cliente HTTP. (Um cliente HTTP de gente adulta, que nĂŁo Ă© o $.ajax.) Existem duas Ăłtimas opçÔes: axios e o fetch (“WHATWG Fetch API”).

axios

Uma biblioteca maravilhosa.

A API do axios Ă© completa: tĂȘm interceptadores de requisição, mĂșltiplas requisiçÔes em paralelo
 E suas requisiçÔes retornam lindas promises.

Fazendo uma requisição POST:

import axios from "axios";
+
+axios
+  .post(
+    "/api/pets",
+    { name: "Bard", cat: false },
+    { headers: { "X-Custom-Header": "foobar" } }
+  )
+  .then(() => console.log("Pet salvo com sucesso!"))
+  .catch((response) => console.log(response));
+

Fetch API

O fetch, por outro lado, jĂĄ Ă© um living standard, e, nesse momento, tem suporte bĂĄsico nos navegadores Firefox, Chrome e Opera. É recomendado, no entanto, o uso de um polyfill, por ser uma tecnologia ainda experimental.

A mesma requisição POST ficaria assim:

fetch("/api/pets", {
+  method: "post",
+  headers: { "X-Custom-Header": "foobar" },
+  body: { name: "Bard", cat: false },
+})
+  .then(() => console.log("Pet salvo com sucesso!"))
+  .catch((response) => console.log(response));
+

VocĂȘ pode saber mais sobre o Fetch API no Mozilla Developer Network.

ConsideraçÔes

Embora eu tenha citado apenas cinco, existem diversas bibliotecas e componentes que descomplicam o processo de desenvolvimento de uma aplicação com React. Sem dĂșvidas, Ă© um dos ecossistemas mais relevantes que front-end jĂĄ teve.

Destaco que nĂŁo cobri um tĂłpico que, quando se trata de React, Ă© bastante pertinente: formulĂĄrios. Lidar com formulĂĄrios no React Ă© complicado. Nesse primeiro momento, resolvi deixar o tema de lado para nĂŁo fugir da proposta do artigo.

\ No newline at end of file diff --git a/blog/a-better-es2015-and-jsx-workflow-in-vs-code/index.html b/blog/a-better-es2015-and-jsx-workflow-in-vs-code/index.html new file mode 100644 index 0000000..1be0459 --- /dev/null +++ b/blog/a-better-es2015-and-jsx-workflow-in-vs-code/index.html @@ -0,0 +1,7 @@ +A Better ES2015+ and JSX Workflow in VS Code | Diéssica Gurskas
diessi.caBlog
October 30, 2016

A Better ES2015+ and JSX Workflow in VS Code

Lately I’ve been trying VS Code, a code editor based on Electron. Since then, it really surprised me and it’s been a nice coding experience.

But


By default, JS syntax highlighting and ES2015+ and JSX support don’t work as expected.

I’ve tried to workaround it by using:

  1. Atom grammar. JSX support was pretty bad.
  2. A development branch of VS Code colorization, which is delivered as an extension. Finally got JSX to work properly, but syntax highlighting was still missing something.

So, no success.

Improving your VS Code workflow

After much trial and error, I came up with a better JS workflow in VS Code.

1. Fix JS syntax highlighting

Install the Sublime Babel extension and make sure you’re using one of the suggested color themes. (I like Charcoal Oceanic Next!)

2. Use “JavaScript React” in .js files

VS Code only uses “JavaScript React” syntax in .jsx files. Add the following to your User (or Workspace) Settings:

"files.associations": {
+  "*.js": "javascriptreact"
+}
+

3. Enable Emmet for JSX

(That’s a plus!)

VS Code uses Emmet by default, but doesn’t enable it for .jsx files. Add the following to your User Settings:

"emmet.syntaxProfiles": {
+  "javascript": "jsx"
+}
+

Let’s improve VS Code!

There has been improvements for JS grammar already, but it’s still not perfect.

Fortunately, VS Code is an open source project and can be improved by developers like us! Let’s not leave it like this. Give useful feedback and help!

Happy coding!

\ No newline at end of file diff --git a/blog/a-bit-on-random-numbers-in-javascript/index.html b/blog/a-bit-on-random-numbers-in-javascript/index.html new file mode 100644 index 0000000..c2dc065 --- /dev/null +++ b/blog/a-bit-on-random-numbers-in-javascript/index.html @@ -0,0 +1,10 @@ +A Bit on Random Numbers in JavaScript | Diéssica Gurskas
diessi.caBlog
November 15, 2016

A Bit on Random Numbers in JavaScript

Math.random() is a JavaScript function that outputs a random number in the range [0, 1) (from 0 up to 1, but doesn’t include 1). It’s the main source of randomness in JavaScript.

Although the output looks random, it’s actually not.

Behind the Scenes

Math.random() uses a pseudo-random number generator (PRNG). Those algorithms work completely determined by a initial value called “seed”.

Given a seed, the sequence of random numbers is deterministic.

Every PRNG requires a seed, which generally is the current system time in milliseconds. Yeah, simple as that.

Speaking of JavaScript language, the PRNG algorithm to deal with the seed is left up to implementors1. The algorithm powering V8’s Math.random() was very poor quality until last year (2015), and implementations between engines were pretty inconsistent.

But the scenario has changed. Currently, JavaScript Engines such as SpiderMonkey, V8, Webkit and Chakra all implements Xorshift128+ algorithm2, faster than the previous one.

Secure Randomness

Although randomness was improved in most JavaScript engines, it isn’t trustworthy as seen that standard PRNGs are highly predictable after a certain period. That’s where Web Crypto API shines!

Web Cryptography API introduces window.crypto.getRandomValues, a cryptographically secure pseudo-random number generator (CSPNG), whose output is impossible or highly improbable to distinguish from a truly random one.

Example

// Array containing two 32-bit integers
+const arr = new Int32Array(2);
+
+// Override array integers with random values
+const random = crypto.getRandomValues(arr);
+
+for (let i = 0; i < random.length; i++) {
+  console.log(random[i]);
+}
+

Of course it comes at a performance cost, so make sure you really need secure random numbers in your program.

Conclusion

If you need apparent randomness–less and speed, you’d probably better off using Math.random(). If you need high-quality randomness, such as in cryptography applications, hashing or statistics, go for a CSPNG such as window.crypto.getRandomValues instead.

\ No newline at end of file diff --git a/blog/a-cascata-das-variaveis-do-css/index.html b/blog/a-cascata-das-variaveis-do-css/index.html new file mode 100644 index 0000000..22344ab --- /dev/null +++ b/blog/a-cascata-das-variaveis-do-css/index.html @@ -0,0 +1,45 @@ +A Cascata das Variåveis do CSS | Diéssica Gurskas
diessi.caBlog
May 30, 2016

A Cascata das VariĂĄveis do CSS

Suporte | Especificação

Muito embora todos os seres humanos do Planeta Terra tenham odiado sua sintaxe, as variĂĄveis finalmente chegaram ao CSS – e elas sĂŁo mais poderosas do que vocĂȘ imagina!

Motivação

O desenvolvimento de grandes aplicaçÔes web implica inevitavelmente em grandes folhas de estilo, que devem ser organizadas de forma que facilite a manutenção. Muitos valores definidos para propriedades são repetidos, quando poderiam ser reutilizados e padronizados, de forma compartilhada, pela folha de estilo.

Nesse contexto, surgem as variĂĄveis no CSS, tambĂ©m chamadas de Custom Properties – pois, tecnicamente, Ă© isso que elas sĂŁo.

Definição

As Custom Properties sĂŁo propriedades CSS customizadas (ou seja, vocĂȘ configura o seu valor) iniciadas com --, de nome case-sensitive, e que sĂŁo utilizadas no documento atravĂ©s da função var(). Por serem propriedades, Ă© importante compreender que seu comportamento Ă© idĂȘntico ao de uma propriedade qualquer do CSS (guarde essa informação!).

Exemplo

:root {
+  --colorPrimary: purple;
+}
+
+a {
+  color: var(--colorPrimary);
+}
+

(Eu nĂŁo conheço ninguĂ©m que gosta da ideia esplĂȘndida do --. Mas elas nĂŁo vĂŁo deixar de iniciar com -- se vocĂȘ reclamar. Inclusive, isso jĂĄ foi discutido o suficiente.)

A função var()

Quem viabiliza o uso de Custom Properties? Ela:

var( <custom-property-name> [, <declaration-value> ]? )
+

O primeiro parĂąmetro Ă© o nome da propriedade, e o segundo, opcional, Ă© o valor a ser usado como fallback caso o primeiro argumento seja invĂĄlido (por exemplo: uma variĂĄvel com 20px sendo usada como valor de um background, ou variĂĄvel inexistente).

Escopo

Cascata, especificidade, herança
 Esses conceitos são muito importantes para entender o poder das variáveis do CSS – e do CSS no geral, eu diria.

Aqui, uma das informaçÔes mais importantes deste artigo: As Custom Properties seguem regras de cascata tal como qualquer outra propriedade do CSS.

Por isso, quando quisermos que a variĂĄvel esteja disponĂ­vel “globalmente” (para todos os seletores), a declaramos no seletor :root, que Ă© o prĂłprio documento HTML. Isso acontece pois o efeito cascata do CSS permite que todos seus descendentes herdem a propriedade. Legal, nĂ©?

A propriedade customizada, tal como qualquer outra propriedade, pode ser sobreescrita através de seletores. Seu valor serå definido de acordo com a especifidade deles.

A implementação de Custom Properties do CSSNext não segue regras de cascata. Apenas variåveis declaradas no :root são vålidas. :-(

Exemplo

:root {
+  --bgColor: indianred;
+}
+
+div {
+  --bgColor: darkseagreen;
+}
+
+#wow {
+  --bgColor: darkcyan;
+}
+
+* {
+  background-color: var(--bgColor);
+}
+

Nesse caso:

  • Todos os elementos sĂŁo vermelhos.
  • Exceto elementos div e seus filhos, que seriam verdes.
  • Exceto o elemento com id wow e seus filhos, que seriam ciano.

As Ășltimas versĂ”es do Firefox e Chrome jĂĄ implementaram as variĂĄveis nativas do CSS. Se estiver utilizando algum desses navegadores, o exemplo abaixo ilustrarĂĄ o funcionamento do CSS acima.

JS Bin on jsbin.com

Manipulando variĂĄveis CSS com JavaScript

Outra informação valiosa sobre as variåveis do CSS é a possibilidade de acesså-las e alterå-las via JavaScript, usando a interface CSSStyleDeclaration para interagir com propriedades.

Exemplo

Considerando:

:root {
+  --my-color: darkcyan;
+  background-color: var(--my-color);
+}
+

VocĂȘ pode obter o valor da propriedade --my-color, atravĂ©s do window.getComputedStyle() e getPropertyValue().

const myColor = getComputedStyle(document.body).getPropertyValue("--my-color");
+console.log(myColor); // => darkcyan
+

VocĂȘ pode alterar o valor da variĂĄvel, atravĂ©s do setProperty() do objeto style:

document.body.style.setProperty("--my-color", "tomato");
+

Conheça o CSSStyleDeclaration abrindo o DevTools e digitando getComputedStyle(document.body) no console.

Curiosidades

  • VocĂȘ nĂŁo pode armazenar nomes de propriedades do CSS como Custom Properties.
div {
+  --myProperty: overflow;
+  var(--myProperty): hidden; /* Erro de sintaxe */
+}
+


Em compensação, vocĂȘ pode armazenar qualquer outra coisa (e usĂĄ-las com JavaScript!):

--foo: if (x > 5) this.width = 10;
+
  • VocĂȘ nĂŁo pode formar valores com variĂĄveis.
div {
+  --myContainerWidth: 300;
+  width: var(--myContainerWidth) px; /* Valor invĂĄlido */
+  /* => 300 px, em vez de 300px */
+}
+


Ao menos que vocĂȘ use calc():

div {
+  --myContainerWidth: 300;
+  width: calc(var(--myContainerWidth) * 1px); /* => width: 300px; */
+}
+

ConsideraçÔes Finais

As Custom Properties abriram novas possibilidades para o uso de variåveis em folhas de estilo. Depois de diversas especificaçÔes e sintaxes (nem sempre foi --, acredite!), elas estão finalmente em fase de implementação nos navegadores.

Tem interesse em se aprofundar em outras novas funcionalidades do CSS? Acompanhe a série O CSS do Futuro!

\ No newline at end of file diff --git a/blog/a-fantastica-diversidade-do-front-end/index.html b/blog/a-fantastica-diversidade-do-front-end/index.html new file mode 100644 index 0000000..ab89291 --- /dev/null +++ b/blog/a-fantastica-diversidade-do-front-end/index.html @@ -0,0 +1 @@ +A Fantåstica Diversidade do Front-end | Diéssica Gurskas
diessi.caBlog
April 09, 2016

A FantĂĄstica Diversidade do Front-end

Os diferentes perfis de desenvolvedores front-end Ă© um tĂłpico que frequente em fĂłruns de discussĂŁo. Quais perfis o mercado espera? Como posso me definir enquanto desenvolvedor(a) front-end?

Vi, recentemente, uma vaga no Facebook para Front-end Engineer com foco em Acessibilidade. Pensei “Foco em acessibilidade? Que especĂ­fico!”, e, segundos depois, todas as discussĂ”es que jĂĄ tive sobre os perfis de desenvolvedores front-end me vieram Ă  mente.

Falar sobre esse assunto Ă© falar sobre como interpretar vagas de emprego sem entrar em desespero.

Mesmo Papel, Diversas Habilidades

Estuda Motion Design a fim de desenvolver nĂŁo sĂł sites, mas experiĂȘncias fantĂĄsticas? Estuda UX Design e prĂĄticas de Acessibilidade a fim de desenvolver produtos que engajam o mĂĄximo de pessoas possĂ­vel? Estuda padrĂ”es de arquitetura de software a fim de desenvolver aplicaçÔes web complexas e escalĂĄveis no client-side?

VocĂȘ pode estudar e gostar todos; estudar mais um mais do que o outro; trabalhar com um, mas tender a outro; e pode atĂ© mesmo nĂŁo focar em nenhum dos que eu citei acima. Em qualquer uma das possibilidades, vocĂȘ provavelmente nĂŁo deixarĂĄ de ser um profissional da ĂĄrea de front-end – mas terĂĄ, com certeza, um mercado especĂ­fico e uma carreira que se basearĂŁo nas suas escolhas profissionais.

Existe uma diversidade incrĂ­vel de habilidades na ĂĄrea de desenvolvimento front-end.

Somos o intermediĂĄrio entre o back-end e o design, mas nosso papel Ă© transformar o web design em uma experiĂȘncia real. Essa (grande) responsabilidade faz com que desenvolvamos diversas habilidades, e algumas sĂŁo inegavelmente desenvolvidas em maior ou menor nĂ­vel. Nesse desnĂ­vel, encontramos de Motion Designers a JavaScript Developers, cada um com seu espaço em times e projetos especĂ­ficos.

E nĂŁo hĂĄ nada de errado nisso. O surgimento dessas especializaçÔes – que podem (e devem) ser escolhidas por vocĂȘ – Ă© apenas um resultado da complexidade atual do desenvolvimento front-end.

Confie nas Suas Habilidades

(ou “VocĂȘ NĂŁo Precisa Ser o Candidato Perfeito Para Todas as Vagas de Front-end Existentes”.)

Por que eu disse que falar sobre esse assunto Ă© falar sobre como interpretar vagas de emprego sem entrar em desespero?

Pense: VocĂȘ Ă© experiente, estuda com frequĂȘncia, mas, ocasionalmente, procura vagas de emprego e se vĂȘ insuficiente. Ok, convenhamos, a possibilidade existe: vocĂȘ nĂŁo estar atingindo os requisitos mĂ­nimos das vagas pode sim ser um sinal de que algo estĂĄ errado. Mas provavelmente nĂŁo Ă© o caso.

Talvez vocĂȘ esteja procurando vagas para um perfil que nĂŁo Ă© o seu. NĂŁo precisamos aceitar ter expertises variadas como Ă© exigido; afinal, muitas vagas na ĂĄrea de TI viram piada justamente por esse motivo. Desde que vocĂȘ entenda a multidisciplinaridade como mais valiosa que qualquer disciplina, apenas abrace o que prefere e se aprofunde, torne-se uma referĂȘncia nisso.

No fim, suas preferĂȘncias moldarĂŁo vocĂȘ como profissional. Elas farĂŁo com que vocĂȘ seja incluĂ­do(a) ou excluĂ­do(a) de vĂĄrias oportunidades, o que, por consequĂȘncia, moldarĂĄ sua carreira.

Estude o que gosta, reconheça suas preferĂȘncias, confie nas suas habilidades, e, entĂŁo, procure vagas sem entrar em desespero.

Perfis de Desenvolvedores Front-end

No fĂłrum do Front-end Brasil, foi proposta a divisĂŁo de separar profissionais de front-end que desenvolvem a camada de apresentação dos que arquitetam aplicaçÔes que interagem com back-end. Concordo com a divisĂŁo. Tenho uma visĂŁo bem definida, com base nas exigĂȘncias atuais do mercado internacional.

Dois Perfis: Uma Proposta

Front-end Developer

A ponte entre o design e o front-end. (“UI Developer” Ă© um nome alternativo.)

Habilidades
  • ProficiĂȘncia em HTML semĂąntico, CSS e JavaScript a nĂ­vel de desenvolvimento da camada de apresentação da aplicação.
  • PrincĂ­pios e boas prĂĄticas de User Experience Design.
  • PrincĂ­pios e boas prĂĄticas de Acessibilidade.
  • ProficiĂȘncia em metodologias de organização do CSS como OOCSS, SMACSS e BEM.
  • NoçÔes de User Interface Design.
  • NoçÔes de Motion Design.
  • NoçÔes de back-end, geralmente a nĂ­vel de integração com CMS.
Responsabilidades
  • Planejamento e desenvolvimento da camada de apresentação da aplicação.
  • Implementação do live styleguide, junto ao designer.
  • Metodologia e estrutura a ser usada no CSS.
  • Participação no processo de Design (pois Development is Design).

Front-end Engineer

A ponte entre o front-end e o back-end. (Dependendo do projeto, “JavaScript Developer” pode ser mais apropriado.)

Habilidades
  • ProficiĂȘncia em HTML e CSS, mas sua especialização Ă© JavaScript.
  • ProficiĂȘncia em Design Patterns e padrĂ”es de arquitetura de software.
  • Conhecimento de modelo cliente-servidor, HTTP, REST.
  • PrincĂ­pios e boas prĂĄticas de Performance.
  • PrincĂ­pios e boas prĂĄticas de Segurança.
  • NoçÔes de estratĂ©gias de desenvolvimento, como Integração ContĂ­nua (CI).
Responsabilidades
  • Planejamento e desenvolvimento da aplicação JavaScript.
  • Automatização das tarefas.
  • Tooling da aplicação.
  • Implementação de uma metodologia de testes.

NĂŁo concordo com o nome “Front-end Designer”, sugerido pelo Brad Frost. Ainda que desenvolvedores front-end participem do processo de design, tornar funcional a camada de apresentação Ă© uma etapa do desenvolvimento de software – nĂŁo do design. O fato do desenvolvimento front-end ser erroneamente considerado mais programação do que design, quando deveria ser os dois, Ă© um argumento que nĂŁo justifica o nome.


Qual Deles?

Normalmente temos um pouco dos dois, mas sempre um mais do que o outro. Nesse caso, uma boa maneira de explicitar o seu papel sem desmerecer o outro Ă© falar sobre suas habilidades, em vez de se apegar a um rĂłtulo.

Dificilmente um rĂłtulo resumirĂĄ todo o seu conhecimento.

Eu não me apego a isso, por exemplo. Mesmo exercendo a função de Front-end Engineer atualmente, continuo me denominando “Front-end Developer”.

A Vaga Ideal Para Suas Habilidades

É utópico esperar que todos desenvolvedores front-end sejam bons UX Designers, Motion Designers, JavaScript Developers
 Isso não existe. As empresas procuram diferentes perfis de desenvolvedores front-end. E elas nem sempre sabem disso.

As empresas não simplesmente procuram um Front-end Developer ou um Front-end Engineer. Existem vagas bastante híbridas, como Front-end Engineers com foco em UX ou Acessibilidade, ou até mesmo Front-end Developers com noçÔes de arquiteturas como MVC. Plenamente possível e vålido!

Cabe a vocĂȘ identificar se Ă© ideal Ă  vaga de emprego que quer se candidatar e se suas habilidades sĂŁo compatĂ­veis com a expectativa da empresa. À empresa, cabe a identificação do seu perfil, a fim de alocar vocĂȘ em um projeto e time que explorem suas habilidades.

É o cenário perfeito, pelo menos.

Lembre-se da Nossa EssĂȘncia

Independente de como vocĂȘ se posiciona e rotula, dos projetos que trabalha e do caminho que quer seguir, o front-end nĂŁo deixarĂĄ de orbitar ao redor da trinca HTML, CSS e JavaScript.

Enquanto vocĂȘ possuir interesse nessas trĂȘs linguagens, os seus outros interesses apenas moldarĂŁo o seu caminho profissional.

E, temos sorte: na ĂĄrea de front-end, a diversidade de caminhos Ă© fantĂĄstica.

\ No newline at end of file diff --git a/blog/a-guide-to-favicons-and-touch-icons/index.html b/blog/a-guide-to-favicons-and-touch-icons/index.html new file mode 100644 index 0000000..abead36 --- /dev/null +++ b/blog/a-guide-to-favicons-and-touch-icons/index.html @@ -0,0 +1,83 @@ +A Guide to Favicons and Touch Icons | Diéssica Gurskas
diessi.caBlog
September 06, 2015

A Guide to Favicons and Touch Icons

Favicon is a simplified visual element associated with a particular website, page or event, which you once found only in your browser’s address bar or bookmarks. Nowadays, the scenario is different: they are everywhere.

Introduction

Favicons provide a important visual indicator to people, and help them to easily associate your content (which can be a website, a particular page or even events like a new message) when browsing.

Formerly, they, also called shortcut icons or bookmark icons, were just tiny pieces of art designed to help users to browse through their tabs or bookmarks. Today, shortcut icons can also provide an app-like link on operational systems (Windows 8, Android, OS X and so on), and should therefore be considered for achieving a pleasant cross-platform experience.

This is a guide for using favicons today, the right way. At the end of this article, I’m sure you’ll be excited about SVG favicons.

Usage

Favicons in different dimensions are needed, so devices and browsers can pick the picture that fits best based on sizes attribute (little exception for Mozilla Firefox, which always gets the last favicon declared and scale it if necessary).

The images are not requested when not used. As said, browsers will get only what fits them best, therefore it’s important to provide the favicon in the required dimensions to avoid ugly scaled images.

General

<!-- I'm lazy -->
+<link rel="icon" href="favicon.png" />
+
+<!-- Browser tabs -->
+<link rel="icon" href="favicon-16x16.png" sizes="16x16" />
+
+<!-- Safari on OS X, IE10 Metro -->
+<link rel="icon" href="favicon-32x32.png" sizes="32x32" />
+
+<!-- Google TV -->
+<link rel="icon" href="favicon-96x96.png" sizes="96x96" />
+
+<!-- Chrome on Android -->
+<link rel="icon" href="favicon-192x192.png" sizes="192x192" />
+

No need for type="image/png" when using HTML5.

You’ll need to provide a manifest in order to Chrome on Android’s icon to work properly. See manifest.json example.

<link rel="manifest" href="manifest.json" />
+

Lacking of PNG support on IE: a workaround

Internet Explorer until version 11 and Safari don’t support PNG favicons. However, you can provide a fallback for IE up to 9:

<!--[if IE]> <link rel="shortcut icon" href="favicon.ico" /> <![endif]-->
+

Notice the shortcut, which is a non-standard. Also, providing this fallback within a conditional comment is necessary; otherwise Chrome will use the ICO favicon, even if it supports PNG ones.

I don’t recommend it, though, because IE 10 doesn’t support conditional comments (so it won’t get any favicon, as seen that it doesn’t support PNG too), and also because it encourages the use of the non-standard and confusing shortcut.

Luckily, you can workaround everything just placing a favicon.ico in the root directory (the browser will look for it automagically). Then link only the PNG favicon and don’t worry.

Web Clip bookmarks

iOS users can add websites to their home screen – shortcuts called “Web Clip bookmarks”. The default icon is a thumbnail screenshot of the page, but developers can specify one instead.

You will need to provide a lot of dimensions in order to support both new devices and older (iOS6 and prior), however.

There’s a no-HTML way and a HTML way to provide those icons. It’s up to you.

No-HTML: Touch Icon file

Add a apple-touch-icon-*.png file, where * is the size to the root directory, instead. iOS Safari will look for the appropriate icon size, and if it doesn’t find any that fits best, it’ll use apple-touch-icon.png.

You can reuse the image of another favicon specifying a href (not possible while using the solution above).

<!-- Non-retina iPhone pre iOS 7 -->
+<link rel="apple-touch-icon" sizes="57x57" href="apple-touch-icon-57x57.png" />
+
+<!-- Non-retina iPad pre iOS 7 -->
+<link rel="apple-touch-icon" sizes="60x60" href="apple-touch-icon-60x60.png" />
+<link rel="apple-touch-icon" sizes="72x72" href="apple-touch-icon-72x72.png" />
+
+<!-- Non-retina iPad iOS 7 -->
+<link rel="apple-touch-icon" sizes="76x76" href="apple-touch-icon-76x76.png" />
+
+<!-- Retina iPhone pre iOS 7 -->
+<link
+  rel="apple-touch-icon"
+  sizes="114x114"
+  href="apple-touch-icon-114x114.png"
+/>
+
+<!-- Retina iPhone iOS 7 -->
+<link
+  rel="apple-touch-icon"
+  sizes="120x120"
+  href="apple-touch-icon-120x120.png"
+/>
+
+<!-- Retina iPad pre iOS 7 -->
+<link
+  rel="apple-touch-icon"
+  sizes="144x144"
+  href="apple-touch-icon-144x144.png"
+/>
+
+<!-- Retina iPad iOS 7 -->
+<link
+  rel="apple-touch-icon"
+  sizes="152x152"
+  href="apple-touch-icon-152x152.png"
+/>
+
+<!-- iOS 8 -->
+<link
+  rel="apple-touch-icon"
+  sizes="180x180"
+  href="apple-touch-icon-180x180.png"
+/>
+

Using apple-touch-icon-precomposed instead of apple-touch-icon, which prevents iOS icons defaults like rounded corners and reflective shine, isn’t necessary, as seen that there isn’t shiny effects on iOS 7 and up anymore.

Windows Tiles

Tiles are icons that appear on the Start screen, linked as apps. By default, the image on the tile is the website’s favicon or a default IE11 logo.

To cover a wide range of devices, use an image 1.8 times the standard tile size so the image can be scaled up or down as needed.

There’s a no-HTML way and a HTML way to provide those icons. It’s up to you, again.

No-HTML: Browser config file

Provide a browserconfig.xml file and save it at the root of your server. Internet Explorer 11 will automatically read the file when the user pins the website. See browserconfig.xml example.

Metadata tags

msapplication-TileColor is the background color of the tile, and msapplication-TileImage is the icon, which can be tiny (70 × 70px), square (150 × 150px), wide (310 × 150px) or large (310 × 310px).

<!-- Windows Tile -->
+<meta name="msapplication-TileColor" content="#000" />
+<meta name="msapplication-TileImage" content="tile-icon.png" />
+
+<!-- Different Windows Tiles (optional) -->
+<meta name="msapplication-square70x70logo" content="tile-icon_tiny.png" />
+<meta name="msapplication-square150x150logo" content="tile-icon_square.png" />
+<meta name="msapplication-wide310x150logo" content="tile-icon_wide.png" />
+<meta name="msapplication-square310x310logo" content="tile-icon_large.png" />
+

Bulletproof favicons

  • For Touch Icons, add apple-touch-icon.png and apple-touch-icon-*.png files, where * is the size, to the root directory.
  • For IE support, add a favicon.ico file with both 16 × 16px and 32 × 32px resources to the root directory.
  • For Windows Tiles, add a browserconfig.xml to the root directory.
  • For Chrome on Android icon, add a manifest.json to the root directory.
  • Add the following HTML to <head>:
<!-- Chrome on Android -->
+<link rel="icon" href="favicon-192x192.png" sizes="192x192" />
+<link rel="manifest" href="manifest.json" />
+
+<!-- Google TV -->
+<link rel="icon" href="favicon-96x96.png" sizes="96x96" />
+
+<!-- Safari on OS X, IE10 Metro -->
+<link rel="icon" href="favicon-32x32.png" sizes="32x32" />
+
+<!-- Browser tabs -->
+<link rel="icon" href="favicon-16x16.png" sizes="16x16" />
+

Order matters here! Mozilla Firefox ignores sizes and always get the last favicon for the browser tabs. :-(

Or you can add all the favicons through meta and link tags.

Favicon as SVG

Not encouraged as an unique solution, as seen that isn’t widely supported yet.

I’m excited about this:

<link rel="icon" href="favicon.svg" sizes="any" type="image/svg+xml" />
+

Final words

I’m sure you are now excited about SVG support for favicons. Providing a lot of different images is quite boring.

I encourage you to support favicons everywhere (or at least retina-ready ones), but unfortunately there’s no human-friendly way to do it nowadays. Use favicons package on npm or, if you are not comfortable with the command line, refer to RealFaviconGenerator.

Don’t be lazy.

References

\ No newline at end of file diff --git a/blog/a-minimal-workspace-on-macos/index.html b/blog/a-minimal-workspace-on-macos/index.html new file mode 100644 index 0000000..ac70ef7 --- /dev/null +++ b/blog/a-minimal-workspace-on-macos/index.html @@ -0,0 +1,29 @@ +A Minimal Workspace on macOS | Diéssica Gurskas
diessi.caBlog
May 04, 2017

A Minimal Workspace on macOS

Ask me for a screenshot of my desktop and all you get is a wallpaper – if I’m using any. Everything else is hidden, unless actually requested by me.

That’s the way I work on macOS. The minimal way.

My macOS desktop. This + Spotlight = life. 😎

In my workspace, there are no desktop items, app icons, time clock, battery percentage, transition delays, distracting animations, dashboards or context menus.

Too much information makes it easy for me to get stimulated and then distracted. So I like it minimal.

Recipe for the minimal 👌

Get rid of everything you can. Hide. Disable. Assume everything is useless, not useful. (I actually use this approach for life.)

You’ll get frustrated sometimes, because there are simple things you want so bad to get rid of but then found out it’s impossible unless you hack things. SRLSY GOTTA LOVE APPLE 😍😍😍

Well, let’s begin! Follow the steps below and type the commands in a terminal. If you’re not familiar with a terminal, I’m pretty sure it’s possible to find those settings in “System Preferences” as well.

(
But I highly recommend you to open a terminal and start typing around because SRSLY USING A TERMINAL IS LIKE KNOWLEDGE AND POWER 4 UR ENTIRE LIFE!!!!!!!!)

Hide your desktop

It’s easier to live without than to live with it. Disable it and it won’t be something you have to clean up anymore!

defaults write com.apple.finder CreateDesktop -bool false
+

Hide your dock

It’ll be only shown when you hover it.

defaults write com.apple.dock autohide -bool true
+

Other cool things you can do too to keep your dock clean are:

# Minimize windows into their application's icon
+defaults write com.apple.dock minimize-to-application -bool true
+
+# Wipe all (default) app icons from the Dock
+defaults write com.apple.dock persistent-apps -array
+

Because I initialise apps from Spotlight, I really don’t mind not having any app in my dock. Sometimes I ask myself why do I have a dock at all. đŸ€”

And
 Launchpad. WHY?????? 😭

Hide your menu bar

It’ll be only shown when you hover it.

defaults write NSGlobalDomain _HIHideMenuBar -bool true
+

I really like this one, but if you feel it's too radical for you, try hiding only menu bar icons with Vanilla (recommended) or Bartender.

Disable dashboard

Why does it even exist? 😒

# Disable Dashboard
+defaults write com.apple.dashboard mcx-disabled -bool true
+
+# Don't show Dashboard as a Space
+defaults write com.apple.dock dashboard-in-overlay -bool true
+

Disable and/or speed up animations

Saving some time because I don’t think those really add anything to my user experience on macOS.

# Disable window animations and Get Info animations
+defaults write com.apple.finder DisableAllAnimations -bool true
+
+# Remove the auto-hiding Dock delay
+defaults write com.apple.dock autohide-delay -float 0
+
+# Remove the animation when hiding/showing the Dock
+defaults write com.apple.dock autohide-time-modifier -float 0
+
+# Don't animate opening applications from the Dock
+defaults write com.apple.dock launchanim -bool false
+
+# Speed up Mission Control animations
+defaults write com.apple.dock expose-animation-duration -float 0.1
+

Finally, restart system stuff:

killall Finder; killall Dock; killall SystemUIServer
+

And that’s it! 🎉 Life-changing commands for sure. Now just don’t forget cleaning your actual desk too.

For more on the way I work, my dotfiles are worth-checking!

Sorry for using too many emojis. Just shipped this feature here on my blog and I can't help myself! 😬

\ No newline at end of file diff --git a/blog/archive/i-travelled-to-photographs/index.html b/blog/archive/i-travelled-to-photographs/index.html new file mode 100644 index 0000000..2d5828d --- /dev/null +++ b/blog/archive/i-travelled-to-photographs/index.html @@ -0,0 +1 @@ +I Travelled to Photographs | Diéssica Gurskas
diessi.caBlog
April 19, 2017

I Travelled to Photographs

February was ending.

Usually, such thing would mean regular summer days. However, it wasn’t summer or even a regular day – this was something else.

February 25th was winter. In that cold afternoon, I ended up into a place I’ll never forget: photographs from my phone’s gallery.


My steps were slow.

Red bricks erected the walls of houses built on top of an equally red-bricked avenue.

The windows of the houses were made of a wood strategically white-colored to match the brick’s white grouts. With such detail, it was pretty easy to forgive the toughness those bricks carried.

Houses ended themselves in grey roofing shingles. The roofs were all hipped. Houses with hip roofs, gotta love them!, I thought to myself. (Imagine the “V” letter upside down on top of a square – that’s a house with a hip roof.)

Showing a winter that was already leaving, dark trees with dry twigs were in contrast against a white sky – the whitest I’d ever seen in my life. Damn! The whole picture looked like a painting, while the white sky worked as the canvas board on which all that was drawn.

I remember walking and trying to get everything I could, until a freezing wind blew abruptly into my face. It was February, though. From where I come, February meant summer, not freezing winds. Why was February that cold?

In an attempt to clear things up, I told myself what I believed that was true: You’re just looking at photographs from your phone’s gallery. There’s no need to get this excited! Ok. So I was home and looking at the “Wallpapers” album I had on my phone.

A moment later, I found myself facing a large and wonderful canal, in which someone was solitary paddling a boat to somewhere. What a view.

Then, self-awareness hit me again: Wait. Isn’t my smartphone in my pocket? How could I be possibly looking at photographs on it?

I immediately started touching my entire body in a desperate hunt for my phone. And there it was. In my fucking coat. It wasn’t really possible for me to see photographs on my phone – that shit was in my pocket all the time.

Besides, why would I be wearing a coat on summer? And, if I was already wearing a coat, how could I be still cold? How inappropriate were my clothes for that weather? Only a person who sensed that winter solely with the eyes would underestimate its coldness like that!

The boat was really leaving through the canal. The view wasn’t photographs. What was all that, then?

I got my phone from my pocket, turned off airplane mode, and opened the Maps app. Come on, where am I?

“Noorder Amstelkanaal”, I read. Wow.

All of a sudden, February 25th was a cold winter in Amsterdam. My very first one.

Noorder Amstelkanaal
Someone solitary paddling a boat to somewhere in Noorder Amstelkanaal, an Amsterdam's canal.

I guess I travelled to photographs.

\ No newline at end of file diff --git a/blog/catalysis/index.html b/blog/catalysis/index.html new file mode 100644 index 0000000..fd3d4d6 --- /dev/null +++ b/blog/catalysis/index.html @@ -0,0 +1 @@ +Catalysis | Diéssica Gurskas
diessi.caBlog
April 13, 2017

Catalysis

As a High School student, I remember always finding Chemistry something between the boring and intriguing. Still, it isn’t hard to find myself wondering about the science concepts I’ve learned at that time.

Lately, I’ve been particularly thinking about catalysis.


In Chemistry, catalysis is the acceleration of a reaction due to the participation of a substance – the “catalyst”.

The way a catalyst induces a reaction to happen faster is intriguing. Curiously, it neither gives the reaction more energy nor change its environmental conditions. Catalysts have an even better strategy: they lower the amount of energy required for the reaction to take place.

Diagrama representando conhecimento como ele realmente Ă©
Uncatalyzed reaction (solid) vs. catalyzed reaction (dashed). The highest point is the energy required for the reaction to happen.

In a catalysed reaction, then, the same product is obtained for less energy. Bringing this concept to our lives is quite thought-provoking.

Sometimes it isn’t possible for us to achieve something because it demands more time or energy than what we currently have. To deal with this, we then try looking for them in our lives – which mostly means depriving yourself of things.

However, matter of fact is that optimising isn’t always about getting rid of things in your life. If we think of catalysis, we can manage it differently.

What if the problem weren’t the lack of energy or time, but that we’re in need of too much of them in order to get things done? Having a catalyst would totally figure it out. Without something that pushes us forward, we’ll always require more energy for the product we want to get.

At this point, you may think your catalyst is your motivation. Motivation is out of our control though – which makes it a goal, not a source. It’s also too ephemeral, and a catalyst mustn’t ever be consumed by an unique reaction, just like in Chemistry. We can’t count on being motivated!

So it goes more like what habitual and practical things in life would give you productivity for less. Is it everyday meditation? A partner by your side? Self-confidence? Inspiring weekends without thinking of work at all? Eating healthy? Going out for a walk every day?

You have to mind what pushes your forward. Catalysts themselves cannot make a reaction happen that wouldn’t happen on its own, but they sure make it occur under less extreme conditions. It’s an improvement when you’re already motivated.

So, what’s your catalyst?

\ No newline at end of file diff --git a/blog/choose-life-in-berlin/index.html b/blog/choose-life-in-berlin/index.html new file mode 100644 index 0000000..2e5ebc6 --- /dev/null +++ b/blog/choose-life-in-berlin/index.html @@ -0,0 +1 @@ +Choose Life đŸ‡©đŸ‡Ș | DiĂ©ssica Gurskas
diessi.caBlog
May 12, 2017

Choose Life đŸ‡©đŸ‡Ș

Choose life. Choose a job. Choose a career. Choose relocation. Choose giving life a fresh1 beginning. Choose an one-way flight ticket. Choose fitting your entire life in a 23 kg suitcase. Choose getting rid of all your crap. Choose a higher Human Development Index. Choose being thousands of kilometers far away. Choose devastating your loved ones. Choose different bureaucracies you still don’t understand. Choose calling another place home. Choose not fitting in (you never did anyway!). Choose saying goodbye to places, food and friends, then choose new places, food, and friends. Choose memories. Choose developing new tastes. Choose being forced to develop social skills. Choose ignorance. Choose mundane and boring activities as exciting adventures. Choose not speaking your mother language. Choose limited self-expression. Choose missing the food from your country, and especially your mum’s. Choose letting part of your heart be elsewhere. Choose adapting 24/7. Choose wondering what the fuck you are doing. And choose getting the answer as soon as you go outside. Choose not understanding jokes from natives. Choose recognising you can do anything, anywhere. Choose not knowing if you should. Choose the bittersweet feeling of moving abroad. Choose to be afraid. Choose your future. Choose life.

But why wouldn’t I want to do a thing like that?

I chose to choose life. And the reasons? There are no reasons. Who needs reasons when you’ve got Berlin?2

1

See HelloFresh, which helped me relocating to Berlin.

2

The entire essay is inspired by Mark Renton’s “Choose Life” speech from Trainspotting, a movie that makes me think a lot about life choices.

\ No newline at end of file diff --git a/blog/como-eu-vi-a-braziljs-2015/index.html b/blog/como-eu-vi-a-braziljs-2015/index.html new file mode 100644 index 0000000..f492d21 --- /dev/null +++ b/blog/como-eu-vi-a-braziljs-2015/index.html @@ -0,0 +1 @@ +Como Eu Vi a BrazilJS 2015 | Diéssica Gurskas
diessi.caBlog
August 26, 2015

Como Eu Vi a BrazilJS 2015

É mais experiente que volto de mais uma BrazilJS, evento que acontece na cidade onde nasci desde 2012. Aqui, compartilho nĂŁo um relatĂłrio tĂ©cnico das palestras, nĂŁo acusaçÔes do que foi ruim ou bom, mas minhas visĂ”es, em conjunto, sobre a conferĂȘncia e a comunidade.

Importante observar que nĂŁo seleciono aqui a “nata” do evento. NĂŁo Ă© minha intenção desmerecer qualquer acontecimento. Meu objetivo com esse texto Ă© somente compartilhar o meu ponto de vista sobre o que penso que deve ser comentado.

O primeiro dia

O meu dia começou localizando onde seria o evento. Neste ano, foi no BarraShoppingSul; um shopping que, considerando os outros da cidade, é de difícil acesso mesmo para quem mora hå alguns quilÎmetros de Porto Alegre.

O Centro de ConvençÔes, ao menos, foi fĂĄcil de achar, e o check-in ocorreu como esperado: pontual. As meninas que forneceram minha credencial estavam de Ăłtimo humor — e olha que era um dos primeiros horĂĄrios da manhĂŁ de sexta! Ano passado, o meu check-in foi feito pelo Jaydson, o que fez eu me perguntar onde estaria ele, se nĂŁo credenciando os participantes do evento.


E, na verdade, ele tinha se tornado um Power Ranger junto com o Felipe. E Power Rangers não fazem check-in. Descobri isso da pior maneira.

Uma abertura idiota

Dois desenvolvedores, os organizadores desse evento que trouxe mais de mil pessoas para o mesmo lugar, brincando de “lutinha” na frente de todo mundo, vestidos de Power Rangers só porque o JavaScript fez 20 anos. Essa foi a abertura da BrazilJS, e eu não mudaria nada.

Muita gente riu. Muita gente aplaudiu. Eu ri e aplaudi, e aplaudiria de novo, pois, sim, brincaram, mas tambĂ©m fizeram um trabalho muito sĂ©rio. Ainda vestidos de Power Rangers, falaram um pouco da histĂłria da conferĂȘncia e das expectativas para esse ano, finalizando com uma mensagem sobre a importĂąncia da diversidade e, sobretudo, do respeito.

Os eventos que se seguiram mostraram que, sim, o trabalho era sério.

Christian Heillman

We are there for them. Not they for us.

Com uma camiseta do Brasil, Christian chegou com um dos assuntos mais importantes na atualidade, e que estå dando muito o que falar: pushing the web forward. Palavras de protagonismo, reiteração do nosso papel, motivação para acreditar na web e no nosso trabalho, e, o mais importante: como isso deve ser feito. Falou, claro, sobre o ECMAScript 6, sobre o Babel, e fez uma anålise de como resolvemos os problemas atualmente.

We all know the DOM is slow, terrible and to blame for all our problems. Did we allot it to say that way and still be a problem as we abstracted its issues away?

Acredito que essa essa frase foi pesada para muita gente, principalmente em quem estå deprimido de tanto estudar soluçÔes. Christian mostra que, ao trabalharmos com web, não somos apenas desenvolvedores ou designers (ao menos não deveríamos ser). Somos também web makers, e esse é o principal problema de simplesmente abstrair e deixar para lå.

É fĂĄcil entender a razĂŁo dessa abordagem. Heillman trabalha no time de desenvolvimento do Microsoft Edge, o novo e surpreendente navegador padrĂŁo do Windows 10, e esse Ă© o ponto de vista dele enquanto browser maker: somos a representação mĂĄxima do protagonismo, e, por isso, desenvolver nĂŁo deve limitar-se a frameworks ou libraries. Estamos em uma posição em que inovar sempre que possĂ­vel Ă© visto como uma contribuição, e ele ensina a entender esse ponto de vista desde a analogia feita logo nos primeiros slides. NĂŁo devemos esperar que a inovação venha apenas de grandes companhias.

Não disse para pararmos de usar ES6 com Babel. Não disse para usarmos ES6 em produção e beber ågua de coco na praia. Mas não é mentira que existem casos em que podemos, se assim desejarmos, relatar o que estå de errado e o que faz falta, e é justamente aí que o nosso protagonismo é måximo.

Os argumentos foram reĂșnidos, as situaçÔes em que podemos nos tornar web makers foram apresentadas, e tudo em prol de provar o nosso protagonismo.

You are a creator of the next web!

Sem dĂșvidas, uma das melhores palestras que jĂĄ assisti na minha vida. É difĂ­cil relatar uma interpretação detalhada sobre a mensagem do Christian, mas, aos que jĂĄ se sentiram no dever de fazer a web um lugar melhor alguma vez e nunca deixaram de acreditar nessa mĂ­dia, acho que essas minhas palavras foram mais que o suficiente para compreender o pensamento dele. Simples e sensacional.

Use lowlevel

Tive dificuldades em acompanhar o raciocĂ­nio do Douglas Campos algumas vezes, e noto que isso se deu em razĂŁo de ele nĂŁo estar falando a lĂ­ngua nativa. NĂŁo entro aqui no mĂ©rito das palestras em InglĂȘs ou PortuguĂȘs (para mim tanto faz desde que o palestrante consiga passar a mensagem de forma fluente na lĂ­ngua escolhida), mas reforço a importĂąncia de fazer a escolha certa, pois a tua escolha afeta um pĂșblico que estĂĄ confiando na tua capacidade enquanto transmissor.

Douglas falou sobre compiladores, e engajou os desenvolvedores a entender how things work under the hood, explorando conceitos como AST (Abstract Syntax Tree), um assunto que estå finalmente chamando a atenção em JavaScript, tanto que não foi a primeira vez que foi abordado na BrazilJS.

Acredito que o questionamento que o palestrante buscou provocar no pĂșblico nĂŁo teve ĂȘxito. Os 30 minutos, infelizmente, nĂŁo foram bem aproveitados e nĂŁo atenderam Ă s perguntas que o Douglas tentou provocar e responder. Ficou a sensação de uma mensagem subentendida, no entanto:

It’s really important for us to take a look at the things we don’t necessarily like.

JavaScript at Spotify

Felipe Ribeiro juntou os desafios encontrados durante a transição do Spotify (nativo com C++ para hĂ­brido), e o resultado foi uma palestra bastante completa sobre arquitetura e engenharia de software. Diversificou bastante a programação da conferĂȘncia, e mostrou que devemos analisar a necessidade de re-escrita de cĂłdigo em uma aplicação complexa sob uma Ăłtica criteriosa que equilibra utilidade, valor e esforço necessĂĄrio.

Desafios

Os desafios foram bastante interessantes. Um deles foi o gerenciamento de memĂłria no Spotify, jĂĄ que se trata de uma aplicação que nĂŁo Ă© descartada com a mesma frequĂȘncia de um site. Outro, a organização do cĂłdigo, que era excessivamente fragmentado, o que prejudicava a padronização (diferentes versĂ”es de mĂłdulos), manutenção (atualização em “efeito cascata”) e integração contĂ­nua do projeto.

Releases

O Spotify estabeleceu uma cultura colaborativa de testes (sempre gostei dessa abordagem!). Os empregados usam somente versÔes experimentais da aplicação, ajudando a testar e agilizar os hotfixes. O release é gradual, e é distribuído na medida em que a versão vai apresentando estabilidade aos usuårios que jå possuem acesso.

A saga dos 12 tĂłpicos de acessibilidade

A primeira vez que conheci o Reinaldo Ferraz foi no Front in POA em 2012. Na época, acessibilidade era mais novidade para as pessoas do que Sass. Todos conheciam Sass, ninguém conhecia WCAG.

Lembro de ter sido uma das palestras mais marcantes e diferentes do evento, e nĂŁo foi diferente na BrazilJS. Esta foi a mensagem que ficou:

"Aplicar tĂ©cnicas de acessibilidade em um site com usabilidade ruim Ă© como passar batom em um porco. NĂŁo importa o quanto vocĂȘ passe, ele continuarĂĄ sendo um porco."

500 days of open source

Uma palestra que dividiu bastante o pĂșblico. Na verdade, acredito que o Raphael Amorim deu o melhor dele para fazer o discurso significar exatamente o que ele queria que significasse. O Raphael sabe se comunicar muito bem, e paciĂȘncia foi o Ășnico requisito para captar a mensagem.

Vi muita dedicação na apresentação que ele fez. Organizou os aprendizados e os desafios de seguir Ă  risca a proposta do John Resig, e os apresentou mostrando que “preencher grade de contribuiçÔes” ou “se sentir no dever todo dia” nĂŁo Ă© o suficiente para progredir. Inclusive, para quem acredita que isso Ă© o suficiente, apresentou o Rockstar.

Esse tipo de palestra é essencial, e eu não estou disposta a discutir isso com ninguém. Havia mais de mil pessoas no mesmo lugar, e, por mais que não pareça, é uma minoria que contribui ou gerencia algum projeto open source, e também é uma minoria que contribui hå tempo o suficiente para passar por todos os desafios que o Raphael passou. Foi uma palestra sobre open source, mas também sobre esforço e saber o que estå te movendo para se esforçar mais: criar.

(Entendi o trocadilho no nome, a propĂłsito.)

David Bryant

Happy birthday, JavaScript!

Terminou o primeiro dia de BrazilJS tal como o Christian o iniciou: fazendo-nos acreditar no que trabalhamos. David Bryant, que faz parte do leadership team da Mozilla, falou sobre a evolução do JavaScript até o seu aniversårio de 20 anos, e em como devemos acreditar na web em detrimento da plataforma nativa. Para isso, lembrou da palestra Nick Desaulniers, anterior a dele, que mostrava quanto esforço tem sido feito para que a web alcance a plataforma nativa.

David, representando a Mozilla, deixou Ăłbvia a mensagem: a web Ă© a melhor plataforma.

O segundo dia

What can you build with a log

James começa explicando sua motivação: a impermancĂȘncia e a centralização do conteĂșdo sĂŁo coisas negativas da web. O que podemos fazer sobre isso? UĂ©, abrir o Vim, e construir meu cliente torrent, Flickr, Twitter


O Substack Ă© uma pessoa extremamente simples e humilde. É impossĂ­vel nĂŁo achĂĄ-lo, no mĂ­nimo, adorĂĄvel. Um dos live codings mais fluĂ­dos e espontĂąneos que jĂĄ assisti.

Reduce: seu novo melhor amigo

A Ju Gonçalves explicou o uso do reduce() na pråtica. (Na pråtica mesmo, para sair da BrazilJS usando, caso nunca tenha usado.)

O tema escolhido complementou muito bem a palestra de programação funcional do Jacob Page, anterior a dela. O formato ficou perfeito para 30 minutos (a propósito, a ideia de abordar apenas o reduce() foi muito legal!), e deu para aprofundar bastante em algo que deve fazer parte do dia a dia. Só fiquei com a sensação de que 5 minutos a mais ajudariam ela a guiar os exemplos com mais calma. O tempo estava bastante inflexível nesse quesito.

Enfim, a Ju sabe o que faz. NĂŁo a conhecia pessoalmente ainda, mas conheço o trabalho e o entusiasmo dela e apostaria nela de longe, tal como a organização da conferĂȘncia, sem dĂșvidas, fez.

ECMAScript 6: O que HĂĄ de Novo, O que Mudou, O que tem de Bacana ou de Estranho!

Título engraçado.

Quem foi na BrazilJS do ano passado sabe muito bem quem Ă© Jonathan Sampson. Em 2014, ele deu um nĂł na cabeça do Daniel Filho ao falar PortuguĂȘs durante a entrevista.

No entanto, ano passado ele palestrou em InglĂȘs. Neste ano, ele falou sobre o ES6 totalmente em PortuguĂȘs, e fez muita gente rir com coisas simples, como, por exemplo, referir-se aos que nĂŁo entendiam hoisting de variĂĄveis como “chorĂ”es do Stack Overflow”, ou atĂ© mesmo perguntar como se traduz replace (todo mundo sabe que Ă© “substchitutituir”, no caso).

JavaScript Robotics: A NodeBots show

JuliĂĄn Duque Ă© uma pessoa admirĂĄvel. Eu fico realmente muito alegre vendo o envolvimento dele com projetos como a NodeSchool. Pelo tĂłpico da palestra, dĂĄ para ver como ele acredita bastante em JavaScript.

Como o Laurie disse, o trabalho feito foi sensacional. Mereceu todos os aplausos recebidos, tanto pela apresentação quanto pelos projetos paralelos que organizou.

E ele fala PortuguĂȘs (nĂŁo sĂł no Twitter).

Brendan Eich

NĂŁo estive na BrazilJS 2012, entĂŁo esse foi o meu primeiro encontro com aquele conhecemos como criador do JavaScript.

A palestra dele foi engraçada, motivacional e também técnica. Falou sobre como foi criar o JavaScript em 10 dias, deu explicaçÔes sobre o wtfjs, e mostrou o quanto valeu a pena acreditar no JavaScript.

Terminou com a frase que foi a grande mensagem da BrazilJS 2015: always bet on JS.

O fim

O evento acabou com um show de rock e cerveja artesanal. NĂŁo sou uma pessoa agitada, nem gosto de beber cerveja, nem queria me arriscar a chegar tarde em casa (voltaria de ĂŽnibus), entĂŁo me limitei a finalizar meu dia indo falar com o Daniel Filho, que estava com outras duas pessoas, o Leonardo Balter e o Igor-que-foi-aprender-InglĂȘs.

(Conversar com o Leonardo faz bem para a mente, pois ele nĂŁo sĂł se dispĂ”e a te ouvir como tambĂ©m te recebe bem. Se um dia encontrĂĄ-lo, inicie uma conversa, talvez vocĂȘ ganhe um grande amigo.)

Saindo do BarraShoppingSul, lembro que, fora do shopping, aquele Ă© um lugar deserto. Deserto. Em direção a parada, com meu computador na mochila, encontro um homem que promete nĂŁo me assaltar e que sĂł quer dinheiro para ir para casa. Dou o que tenho para ajudar, e ele insiste que eu dĂȘ mais, afirmando saber que eu tenho mais. Nego gentilmente, e entro no T4 para ir embora logo. E, aos que nĂŁo conhecem Porto Alegre, o T4 Ă© simplesmente o ĂŽnibus mais inseguro da cidade.

Era um assaltante. Isso foi me dito no ĂŽnibus por uma moça, que disse tambĂ©m que tive sorte de nĂŁo ter sido assaltada. NĂŁo entendi o que me salvou, se foi a distĂąncia que mantive do homem, se foi o fato de eu nĂŁo estar desatenta no celular
 Enfim, cheguei em casa bem e feliz com os dois dias que se passaram.

Notas sobre o espaço

  • O lugar onde a conferĂȘncia ocorreu Ă© legal, pareceu bem mais aberto que o Bourbon Country e nĂŁo distancia as pessoas de quem palestra. O Teatro do Bourbon Country Ă© confortĂĄvel, exageradamente belo, possui uma Ăłtima acĂșstica; mas, alĂ©m de enjoar, valoriza muito quem estĂĄ palestrando, pois Ă© um espaço para dar palestras e nada mais. Todo o networking que acontece ali Ă© fora de onde as palestas ocorrem.
  • O espaço nĂŁo Ă© mais aberto no sentido de nĂŁo te sufocar. O local fica no subsolo do shopping, portanto, nĂŁo hĂĄ acesso fĂĄcil e sem demora a rua, como havia no Bourbon Country. Lembro bem de ver o sol na BrazilJS do ano passado. Parece pouco, mas Ă© muito importante quando se fica dois dias no mesmo lugar, com luz artificial e tal. Isso simplesmente dĂĄ muita abertura para acelerar a fadiga, ainda mais que vocĂȘ acaba comendo no shopping pela facilidade (pois a Ășnica coisa que tem no bairro do Barra Ă© o prĂłprio Barra, sĂ©rio), entĂŁo vocĂȘ nunca sai dali. Sinceramente, durante essa BrazilJS, eu esqueci que orbitĂĄvamos ao redor de uma estrela chamada Sol. (Esse parĂĄgrafo Ă© muito pessoal, realmente nĂŁo espero que ninguĂ©m concorde comigo com meus exageros, e de nenhuma forma exijo que sejam levados em consideração.)
  • Muitas pessoas levam notebooks e o Espaço BrazilJS foi uma Ăłtima ideia para lidar com isso. Conciliou o Ăștil (reconferir palestras, programar durante coffee break) ao agradĂĄvel (nĂŁo ficar no computador durante palestras). É muito legal ter um lugar para ficar com o notebook, embora eu nĂŁo recomende levar caso vĂĄ embora de ĂŽnibus, como vivenciei.

Notas finais

  • Foi difĂ­cil comer e beber no primeiro dia. Percebi que, em vez de as pessoas organizarem-se em filas, muitas ficavam no entorno da mesa do coffee break, e isso dificultou muito o fluxo. No segundo dia, no entanto, foi bem mais organizado.
  • Os organizadores nĂŁo param. EstĂŁo sempre envolvidos com o evento, resolvendo pendĂȘncias e atendendo a feedbacks. Houve dedicação integral por parte do Daniel, Felipe e Jaydson em fazer uma conferĂȘncia confortĂĄvel para todos. O segundo dia nĂŁo foi mais tranquilo porque simplesmente foi e a a conferĂȘncia deste ano nĂŁo foi mais diversa porque simplesmente foi. Agradeço a eles por isso.
  • Percebi uma mudança de formato em vĂĄrios aspectos neste ano, e a principal delas foi a redução da duração das palestras. Bastante notĂĄvel. 30 minutos por padrĂŁo, e aproximadamente 1 hora para keynotes. Gostei bastante, jĂĄ que possibilitou uma transição bem saudĂĄvel entre assuntos e palestrantes, o que ajuda muito a digerir o conteĂșdo. A BrazilJS dura 2 dias inteiros que terminam cansativos, e Ă© fato que isso acelera o cansaço, mesmo quando a apresentação estĂĄ muito interessante.
  • Quanto mais eu comia o chocolate da Mozilla, mais eu queria. Tive de comer 7 seguidos para satisfazer o meu consumo desenfreado de açĂșcar. E nĂŁo recomendo para ninguĂ©m.
  • A quantidade de homens Ă© avassaladora. Embora as iniciativas em apoio Ă  diversidade tenham sido realmente efetivas (vi, por exemplo, mais mulheres neste ano), sabe-se bem que uma mulher na BrazilJS Ă© uma mulher em meio a homens. É o que a proporção permite afirmar.
  • NĂŁo havia camisetas da BrazilJS para mim, e isso me deixou um pouco triste, pois elas estavam muito bonitas neste ano. Segundo o Eu Compraria, a confecção foi apenas de versĂ”es masculinas da camiseta. No entanto, o problema nĂŁo Ă© a versĂŁo ser masculina, o problema Ă© que o tamanho P da versĂŁo masculina Ă© gigante em mim. AtĂ© a vendedora ficou com dĂł da minha situação. :-(
  • O BarraShoppingSul Ă© um shopping completo e muito espaçoso, mas o bairro onde ele estĂĄ Ă© bastante inseguro e difĂ­cil de acessar caso vocĂȘ nĂŁo esteja vindo de carro.
  • O Daniel Filho Ă© um apresentador muito legal.
  • A BrazilJS 2015 foi Ăłtima, e isso me deixa bastante ansiosa para a conferĂȘncia de 2016.

Até o próximo ano!

\ No newline at end of file diff --git a/blog/computer-and-human-languages/index.html b/blog/computer-and-human-languages/index.html new file mode 100644 index 0000000..2b5b873 --- /dev/null +++ b/blog/computer-and-human-languages/index.html @@ -0,0 +1,45 @@ +Computer and Human Languages | Diéssica Gurskas
diessi.caBlog
June 20, 2018

Computer and Human Languages

Basic knowledge of computer languages (mainly JavaScript) is assumed.

Some time ago, a friend of mine asked how skilled I’d say I was with JavaScript. I told him I was fluent.

– Fluent? What does it mean to be fluent?

– Well, think Portuguese. – We both speak Portuguese — I don’t know every word, but I do know the language enough to express anything I need somehow.

It turned out that “fluent” was just the perfect word.


Fluency is a powerful and straightforward concept to express your ability with a language. When it comes to human languages, it’s the ability to fully communicate your intentions to a human; for computer languages, the ability to fully communicate your intentions to a computer.

That line of thought is shared in one of the most important and revolutionary introductory books to Computer Science. In Structure and Interpretation of Computer Programs, right before introducing Lisp (the programming language used throughout the book) a similar analogy is made:

Just as our everyday thoughts are usually expressed in our natural language (such as English, French, or Japanese), and descriptions of quantitative phenomena are expressed with mathematical notations, our procedural thoughts will be expressed in Lisp. 1

For both kinds of languages, the levels are the same: one cannot communicate; can poorly do it (beginner); can do it (native/fluent), or can brilliantly do it (think book authors, public speakers, and Software Engineers in a senior level).

Why do they match so well?

They match because the linguistics of computer and natural languages wonderfully intersect. Both consist of syntax, semantics and pragmatics functions, found in the core of theoretical linguistics.

In their ecosystem, we can also find syntax trees and different style guides.

Syntax

Syntax is the set of rules that govern how language elements are combined to form a valid expression.

In English, the basic rule is that elements like nouns, verbs and punctuation marks must follow the subject-verb-object order to produce a valid sentence. In JavaScript, a programming language, to produce a valid conditional statement, elements such as if, parenthesis, braces, comparison operators (===, <= ) must be combined in a certain order too.

In the same way that “Do they car a put?” (??) is not valid English, the following code is not valid JavaScript:

if {1 === 2} (
+  return true
+)
+// => SyntaxError: missing ( before condition
+
+add x y = x + y  // u can't use elm's lambda syntax on js, no
+

And just like a pedant friend would do when you write shitty English, the computer will throw a syntax error when running your program. Forgot closing a brace? Wrote an if statement condition using curly braces instead of parenthesis? Well, SyntaxError!

This, however, is valid JavaScript:

if (1 === 2) {
+    return true
+} // "if (1 === 2) return true" is also fine!
+
+const add = (x, y) => x + y
+

In HTML there are syntax rules too. Adding a div inside ul, for instance, is invalid. An unordered list in HTML (ul) only allows list items as children, such as li – and div is not one.

Languages have different degrees of syntax strictness, which is what usually makes some harder to grasp than others. Think the German language – German imposes very strict rules for articles: they may vary in number, gender, and function. English, on the other hand, has a definite (the) and an indefinite article (a/an) – and that’s it.

The same applies to computer languages: some happen to be extremely strict when it comes to syntax, while others are designed for greater syntactic flexibility, letting you achieve the same result in different ways. Think semicolons: they are optional when ending statements in JavaScript, but mandatory in C.

Semantics

Semantics is what the language expression evaluates to. In human languages, expressions evaluate to thoughts, questions, answers; while computers evaluate expressions to CPU instructions that comprise a program’s flow.

Consider the following English statement:

The ant ran over the car.

I don’t know what ants you are familiar with, but even though the sentence contains the necessary elements in correct order and grammar, that doesn’t make sense. The statement is syntactically correct but semantically wrong – we can’t conceive a meaning from it.

(“The car ran over the ant”, however, would be definitely more acceptable to our ears.)

We can relate semantics to computer languages in several ways (like “solving the wrong problem”, basically), but the “semantic” word bubbles up more often when we think about HTML. Consider the following markup:

<span>What is a fruit?</span>
+<div>
+    A fruit is something that humans eat. Some examples of fruits are:
+    watermelon, pineapple and apples.
+</div>
+

The elements span and div do exist in the language and are validly marked in this case (I didn’t do >div<, right?), so the browser will understand and show it accordingly to the user. The syntax is correct; yet, span and divs are non-semantic elements, so computers won’t get any meaning from it. Again, syntactically correct but semantically wrong.

That text, though, is clearly a title and a paragraph. With a bit of HTML knowledge, we can communicate this in a meaningful way to computers! The language provides elements to achieve that.

The following code improves the previous markup for better semantics.

<h1>What is a fruit?</h1>
+<p>
+    A fruit is something that humans eat. Some examples of fruits are:
+    watermelon, pineapple and apples.
+</p>
+

The element h1 is being used to communicate the main title, and p communicates the paragraph. Both syntax and semantics make sense now!

Pragmatics

Pragmatics is what the language expression evaluates to within its interactional context – which might totally affect semantics and syntax.

In a natural language, the context is essentially built around the cultural aspects of the speaker, place, time, manner, and several others unpredictable aspects that humans introduce when communicating.

For computer languages, we can see pragmatics as the methodology or implementation used when approaching a problem: composition vs. inheritance, functional vs. imperative, picking a Design Pattern etc.

Consider the following examples:

  • A child saying that the food is horrible to a beginner that started cooking just recently.
  • A new joiner in the company filters items in an JavaScript array using forEach, but the team expected filter to be used – a more functional approach.
  • A programmer implements Fibonacci with recursion instead of iteration.
  • Your friend uses a very erudite language to add a cake recipe on the internet.

What do they all have in common? By themselves, they are neither right or wrong – unless you consider the context in which they were approached in.

Having either syntax or semantic skills won’t help you understand what’s wrong, since pragmatics is more about what’s appropriate within a context. Some approaches are more elegant, antiquated, or dialect-based than others, and we can only tell how valid they are considering what we are trying to achieve.

Syntax trees

Both kinds of languages can be represented using syntax trees, a concept that reuses the mathematical concept of partially ordered sets.

Human languages are analysed through the Concrete Syntax Tree (“CST”), a context-free analysis that tells us about the function of each language token (word, punctuation etc) used.

This is the Concrete Syntax Tree for the previous sentence, “The water drank a glass of Mary.”:

Concrete Syntax Tree of the sentence 'The water drank a glass of Mary.'
Concrete Syntax Tree for a sentence in a human language, where "S" stands for "sentence", "N" for "noun", "V" for "verb", and P for "phrase". See Wikipedia on Parse Trees for more information.

Computer languages are also represented using syntax trees! When the code (high-level) gets translated into instructions for the computer (low-level), a program called compiler make uses of them. The Concrete Syntax Trees for a program contains a lot of detailed information, from whitespaces to language expressions, so you can imagine a CST for a real-world JavaScript program as something really lengthy.

What compilers do might be tough to understand at first, but think of this program inside us that converts languages to meaning – our internal compiler. Kids improve their compilers while communicating with their families, so every day they get to understand their mother language even more. If you understand English yet struggle with German, we can say your German compiler is pretty bad and has to be improved.

The compiler simplifies the CST down to the expressions that truly represent the program after syntax analysis. That’s where the Abstract Syntax Tree (AST) comes in: the syntax tree that actually lies at the heart of semantic definitions!

Let’s consider the following JavaScript program:

let x = 0
+
+if (x) {
+    x++
+}
+

This is the Abstract Syntax Tree for it:

Concrete Syntax Tree of the sentence 'The water drank a glass of Mary.'
Abstract Syntax Tree for a JavaScript program.

It’s really about the essentials when considering language grammar. If a whitespace means nothing in a language, that won’t show up in the AST.

Compare that against a Concrete Syntax Tree for another program of similar size, which is way more detailed, and therefore more useful in a language-specification level.

Style guides

When the same expression can be written in several ways because the language is not strict enough about it, style guides aim to answer the question of which style to go for. Curiously, style guides of writing are just as useful for programmers as they are for journalists!

Let’s say I’m telling someone my favourite fruits. I could do it in different ways:

My favourite fruits are watermelon, bananas and strawberries.
+
+// or using the Oxford comma
+My favourite fruits are watermelon, bananas, and strawberries.
+

The Oxford comma comes from the Oxford Style Guide.

In JavaScript, you can write a JavaScript object in different ways too:

const hero = {
+    firstName: "Ada",
+    lastName: "Lovelace",
+    birthYear: 1815,
+    superPower: "computers",
+}
+
+// or comma-first style
+const hero = {
+    firstName: "Ada",
+    lastName: "Lovelace",
+    birthYear: 1815,
+    superPower: "computers",
+}
+

Either way, there’s no definite rule. They mean the same, only changing their style of writing.

Some examples of style guides are Airbnb’s Style guide, for writing JavaScript; and Chicago style guide, for general writing.

Where they don’t match

The programmer, like the poet, works only slightly removed from pure thought-stuff. He builds his castles in the air, from air, creating by exertion of the imagination. [
] Yet the program construct, unlike the poet’s words, is real in the sense that it moves and works, producing visible outputs separately from the construct itself. It prints results, draws pictures, produces sounds, moves arms. 2

Even with all the similarities, programming languages are still artificial, while human languages are natural. Computers are rigorous, won’t allow you to be ambiguous, and only get what you mean if you put it the right way.

You won’t have filler words in a computer language, because computers don’t benefit from your thought process. Humans do benefit, though, and I’d even say that those communication imperfections is what connects us to others.

Apart from that, a programming language is an interface between you and a computer, while a natural language is an interface between you and another human being. You are communicating to a computer, but as a human – and you probably won’t be the only one doing it.

Writing in a way that’s meaningful for both is therefore part of the writing process – and probably the most demanding one.

Final thoughts

Just like experienced programmers look at documentation and easily apply language features to create pieces of software, fluent English speakers would look at the dictionary and easily come up with phrases.

Because both computer and natural languages share linguistic structures, speaking about programming skills in terms of fluency works just as well.

After all, fluency is all about how easily our intentions are expressed with a language.


As a next reading, I'd highly recommend Exploring the Linguistics Behind Regular Expressions if you are interested in the linguistics of computer languages.


Follow the discussion thread on Reddit

1

“Programming in Lisp” in “Structure and Interpretation of Computer Programs”, 1979.

2

Fred Brooks. “The Mythical Man-Month: Essays on Software Engineering”, 1975, page 7.

\ No newline at end of file diff --git a/blog/creativity/index.html b/blog/creativity/index.html new file mode 100644 index 0000000..68f5d72 --- /dev/null +++ b/blog/creativity/index.html @@ -0,0 +1 @@ +Creativity | Diéssica Gurskas
diessi.caBlog
February 05, 2018

Creativity

In a life where, by default, there’s no meaning at all, I value creating above all. If I’m creating, that’s a meaningful day.

Lately, I’ve been pondering on the phenomenon of creativity and why creative people are so inspiring to be around. They just broaden my perception of the universe profoundly. What really happens?

The Phenomenon

In an interview in the late 1990s1, Steve Jobs said something that years later would be seen as one of the most simple but accurate definitions of creativity:

Creativity is just connecting things.

And he followed with something I couldn’t help but relate: “When you ask creative people how they did something, they feel a little guilty because they didn’t really do it, they just saw something. It seemed obvious to them after a while. [
]”.

In the wake of being called creative, I was used to responding with the most unfair answer ever: “But everything I did was mixing stuff from here and there!?!“. It turns out, however, that “mixing stuff” actually describes precisely the process creative people go through.

And when Steve Jobs said that, he was mixing stuff as well! He most likely got inspired by James Webb Young’s conception of idea, presented in his book A Technique for Producing Ideas, from the 1940s.

An idea is nothing more nor less than a new combination of old elements [and] the capacity to bring old elements into new combinations depends largely on the ability to see relationships.

For James to suggest that, well, guess what? He was inspired by Pareto's idea of the "speculator", a personality type characterized by a constant preoccupation with the possibilities of new combinations of old elements. (Which sort of proves his own point on "ideas as a combination of old elements".)

Creatives are just so overloaded with elements to mix that those overflow and flow out of their heads, and they can’t help but inspire everyone around.

They reframe experiences and mix their elements to be synthesised into something valuable and unique. From songs, painting, programming to scientific theories – all of them comes from mixtures. When the mixture feels good, either as a homogeneous or heterogeneous result, it’s then a creation.

The Creation, The Weird

Creativity comics
Creativity, by Alex Norris.

When the creation distances itself too much from its origin elements (which are things people are already aware of, most likely), it’s perceived as weird, rather than authentic. But that’s when we truly innovate! To come up with the weird, though, we have to limit ourselves to certain existing elements – an outstanding habit people like Alan Turing had.

Alan Turing was an inspiring computer scientist. Among other cool stuff, he proposed humans to consider the question "Can computers think?", and also designed cryptanalytical machines, crucial to cracking German encoded communication during the World War II. Cool stuff!

As described by James Wilkinson, who worked closely with him, Turing avoided looking at previous work on a topic just so he could invent something truly original, truly weird.

”Turing had a strong predilection for working things out from first principles, usually in the first instance without consulting any previous work on the subject, and no doubt it was this habit which gave his work that characteristically original flavor.“ 2

Finally, the ones who release their creations end up turning into painters, mathematicians, writers, architects, sculptors, programmers, musicians. It’s a process that happens in absolutely every realm of thinking and work.

And you know what?


It’s Been Shown by Nature

When Young and Steve Jobs pointed out that the creative process wasn’t magic, they, again, didn’t do anything “new” either. That definition has been shown by Nature for a long time, and, as early as 450 B.C, the philosopher Anaxagoras described it:

Wrongly do the Greeks suppose that something3 begins or ceases to be; for nothing comes into being or is destroyed; but all is an aggregation or secretion of pre-existing things; so that all becoming might more correctly be called becoming mixed, and all corruption, becoming separate.

That might remember you of the Law of Conservation of Mass, later defined by the chemist Antoine Lavoisier.

Just like in the creative process, Nature has always found a way out of its problems by coming up with solutions from pre-existing elements. Even the Planet Earth has transformed from a violent, molten rock to a supporter of life by using what the Universe had already provided!

Its process of creation was the same as the human’s creative process for the discovery of fire, the invention of the wheel, shitty and useful startup ideas, the Pink Floyd’s Echoes song, and all quotes in this post: mixing, connecting, combining “stuff”. From the Planet Earth to what you’re reading right now, the laws that ruled their creations were, in essence, the same.

2

James H. Wilkinson, “Some Comments from a Numerical Analyst”, 1970. Turing Award lecture, Journal of the ACM. February 1971.

3

I’ve deliberately changed “aught”, an archaic English word, to “something” for the sake of readability.

\ No newline at end of file diff --git a/blog/dental-health-and-habits/index.html b/blog/dental-health-and-habits/index.html new file mode 100644 index 0000000..c62c9f3 --- /dev/null +++ b/blog/dental-health-and-habits/index.html @@ -0,0 +1 @@ +Dental Health and Habits | Diéssica Gurskas
diessi.caBlog
December 21, 2017

Dental Health and Habits

Brushing teeth is a good habit. An easy-to-build one, I’d say, thanks to the immediate reward given by the refreshing sensation. After brushing, you feel clean right away.

On the other hand, flossing teeth isn’t a habit as easy to build. After flossing, what comes to mind is how dirty your teeth still were even though you just brushed, not how cleaner they became. There’s no such thing as a fresh sensation in your mouth.

When you finish brushing your teeth, they’re still dirty – no doubt. However, it’s still gratifying, since you’re fooled by the menthol ability to trigger the cooling sensation. (Hence the human inclination to brushing rather than flossing!?)

In terms of dental health, though, flossing teeth is more effective on cleaning than brushing1, even if it doesn’t feel like it. There’s no immediate reward in flossing, but definitely a long-term one.

What am I trying to say? Apart from dental health advice, that sort of reminds me that we shouldn’t rely on feeling instantaneously compensated as a fuel to build habits. After all, some things just need the long-term to pay off; for we to benefit from them.

1

I’ve read that at some point in my life but don’t remember where. You can find some resources out there, such as “What’s More Important: Flossing or Brushing?”. Anyway, I think we’re safe assuming that flossing is, at least, as important as brushing.

\ No newline at end of file diff --git a/blog/desmitificando-seletores-complexos/index.html b/blog/desmitificando-seletores-complexos/index.html new file mode 100644 index 0000000..b9737ad --- /dev/null +++ b/blog/desmitificando-seletores-complexos/index.html @@ -0,0 +1,46 @@ +Desmitificando Seletores Complexos | Diéssica Gurskas
diessi.caBlog
November 28, 2013

Desmitificando Seletores Complexos

Se existem recursos no CSS que a total compreensĂŁo se restringe a uma parcela de desenvolvedores, esses sĂŁo os combinadores filhos (>), irmĂŁos adjacentes (+) e adjacentes gerais (~).

Sem dĂșvidas, esses 3 combinadores sĂŁo tĂŁo poderosĂ­ssimos quanto mal-explicados. É importante compreendĂȘ-los integralmente e hĂĄ dois bons motivos para isso: o seletor descendente nĂŁo dĂĄ conta de tudo e, o Ăłbvio: o CSS estĂĄ evoluindo.

X > Y

Todo filho Ă© necessariamente descendente, mas nem todo descendente Ă© necessariamente filho.

— Eu, sobre família

Para que Y seja alvo da seleção, nĂŁo importa a posição; basta que seja descendente direto de X - isso Ă©, filho. Em outras palavras, basta que esteja interno diretamente ao elemento pai - e seja somente descendente dele. Isso quer dizer que Y nĂŁo serĂĄ alvo caso esteja interno a um elemento Z, mesmo que este esteja interno a X. Por essa razĂŁo o combinador “>” Ă© tambĂ©m chamado de direto, pois nĂŁo admite elementos internos indiretamente.

Seletor descendente vs. seletor filho

Lembrando da frase dita no inĂ­cio desse tĂłpico, vocĂȘ jĂĄ entende a diferença. Enquanto o descendente (X Y) herda as propriedades aos elementos direta e indiretamente internos (filhos, netos, bisnetos
), o alvo do combinador filho sĂŁo os filhos unicamente diretos - sim, falar isso Ă© redundante. O que faz todo sentido, afinal, um filho Ă© tanto filho quanto descendente; e o neto, bisneto, trineto nĂŁo Ă© um filho, mas Ă© descendente.

Na prĂĄtica

Imaginemos um artigo e seus respectivos parĂĄgrafos. Dentro desse artigo, haverĂĄ uma seção de informaçÔes que nĂŁo estarĂĄ diretamente relacionada ao artigo. Como o que se quer destacar Ă© a leitura do artigo, seus parĂĄgrafos terĂŁo mais ĂȘnfase de alguma forma.

HTML
<article>
+  <h1>TĂ­tulo do artigo</h1>
+  <p>Primeiro parĂĄgrafo</p>
+  <p>Segundo parĂĄgrafo</p>
+  <aside>
+    <h2>InformaçÔes</h2>
+    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
+  </aside>
+  <p>Terceiro parĂĄgrafo</p>
+</article>
+
CSS
article > p {
+  font-style: italic;
+}
+

Assim, somente os parĂĄgrafos que sĂŁo filhos diretos do elemento article serĂŁo estilizados.

X + Y

Se para ser alvo do seletor filho a posição era irrelevante, para ser alvo de um seletor irmão adjacente sua posição é critério decisivo. O elemento Y deve ser o primeiro elemento após X, com ambos dentro de um mesmo elemento Z (pai). O nome, portanto, é bem autoexplicativo: são irmãos por possuírem o mesmo pai (no caso, Z) e adjacentes por estarem necessariamente próximos.

Na prĂĄtica 1

Supondo um artigo constituído por um título e 3 parågrafos. O primeiro parågrafo após o título servirå como uma introdução ao artigo e, portanto, deve ser destacado com um aumento no tamanho da fonte.

HTML
<article>
+  <!-- Z -->
+  <h1>TĂ­tulo do artigo</h1>
+  <!-- X -->
+  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
+  <!-- Y -->
+  <p>Debitis sint aperiam numquam nisi animi porro in reprehenderit!</p>
+  <p>Magnam atque placeat fuga sed eligendi maxime neque labore. Doloribus?</p>
+</article>
+
CSS
h1 + p {
+  font-size: 20px;
+}
+

Na prĂĄtica 2

O checkbox hack funciona com o uso do combinador irmĂŁo adjacente.

HTML

<input type="checkbox" id="hider" />
+<div>Hide me if you can!</div>
+<label for="hider">Esconder div</label>
+

CSS

input[type="checkbox"] {
+  display: none; /* Esconde o checkbox */
+}
+input:checked + div {
+  display: none; /* Quando o checkbox for checado, a div serĂĄ escondida */
+}
+

X ~ Y

Seletor do CSS 3, o combinador adjacente geral tem uma definição bem semelhante ao irmão adjacente. Para que Y seja alvo, os elementos X e Y devem ser filhos de um mesmo elemento (irmãos) e X deve preceder Y, direta ou indiretamente - isso é, para que Y seja alvo, esse precedimento não precisa ser imediato.

Na prĂĄtica

Esse combinador contorna algumas inflexibilidades do combinador irmão adjacente. Ainda com o exemplo do checkbox hack, podemos personalizar o elemento de forma não tão específica quanto à sua posição:

HTML

<input type="checkbox" id="shower" />
+<label for="shower">Mostrar div</label>
+<div>Hide me if you can!</div>
+<div>Hide me too if you can!</div>
+

CSS

input[type="checkbox"],
+div {
+  display: none; /* Esconde o checkbox e a div, por padrĂŁo */
+}
+input:checked ~ div {
+  display: block; /* Quando o checkbox for checado, a div aparecerĂĄ */
+}
+

ConclusĂŁo

As linguagens CSS e HTML foram documentadas para serem intuitivas: os elementos formam famĂ­lias com outros elementos pais, filhos, descendentes, irmĂŁos
. Isso fica claro no nome dos seletores, que tĂȘm papel importante na compreensĂŁo do combinador; afinal, caso o desenvolvedor entenda que irmĂŁos tem o mesmo pai e que filhos sĂŁo descendentes diretos do pai, ele poderĂĄ tirar um bom proveito do nome dos combinadores para compreender seus funcionamentos.

[
] In both cases, non-element nodes (e.g. text between elements) are ignored when considering adjacency of elements.

Hå uma grande confusão - e com razão - entre os seletores irmãos adjacentes e irmãos gerais. Essa confusão se origina não só de suas classificaçÔes como seletores de combinação, mas em seus comportamento e definição semelhantes. Tanto é verdade que o combinador adjacente geral (~) se comportarå muitas vezes como um irmão adjacente (+), com a diferença de que o adjacente geral é menos exigente quanto à posição do elemento-alvo.

O uso serå, portanto, facultativo em diversas situaçÔes. E, nesse caso, a minha recomendação é dar prioridade ao combinador adjacente, visto que é um seletor do CSS 2.1 e, portanto, compatível com uma maior gama de browsers. :-)

ReferĂȘncias

\ No newline at end of file diff --git a/blog/dont-blame-it-on-react-or-redux/index.html b/blog/dont-blame-it-on-react-or-redux/index.html new file mode 100644 index 0000000..2cc6ec4 --- /dev/null +++ b/blog/dont-blame-it-on-react-or-redux/index.html @@ -0,0 +1 @@ +Don't Blame it on React or Redux | Diéssica Gurskas
diessi.caBlog
March 18, 2017

Don't Blame it on React or Redux

What most people don’t know when they first get into Redux is that, just like React, Redux itself is meant to be simple. And as seen that simplicity is a goal, both React and Redux won’t and don’t want to tell you how to solve everything.

They won’t tell you how to deal with side effects, or what HTTP request library you should use. That’s completely delegated to the JavaScript ecosystem.

React and Redux alone don’t do much for really complex web applications.

React indirectly delegates state management problems to solutions like Flux. On the other hand, Redux, for instance, delegates dealing with async stuff or even the too-much-boilerplate problem that people complain.

But what motivates React and Redux to be that way? Some reasons I can think of are:

  • Both libraries are highly focused on their principles, not the built-in stuff. The efficiency of them is on the why and how, not the what.
  • They aim to be a great fit for both simple and large applications, so the “plug-in-play” approach is followed. (A framework wouldn’t ever do everything a programmer needs anyway
)
  • Diversity of solutions. Because React and Redux are more like “plug-in-play”, the “plugins” (tools, libraries, middlewares) will evolve by themselves. For instance: axios, a HTTP request library, will evolve in parallel to Redux itself – which certainly make things move forward faster!

If your application’s state is messy, don’t blame it on React. If you find yourself writing too much boilerplate, don’t blame it on Redux. React and Redux don’t really do much, but this is by design.

React is awesome not just because it makes it possible to turn a large and complex application into simple components.

Redux is awesome not just because it makes it effortless to deal with and share state throughout an application.

They’re also awesome because of their great and diverse ecosystem. So, when you buy into React or Redux, it’s better for you to buy into their ecosystem too.

\ No newline at end of file diff --git a/blog/encadeamento-de-metodos-em-javascript/index.html b/blog/encadeamento-de-metodos-em-javascript/index.html new file mode 100644 index 0000000..46224b1 --- /dev/null +++ b/blog/encadeamento-de-metodos-em-javascript/index.html @@ -0,0 +1,63 @@ +Encadeamento de Métodos em JavaScript | Diéssica Gurskas
diessi.caBlog
August 06, 2016

Encadeamento de MĂ©todos em JavaScript

Popular em diversas bibliotecas JavaScript, o encadeamento de mĂ©todos (“method chaining”) Ă© uma tĂ©cnica usada para invocar diversos mĂ©todos em um mesmo objeto.

Com o objetivo de melhorar a legibilidade do código, a técnica é vastamente utilizada na API da jQuery, o que certamente influenciou na popularidade da biblioteca.

Se vocĂȘ jĂĄ utilizou jQuery, o estilo do cĂłdigo abaixo pode ser familiar:

$("#my-element")
+  .css("background", "purple")
+  .height(100)
+  .animate({ height: 250 })
+  .find("input")
+  .fadeIn(200)
+  .val("")
+  .end();
+

No exemplo acima, uma Ășnica declaração faz vĂĄrias coisas. No entanto, uma boa prĂĄtica com method chaining Ă© fazer somente uma ação por declaração. ;-)

Perceba que vĂĄrios mĂ©todos sĂŁo invocados no objeto $('#my-element'), sem a necessidade de repetĂ­-lo. JĂĄ sem Method Chaining, Ă© necessĂĄrio fazer a referĂȘncia diversas vezes:

const myElement = $("#my-element");
+myElement.css("background", "purple");
+myElement.height(100);
+myElement.fadeIn(200);
+

Exemplo

Vamos criar um contador Counter:

class Counter {
+  constructor() {
+    this.value = 0;
+  }
+
+  increase() {
+    this.value += 1;
+  }
+
+  decrease() {
+    this.value -= 1;
+  }
+
+  log() {
+    console.log(this.value);
+  }
+}
+

Agora, vamos instanciar um contador e usar seus métodos:

const counter = new Counter();
+counter.increase();
+counter.log(); // => 1
+counter.decrease();
+counter.log(); // => 0
+

Perceba que é necessårio fazer vårias declaraçÔes para interagir com a instùncia, o que prejudica a legibilidade do código.

E se tentarmos usar Method Chaining


new Counter().increase().log();
+// > TypeError: Cannot read property 'log' of undefined
+

Perceba que log() estĂĄ sendo executado em new Counter().increase(), que, por sua vez, estĂĄ retornando undefined. Portanto, ainda nĂŁo Ă© possĂ­vel interagir com Counter dessa forma.

Como Encadear MĂ©todos

Para evitar a repetição do objeto, é necessårio que seus métodos retornem o próprio objeto.

Veja este exemplo com Promises:

getJSON("users.json")
+  .then(JSON.parse)
+  .then((response) => console.log("Olha o JSON!", response))
+  .catch((error) => console.log("Falhou!", error));
+

Isso só é possível pois os métodos then() and catch() sempre retornam outras promises. Assim, podemos dizer que as Promises são fluent APIs, tal como a jQuery.

Quem Lembra do this?

Para os métodos serem encadeados, serå necessårio retornar o contexto (this) em cada método.

Em JavaScript, this sempre se refere ao contexto de execução de função.

No caso de um método, que é uma função de um objeto, refere-se ao próprio objeto.

Exemplo com Method Chaining Pattern

Para implementar o encadeamento de métodos na classe Counter, apenas retornamos seu contexto a cada método:

class Counter {
+  constructor() {
+    this.value = 0;
+  }
+  increase() {
+    this.value += 1;
+    return this; // Aqui!
+  }
+  decrease() {
+    this.value -= 1;
+    return this; // Aqui!
+  }
+  log() {
+    console.log(this.value);
+    return this; // E aqui!
+  }
+}
+

Agora, ao executar new Counter().increase(), o retorno jĂĄ nĂŁo serĂĄ mais undefined.


E, portanto, Ă© possĂ­vel fazer method chaining!

new Counter()
+  .increase()
+  .log() // => 1
+  .decrease()
+  .log(); // => 0
+

ConclusĂŁo

No universo de APIs orientadas a objetos, o encadeamento de métodos é uma técnica incrível se o seu objetivo é tornar o código mais expressivo e fluente.

No geral, fluent APIs sĂŁo sim interessantes de se entender e implementar, e vocĂȘ pode ter certeza disso analisando o primeiro exemplo com jQuery do inĂ­cio deste artigo. É fantĂĄstico! Mas Ă© importante entender que o encadeamento de mĂ©todos nem sempre tornarĂĄ as coisas mais fĂĄceis (debugar, por exemplo, se torna mais difĂ­cil), e, portanto, a maneira aparentemente “mĂĄgica” com que elas funcionam nĂŁo deve ser sempre levada em consideração.

\ No newline at end of file diff --git a/blog/expressive-javascript-conditionals/index.html b/blog/expressive-javascript-conditionals/index.html new file mode 100644 index 0000000..0f206bb --- /dev/null +++ b/blog/expressive-javascript-conditionals/index.html @@ -0,0 +1,165 @@ +Expressive JavaScript Conditionals (for Humans) | Diéssica Gurskas
diessi.caBlog
October 30, 2017

Expressive JavaScript Conditionals (for Humans)

Conditionals! As programmers, we write at least one every day. Easy to write, horrible to read, and sometimes it seems as though there’s no way to work around that.

Today, I’m happy to share some patterns I’ve learned over time and have spread heavily in code reviews. Let’s rethink conditionals to make the most out of a language’s power of expression – in the case of this article, JavaScript.

Patterns for Conditionals

First, to put you in the mood, a quote from Literate Programming1, by Donald Knuth.

The practitioner of literate programming can be regarded as an essayist, whose main concern is with exposition and excellence of style. Such an author, with thesaurus in hand, chooses the names of variables carefully and explains what each variable means. He or she strives for a program that is comprehensible because its concepts have been introduced in an order that is best for human understanding, using a mixture of formal and informal methods that reinforce each other.

That sums up the approach for this post: purely aimed at how to write code for people to read. Performance doesn’t matter now, since 1) that’s not the goal and 2) I don’t believe in premature optimisation.

I’ll briefly talk about each pattern, but what’s more important here is to read the code carefully and get something out of it (as if it were poetry or something!).

1. Variables that hold conditions

When your condition is made up of an expression (or many of them), you can store it within meaningful-named variables.

Let’s say, to illustrate, that our program holds some data about a fruit and we have to check whether that fruit is a banana. We could do this:

const fruit = {
+    colors: ["yellow", "green"],
+    sweet: true,
+}
+
+if (fruit.sweet === true && fruit.colors.some((color) => color === "yellow")) {
+    alert("do your stuff 🍌")
+    return "is banana"
+}
+

Or we could store our conditions in variables!

const fruit = {
+    colors: ["yellow", "green"],
+    sweet: true,
+}
+
+const isSweet = fruit.sweet === true // or just `fruit.sweet`
+const isYellow = fruit.colors.some((color) => color === "yellow")
+const isBanana = isYellow && isSweet
+
+if (isBanana) {
+    alert("do your stuff 🍌")
+    return "is banana"
+}
+

Not all conditions need to be in a variable. fruit.sweet, for instance, is quite expressive by its own.

This way, if we or our workmates need to know what makes a fruit a banana in our program, it’s just a matter of checking out the variable itself. The logic for how conditions evaluate will be there, behind a meaningful name.

It’s even more useful for composing and reusing conditions.

Filtering arrays

In the previous example, all variables were conditions based on the fruit object, for didactic purposes. Commonly, though, those variables actually store (pure) functions that take any fruit and test against it. I'm changing that to fit this example.

Let’s say we’ve got an array of fruits and we need to filter all the bananas out of it.

const fruits = [
+    {
+        colors: ["yellow", "green"],
+        sweet: true,
+    },
+    {
+        colors: ["red"],
+        sweet: false, // don't know what kind of fruit this'd be
+    },
+]
+
+const isSweet = (fruit) => fruit.sweet === true
+
+const isYellow = (fruit) => fruit.colors.some((color) => color === "yellow")
+
+const isBanana = (fruit) => isSweet(fruit) && isYellow(fruit)
+
+const bananas = fruits.filter(isBanana)
+

So expressive! I love the way that I can read that last line and even a kid (a non-programmer one!) can understand. (Yes, I’ve tried that.)

The currying technique would help introduce expressiveness without the verbosity for isBanana. An optional appendix at the end of the article elaborates more on that, if you’re curious.

That’s it. Hold on to that one though – it’s the foundation for what’s next.

2. Define value conditionally

Still considering the variables from the example above, this could also be done:

const myFruit = isYellow && isSweet && "banana"
+return myFruit
+

The value for the myFruit variable will only be assigned to “banana” if those conditions are true. Pretty useful for when values are defined conditionally!

That saves you from if (isYellow && isSweet) [...], and it’s quite expressive, I’d say. An expressive expression. 👌

3. Define value conditionally with fallback

Conditionals, a comic from xkcd
xkcd: Conditionals

What if we want something else in case it’s not a banana? Instead of an if (isBanana) [...] with else, go for the ternary operator.

const isBanana = isYellow && isSweet
+const myFruit = isBanana ? "is banana" : "is other stuff"
+return myFruit
+

Some additional but important advice I’d give regarding ternary expressions:

  • Make them as compound as possible.
  • Do NOT nest them. Don’t pretend the nesting is readable – it’s not even human to do that.
  • Don’t avoid writing if statements because you want to look smart.

4. Check for all conditions

We’ve (finally) found out that checking for isYellow and isSweet isn’t enough to make sure the fruit is a banana. After all, yellow pepper is both sweet and yellow and it’s still not a banana, right?

Right. We then add more checks to the isBanana variable, and this time they’re ugly ones: they check whether the fruit is either from Brazil or Ecuador, both top banana producing countries.

const fruit = {
+    colors: ["yellow", "green"],
+    sweet: true,
+    countries: [
+        {
+            name: "Brazil",
+            topProducer: true, // i'm brazilian and therefore biased
+        },
+        {
+            name: "Ecuador",
+            topProducer: false,
+        },
+    ],
+}
+
+const isSweet = fruit.sweet === true // or just `fruit.sweet`
+const isYellow = fruit.colors.some((color) => color === "yellow")
+const isBrazilian = fruit.countries.find((i) => i.name === "Brazil")
+const isEcuadorian = fruit.countries.find((i) => i.name === "Ecuador")
+const isBanana = isYellow && isSweet && isBrazilian && isEcuadorian
+
+if (isBanana) {
+    alert("do your stuff!11 🍌")
+    console.log("now this is really a banana")
+}
+

Did you see how big isBanana is getting? We’d have to start breaking lines in those && to improve readability, which, personally, I don’t like doing.

If refactoring the booleans into new variables isn’t an option anymore, what about storing the conditions in an array and testing every item for truthiness?

Use the power of array’s every:

const isBanana = [isYellow, isSweet, isEcuadorian, isBrazilian].every(Boolean) // or `x => x === true`
+

Repetitive friendly reminder: don't store every condition in a variable. Remember you can always add the condition itself to the array.

You can even turn that into a snippet:

const all = (arr) => arr.every(Boolean)
+
+const isBanana = all([isYellow, isSweet, isEcuadorian, isBrazilian])
+

I don’t know how useful that looks for you, but, in everyday work, I really appreciate doing it.

5. Check for any condition

What if we’ve got crazy and we’re fine considering something a banana when it’s either yellow, Brazilian or sweet?

Use the power of array’s some:

const isBanana = [isYellow, isSweet, isBrazilian].some(Boolean) // or `x => x === true`
+

Yeah, yeah, I know, you can just use the OR operator.

If any of them evaluates to true, profit! – it’s a banana. 🍌

const any = (arr) => arr.some(Boolean)
+
+const isBanana = any([isYellow, isSweet, isBrazilian])
+

In other words, being a Brazilian means you’re a banana! It doesn’t sound any bad to me honestly.

Pretty similar to Ramda’s either. 😎

6. Early return

We want something special for when the banana is Brazilian! else conditions would do the trick, wouldn’t they?

const fruit = {
+    colors: ["yellow", "green"],
+    sweet: true,
+    countries: [
+        {
+            name: "Brazil",
+            topProducer: true, // i'm brazilian and therefore biased
+        },
+        {
+            name: "Ecuador",
+            topProducer: false,
+        },
+    ],
+}
+
+const isSweet = fruit.sweet === true // or just `fruit.sweet`
+const isYellow = fruit.colors.some((color) => color === "yellow")
+const isBrazilian = fruit.countries.find((i) => i.name === "Brazil")
+const isEcuadorian = fruit.countries.find((i) => i.name === "Ecuador")
+const isBanana = isYellow && isSweet
+
+if (isBanana && isBrazilian) {
+    // first true case!
+    alert("i am a brazilian banana i love football 🍌")
+} else if (isBanana && isEcuadorian) {
+    alert("i am an ecuadorian banana do not mess with me 🍌")
+} else {
+    alert("a normal banana from somewhere else")
+}
+

Alternatively, THOOOUGH, we can early return (nothing at all, i.e. undefined), which will make our code stops its flow at that point.

if (isBanana && isBrazilian) {
+    alert("i am a brazilian banana i love football 🍌")
+    return // sTAAAAHP!!!1
+}
+
+if (isBanana && isEcuadorian) {
+    alert("i am an ecuadorian banana do not mess with me 🍌")
+    return // DON'T GO ANY FURTHER, JAVASCRIPT!11
+}
+
+// or do, whatever
+alert("a normal banana from somewhere else")
+

Those checks could also be refactored into a variable named isBrazilianBanana. I found it too much for this example though, so this is just a friendly reminder that your conditions can always be composable.

Keep in mind that early returns might make the flow of your program confusing. Different from when you’re using else conditions, it’s not explicit that the conditionals are from the same logical group anymore.

7. Check for the same variable

Let’s get the colour of the fruits! Each fruit has one.

Hmmm
 Different cases that require different handling, but all handled cases depend on the same thing. What do we do? We conditionally check for its value and handle the case depending on that.

const getFruitColor = (fruit) => {
+    if (fruit === "banana") {
+        return "is yellow"
+    } else if (fruit === "apple") {
+        return "is red"
+    } else if (fruit === "orange") {
+        return "is orange"
+    }
+}
+
+getFruitColor("banana") // => is yellow
+

This code would benefit from early returns, and, of course, the switch statement.

Or we don’t. Because, alternatively, we can create a getter function (getFruitColor) that:

  1. inputs a key (fruit), and
  2. outputs the value that was assigned to that key in a specific map (fruitColors).

Like this:

const fruitColors = {
+    banana: 'is yellow'
+    apple: 'is red',
+    orange: 'is orange',
+}
+
+const getFruitColor = fruit => fruitColors[fruit]
+
+getFruitColor('banana') // fruitColors['banana'] => is yellow
+

Simplifying, since that map isn’t useful outside of the getter itself anyway:

const getFruitColor = fruit => ({
+    banana: 'is yellow'
+    apple: 'is red',
+    orange: 'is orange',
+}[fruit]
+
+getFruitColor('banana') // => is yellow
+

This is a very common technique I first saw on a blog post from Angus Croll in 2010. I love the simplicity of it.

Nowadays there’s even more freedom with this technique, considering features such as computed property names for objects. But don’t get too creative with that! Go for what’s more readable and expressive for you AND the people you work with.

Appendix: Currying, because verbosity isn’t expressiveness

This is an additional reading and requires familiarity with curried functions. For further reading on the currying technique, I recommend the "Currying" chapter of the book Mostly Adequate Guide to Functional Programming, or A Beginner’s Guide to Currying, as a more beginner-friendly introduction.

Let’s reconsider:

  1. the problem from the 1st, where we had an array of fruits and had to create a function that checks whether the fruit passed to it was a banana, and
  2. the all util from the 4th pattern.

Check for all conditions, revisited

Imagine if we had a lot of conditions for isBanana. We could use && or even all.

const isBanana = (fruit) =>
+    isBanana(fruit) &&
+    isSweet(fruit) &&
+    isEcuadorian(fruit) &&
+    isBrazilian(fruit)
+// or
+const isBanana = (fruit) =>
+    all([
+        isYellow(fruit),
+        isSweet(fruit),
+        isEcuadorian(fruit),
+        isBrazilian(fruit),
+    ])
+

It’s meaningful, easy to read, but introduces too much verbosity. The currying technique could help us introduce more meaning without being verbose. With some changes in the all util, that could be boiled down to:

const isBanana = all([isSweet, isYellow, isEcuadorian, isBrazilian])
+// no explicit fruit here, and still works!
+const bananas = fruits.filter(isBanana)
+

Notice we’re not explicitly passing fruit anymore. How do we do that? By making all a curried function. There are some ways to achieve that, here’s one:

const all = (conditions) => (currentItem) =>
+    conditions.map((condition) => condition(currentItem)).every(Boolean)
+

It takes the array of conditions and returns a function that takes the current item and calls each condition with that (as argument!). At the end, we check whether they all evaluated to true. It’s not magic, it’s CURRYING!!!112

That’s, of course, a simplistic implementation, which has costed me an array (from map). What’s important to get is how we play with function arguments under the hood to achieve currying.

You can curry your functions using Ramda’s curry (or Lodash’s, whatever); or, if you’re interested on that as an util, Ramda’s all and its source are really worth-checking!

Final considerations

By striving for conditionals as expressions other than statements, you write code in a functional approach. Code with a clearer sense of what it’s being checked without having to unearth to its foundations. Code that’s easier and faster for people to reason about.

But if your code is fine with an if rather than an object lookup or a ternary operator, just stick to it.

It’d break the whole purpose of this post if those patterns were used for looking smart. However, if refactoring your conditionals with them would lead to a more expressive codebase, go for it! Play with the patterns, compound them. Use your creativity to communicate well.

It’s a language, after all.

1

A programming paradigm first introduced by Donald Knuth, with the goal of providing an alternative, human, perspective on the programmer’s motivation. Read the article.

2

It may seem more magic than currying sometimes. JavaScript isn’t a purely functional language, so such techniques aren’t as popular as they are in Haskell community, for instance. Simplicity conflicts with easiness here.

\ No newline at end of file diff --git a/blog/extra/index.html b/blog/extra/index.html new file mode 100644 index 0000000..d9582f6 --- /dev/null +++ b/blog/extra/index.html @@ -0,0 +1 @@ +Extra | Diéssica Gurskas
diessi.caBlog
\ No newline at end of file diff --git a/blog/fetch-npm-package-without-npm-install/index.html b/blog/fetch-npm-package-without-npm-install/index.html new file mode 100644 index 0000000..7d917ed --- /dev/null +++ b/blog/fetch-npm-package-without-npm-install/index.html @@ -0,0 +1,8 @@ +Fetch a npm package on GitHub without npm install | Diéssica Gurskas
diessi.caBlog
August 25, 2024

Fetch a npm package on GitHub without npm install

The other day, a npm package was released broken to a private GitHub registry and it wouldn’t install:

> npm install @company/my-package
+This error happened while installing the dependencies of @company/my-package@0.0.34
+
+another-package is not in the npm registry, or you have no permission to fetch it.
+

The error message is clear: the released package @company/my-package I’m trying to install depends on a package another-package expected to exist in the npm registry somewhere. But another-package is not there. I already knew those packages came from a monorepo, so likely another-package was only an internal dependency in the monorepo, left unreleased. I wanted to inspect the package contents before releasing any fix to be sure, but couldn’t rely on npm install for that. There used to be an option to download npm packages via GitHub UI, but that’s no longer the case.

Finding the package tarball

One can read the package’s metadata to find a download URL for the package’s latest version. Here’s how:

  1. (For private GitHub registries) Grab a classic GitHub token with packages:read permissions (hereafter {GITHUB_TOKEN}).

  2. The URL of a npm package published to GitHub is https://npm.pkg.github.com/{PACKAGE_NAME}. Use that to fetch the package metadata, which contains the package tarball URL.

> curl -L -H "Authorization: Bearer {GITHUB_TOKEN}" "https://npm.pkg.github.com/@company%2Fmy-package" |  grep -o '"tarball":"[^"]*"'
+"tarball":"https://npm.pkg.github.com/download/@company/my-package/0.0.34/3d0304f38791214b09ec92a2262ca1697f"
+
  1. Download the package using the tarball URL.
> curl -L -H "Authorization: Bearer {GITHUB_TOKEN}" "https://npm.pkg.github.com/download/@company/my-package/0.0.34/3d0304f38791214b09ec92a2262ca1697f" | tar zx
+

That will download the package to your current folder, and you may inspect the package contents now. :-)

\ No newline at end of file diff --git a/blog/guitar-rig-macos-mojave-setup/index.html b/blog/guitar-rig-macos-mojave-setup/index.html new file mode 100644 index 0000000..b6427dd --- /dev/null +++ b/blog/guitar-rig-macos-mojave-setup/index.html @@ -0,0 +1,4 @@ +Setup for Audio Interface with Guitar Rig 5 on macOS Mojave | Diéssica Gurskas
diessi.caBlog
August 18, 2019

Setup for Audio Interface with Guitar Rig 5 on macOS Mojave

Setting up Guitar Rig 5 on macOS Mojave seems not to be straightforward.

Although I had gotten the signals to be sent from my guitar to the audio interface and from the interface to Guitar Rig, somehow it’d still not work. Instead of using my audio interface as the input and output device on Guitar Rig, I had to set up an “aggregate device”.

This how you can do it too.

(My specs, just so you know:)

macOS Mojave Version 10.10.14
+Guitar Rig Pro 5.2.2
+Audio Interface Steinberg UR22mkII
+

Audio MIDI setup

  1. Open “Audio MIDI setup” in your Mac. (It’s a tiny secret sound manager shipped along with the system, you’ll find it.)

  2. At the very bottom of the app, there is a small + (“plus”) button wherein you should select “Create an aggregate device”.

  3. Set up your “aggregate device” with your 1) audio inteface and 2) speakers/headphones/whatever – which should be all shown up there, given the setup is correct. Remember to give your device a remarkable name – I suggest FUCK COMPUTERS AND AUDIO.

Audio MIDI Setup app open showing audio device with both devices'
My custom device in Audio MIDI Setup on macOS.
  1. Go back to Guitar Rig. In the context menu “File”, go to “Audio and MIDI Settings”. In the “Audio” tab, select your aggregate device as the device, instead of only the audio interface as you were doing before; then configure input/output as expected in the “Routing” tab.

Should work! If it doesn’t, this guide by Native Instruments on how to troubleshoot audio and others guides on the website might help. Depending on your audio interface, make sure the right driver setup is in place – you can try out ASIO4ALL.

Guitar Rig app showing its custom amps

If it still doesn’t work, I am sorry and prolly have no idea. Have fun.

\ No newline at end of file diff --git a/blog/horizontal-and-vertical-align-anything-with-css/index.html b/blog/horizontal-and-vertical-align-anything-with-css/index.html new file mode 100644 index 0000000..f908743 --- /dev/null +++ b/blog/horizontal-and-vertical-align-anything-with-css/index.html @@ -0,0 +1,17 @@ +Horizontal and Vertical Align Anything with CSS | Diéssica Gurskas
diessi.caBlog
November 06, 2016

Horizontal and Vertical Align Anything with CSS

Using translate() is one of the easiest ways^[Flexbox also provides a great solution. See Solved by Flexbox: Vertical Centering] to instantly horizontal and vertical align any element with CSS without knowing its dimensions.

Vertical Align

You probably know the “vertical align with just 3 lines of CSS” trick, which uses translateY().

.my-element {
+  position: absolute;
+  top: 50%;
+  transform: translateY(-50%);
+}
+

Horizontal Align

But did you know it’s also possible to use translate() to horizontal align elements?

.my-element {
+  position: absolute;
+  left: 50%;
+  transform: translateX(-50%);
+}
+

Vertical and Horizontal Align

​ Mixing both, we can horizontal and vertical align anything!

.my-element {
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  transform: translateX(-50%) translateY(-50%);
+}
+

See JSBin.

\ No newline at end of file diff --git a/blog/how-i-lock-my-bike-in-berlin/index.html b/blog/how-i-lock-my-bike-in-berlin/index.html new file mode 100644 index 0000000..2503185 --- /dev/null +++ b/blog/how-i-lock-my-bike-in-berlin/index.html @@ -0,0 +1 @@ +How I Lock My Bike in Berlin | Diéssica Gurskas
diessi.caBlog
August 30, 2018

How I Lock My Bike in Berlin

1 year with a bike in Berlin, and counting...

I bought a bike 2 months after moving to Berlin, and a really good lock 1 day after.

With no clue about the theft scene in Europe – Berlin, in special –, I did myself some research on /r/berlin, /r/bycicling and a few other places around the internet. What I did find out? Well, the numbers on bike theft are quite concerning.

Nevertheless, after witnessing some people getting their bikes stolen, I feel privileged to say that it’s been more than 1 year I’ve got my bike. If that is because of my good lock or my good luck, I’ll never know.

But I can tell you about the lock.

My lock setup

I generally agree that you should invest as much as you can afford in your lock setup. I’ve put a considerable amount of money on mine because I deeply care – in other words, I have no psychological resilience when it comes to bicycles so losing mine would definitely get me in tears.

If you care about numbers without any trustable source, I've seen recommended somewhere that you should be investing between 10%-20% of the bike price in a lock. đŸ€·

Therefore, considering the price of having to go home by feet and with tears in my eyes, I did the best I could and went for the Kryptonite Evolution Mini-7 with Double Loop Cable (highly recommend you to check their website for more information).

I make sure my bike’s frame and both wheels are locked to a fixed rack – cemented into the ground, ideally.

Yellow bike in a parking space locked with a U-lock and a flexible steel cable.
My tiny yellow bike parked and properly locked at the office's parking space! Locking up the U-lock to the front wheel instead is a good alternative. Also, I often wrap the steel cable through the rack.

I had considered the Kryptnonite's New York Fahgettaboutdit, but I found it way too heavy and the safety factor difference didn't pay off for me at that time. I'd recommend it if an extra weight is no problem for you though.

For I still have my bike after 1 year, I am honestly happy with my choice. The lock came with:

  • Three keys with an unique number. For your information, Kryptonite has a system where every key gets a number, so you can order replacements online in case you mess up.
  • A handy mount made by Kryptonite: Transit FlexFrame U-Bracket (not visible in the photo because it’s in the top tube), so I don’t have to carry the U-lock in my backpack or whatever.
  • Manuals that I didn’t read and got recycled.
  • 1 year coverage according to the Kryptonte’s Anti-theft Program, because the security rating is high enough.

I’ve read a couple complaints about the lock not fitting both the wheel and frame to most city racks, however I’ve managed to do it in most racks around Berlin. It’s definitely not the most flexible and spacious lock, but thieves would love some extra space to do their work too, so I think it’s just the size it should be after all.

In the worst-case scenario, there is always the Sheldon Method lock strategy – or its modified version – anyway!

What bike locks are about

When looking for a lock, instead of (only) asking yourself what’s the best lock ever, ask “How much trouble am I putting a thief into with my lock strategy?”.

It hasn’t been enough stressed that locks do NOT prevent determined thieves with their lock pics, cable cutters, bolt cutters and angle grinders to steal you bike. Period.

Locks do, though, make it harder for thieves to pick your bike, by increasing the “risk” factor in the risk/reward calculation done before they attempt to steal.

It’s all about making it harder. And how do you do that? By having a diverse lock setup, and, just as important: by being extremely careful on where and how to park.

Don’t think just U-lock: saddle locks, wheel locks might be worth-checking too! One awesome lock is just one at the end of the day, and the more tools the thief needs to carry out, the better.

Looking further

Some articles I’ve read last year and that might be interesting if you own a bike and want to learn more on how to keep it safe.

There are a lot of cool videos out on YouTube too, e.g. “How to Lock your Bike” from GCN.

Have a nice ride! đŸšČ

\ No newline at end of file diff --git a/blog/how-to-exclude-css-images-anything-from-unit-tests/index.html b/blog/how-to-exclude-css-images-anything-from-unit-tests/index.html new file mode 100644 index 0000000..354eca9 --- /dev/null +++ b/blog/how-to-exclude-css-images-anything-from-unit-tests/index.html @@ -0,0 +1,27 @@ +How to Exclude CSS, Images, Anything from Unit Tests | Diéssica Gurskas
diessi.caBlog
November 19, 2016

How to Exclude CSS, Images, Anything from Unit Tests

Your app needs all those require, but your unit tests may not.

When developing web applications, we deal with assets that our JavaScript tests don’t have to be aware of.

If using Webpack, which enables different imports in your JavaScript files, you’ve configured loaders that your test runner probably know nothing about. Therefore, that SVG image in your React component and the imported CSS will both be parsed like JavaScript in your tests. A lot of confusing errors will be thrown, of course.

So let’s learn to exclude anything your unit tests, from styles (CSS, Sass), images (PNG, SVG), to other specific imports (like SVG images as React components).

Hook your require() calls

By intercepting require() calls, you can make your testing framework ignore what you want to be ignored the way you want it to be ignored.

It’s also useful in isomorphic setups.

Return an empty module

It all comes to returning an empty module for unwanted imports. It looks like this:

module.exports = "";
+

Jest

For Jest, configure moduleNameMapper to return the empty module for specific extensions. Example:

"jest": {
+  "moduleNameMapper": {
+    "\\.(css|jpg|png)$": "<rootDir>/empty-module.js"
+  }
+}
+

Other testing frameworks

require-hacker is an option for hooking require() calls.

You can also use built-in compilers (like moduleNameMapper in Jest or Mocha compilers), or even only import ignore-styles into your testing framework (which is preconfigured).

I’ll stick to require-hacker and custom configuration because there’s more flexibility.

Get it from npm:

npm install require-hacker --save-dev
+

Configure

Create a JavaScript file and set custom handlers for specific extensions using require-hacker’s hook() method.

Assuming you want to ignore CSS and PNG files, always return an empty module for them:

import requireHacker from "require-hacker";
+requireHacker.hook("png", () => 'module.exports = ""');
+requireHacker.hook("css", () => 'module.exports = ""');
+

Because you’re smart, you’ll store all extensions in a variable and forEach them, so there’s no need to repeat yourself. Example.

Import into your test runner

Let your favourite testing framework know about the require hacking! Some examples, assuming a ignore-utils.js file:

Mocha

Add to your mocha.opts, or use the --require flag:

mocha --require ./ignore-utils
+
ava

Add to your package.json:

"ava": {
+  "require": [
+    "./ignore-utils"
+  ]
+}
+

Now some files will be treated like shit in your JavaScript tests – which is AWESOME!

Bonus: React null component

You don’t need to load that boring SVG icon of a house to test that critical feature in a React component, right?

Right. In case you’re using svg-inline-loader, which transform your SVG files into React components, you cannot just return an empty module because your test case would be actually expecting a React component. Things will break. Annoying errors will be shown.

So, instead of returning an empty module for SVG files, return an empty React component. Let’s set a custom handler for that!

Configure

This example uses require-hacker. For Jest, export a React null component and set it in moduleNameMapper.

import requireHacker from "require-hacker";
+
+const reactNullComponent = `
+  require('react').createClass({
+    render() {
+      return null;
+    }
+  })
+`;
+requireHacker.hook("svg", () => `module.exports = ${reactNullComponent}`);
+

Conclusion

I’ve spent a lot of time figuring out how to make everything work, because:

  1. At the beginning, it was quite confusing to get what was clearly going on.
  2. There’s a ton of options out there (Webpack null loaders; ignore-styles, which also provide custom handlers; babel-plugin-transform-require-ignore
).
  3. I didn’t want to handle all the ignored extensions the same say.

Yeah
 Sometimes our JavaScript unit tests just know too much.

\ No newline at end of file diff --git a/blog/how-to-spy-on-a-prop-with-jest/index.html b/blog/how-to-spy-on-a-prop-with-jest/index.html new file mode 100644 index 0000000..dd25c83 --- /dev/null +++ b/blog/how-to-spy-on-a-prop-with-jest/index.html @@ -0,0 +1,17 @@ +How to Spy on a React Prop with Jest | Diéssica Gurskas
diessi.caBlog
October 31, 2019

How to Spy on a React Prop with Jest

When we want to test whether a prop has been called, mocking the prop in the component is usually the preferred way. This is how it goes with Jest and Enzyme:

const buy = jest.fn();
+const wrapper = enzyme.shallow(<button onClick={buy}>Buy</button>);
+
+wrapper.simulate("click");
+
+expect(buy).toBeCalled();
+

You may also want to spy on the prop directly, when the component is tested along with a provider passing down its props.

const wrapper = enzyme.shallow(
+  <ClickProvider>
+    <button>Buy</button>
+  </ClickProvider>
+);
+const buy = jest.spyOn(wrapper.instance().props, "onClick");
+
+wrapper.simulate("click");
+
+expect(buy).toBeCalled();
+

I am using Enzyme however you should be able to spy on similarly using other testing libraries – just make sure you are spying on a function in the props coming from the component prototype (as in wrapper.instance()).

That’s all. Just posting it here cuz I couldn’t find it easily anywhere else.

\ No newline at end of file diff --git a/blog/i-m-tired-of-beautiful-looking-interfaces/index.html b/blog/i-m-tired-of-beautiful-looking-interfaces/index.html new file mode 100644 index 0000000..60dc413 --- /dev/null +++ b/blog/i-m-tired-of-beautiful-looking-interfaces/index.html @@ -0,0 +1 @@ +I'm Tired of Beautiful-Looking User Interfaces | Diéssica Gurskas
diessi.caBlog
October 23, 2016

I'm Tired of Beautiful-Looking User Interfaces

What if the user interface is more beautiful-looking than usable, understandable, and intuitive?

The visual aspects of an user interface play an essential role in organising information. Once you’ve got the resources, however, that turns out to be the easiest part of an Interface Design process.

Sure we like things that look nice, but looking nice doesn’t compensate a bad product design. Visual communication should not compensate flaws.

If you spend most of the time looking for visual inspiration rather than conducting research, doing usability tests, and studying metrics such as business goals and conversion rates, you will probably come up with a interface that only looks beautiful.

And I’m tired of beautiful-looking interfaces.

\ No newline at end of file diff --git a/blog/index.html b/blog/index.html new file mode 100644 index 0000000..1c1712f --- /dev/null +++ b/blog/index.html @@ -0,0 +1 @@ +Blog | Diéssica Gurskas
diessi.caBlog
\ No newline at end of file diff --git a/blog/isolation-tank/index.html b/blog/isolation-tank/index.html new file mode 100644 index 0000000..58cdc8e --- /dev/null +++ b/blog/isolation-tank/index.html @@ -0,0 +1 @@ +I've Sensory-Deprived Myself In a Tank | Diéssica Gurskas
diessi.caBlog
December 02, 2018

I've Sensory-Deprived Myself In a Tank

I struggle every day trying not to be one step ahead. Living everywhere else but the present and leaping through time have become part of how my brain is wired, so I often find myself not experiencing much anymore.

A while ago, a friend told me about his sensory-deprivation experience in some kind of pool, the so-called Isolation Tank. No sight, no hearing, no touch, no taste, no smell – the idea of getting absolutely no input from anywhere struck me as a way to get my perception back on track. I decided to try it out.

On a sunny Saturday of November, I, along with my endless stream of thoughts, floated for 1 hour straight in a soundproof egg-shaped tub shallowly filled up with salt water. This is my report.

Getting In

With my bathing suit on and no expectations of anything, I showered, got into the tub and sealed down its cover. My body floated easily on that water that thermically felt like my own skin, and a relaxing sound was playing in the background up to the moment my surroundings got all pitch-black.

The first 15 minutes were all about withstanding how restlessly my mind wanted to get out of there. I’ve had done meditation before, but 1 hour was something else. I recalled I worked 8 hours a day, 5 days a week, and therefore I should be making the most out of my Saturday instead. Leisure time! In modern life, that usually means stimulation by means of binge-drinking with friends, uplifting music, delicious food, watching heart-breaking movies
. Quite the opposite of soul-crushingly doing nothing.

The mind just plays a lot of games on you all the time. It tricked me into being physically irritated by the water, its salt, that bogus zero-gravity environment, and that I’d be better off giving up for my own survival  – at least, that was how my body anxiously (over-)reacted to it. But there was actually no physiological danger or whatsoever; truth be told, I was way safer than I had ever been throughout that week. I quit panicking.

I came upon different phases of denial, approval and mind-numbness from that onwards. Saw myself bringing up problems and drifting them away. Tried to work out situations I had no control over. Missed music, so made my own by tapping on the water. Went hyper-focused on how I had performed socially last week to what was going to happen in the next few weeks when I eventually hand over my old apartment’s keys to that spiteful Hausmeister who hates my German.

My thoughts just went on super randomly. After a while, I could draw the exact line where each one ended, and got mindful about my weary physical overreactions to them.

Towards the end, I sank into something else: weightlessness, timelessness, solitude were emerging from that isolation. Things started losing shape. Didn’t perceive water. I was either a floating head or a floating body. I had to touch my thighs, boobs, neck just to relieve myself from the uncertainty that being so relaxed made me feel about where I was.

I wanted to come back down to Earth from wherever I was, and, surprisingly, to be myself – the way I was. Then time was up.

Getting Out

I showered again to wash the salt off. The spa provided a relaxation lounge that was essential to ease the transition, since I had neither desire nor need (important!) to rush anywhere. Hung out there for 1 hour.

The readjusting was an interesting and unexpected phase to me. Had an apple and felt how crispy in sound and taste it was. Drank a glass of water and sensed it going right down through. Read a book and couldn’t make sense of why we humans have ever brought up speed reading techniques in the first place.

Stepping out of the spa, I got savagely welcomed by a gloomy afternoon1 undergoing that life I was used to every day. A lot was happening out there: lights of apartments being turned on and out, cars groaning, people running around, traffic noise, the cozy energy of having my friend by my side, sharper textures of the sidewalks’ cobblestones, and the joy of a having a sky whose amount of stars doesn’t depend on the many times we screw up as human beings, thankfully.

Berlin-Schöneberg is quite chill so that’s helped to readjust. I was sensible and my thoughts were vivid and receptive – pretty much the actual poetic mood I strive for, where I settle and listen to what’s being said in order to write it down. A mood that is “highly disturbed by Philosophy”, as Goethe brilliantly summed up to Schiller once:

“I am still hoping for poetic hours, and philosophy, in my case, disturbs the poetic mood, probably because it drives me into the object, for I am never able to keep myself in a purely speculative mood, but have immediately to try and form a distinct conception, and on this account at once fly out into nature. [
]2

I had finally my mind drifted towards just as much of the world as it was going on.

Lessons Learned

My poetic mood didn’t last much – it wore off the day after.

I’ve realized how much we are externally stimulated and easily adapt to it as if it were natural. On top of that, we are internally stimulated by our worries and whatnot: have I paid my taxes? Am I persuading a career? Does my family still love even though I am thousands of kilometers from them? Have I been eating healthy enough?

It turns out it’s clear why we don’t feel much anymore. Our brain gets wired to parallelising stimuli, and we have less and less coming from our body to the head than the other way around. Apart from that, our experience of the world is barely passive: we actively generate it with our biases, mental models, what and how much we consume. Mind shortcuts are crucial, but might restrain us from genuinely experiencing life, getting us to either ignore ou hyper-focus unconsciously.

I, now, have a better grasp of what Erling Kagge meant in Silence: In the Age of Noise, written after he had spent fifty days walking solo in Antarctica: “Everything seemed completely flat and white. [
] Eventually, in complete isolation, I began to notice that nothing was completely flat after all. The ice and snow formed small and large abstract shapes. The uniform whiteness was transformed into countless shades of white. [
]”

Meditation is the absolute protagonist here, but floating got me into a different flow, and faster. The topic of sensory deprivation is definitely worth-exploring. Think like: If you ditch sugar for a while, it tastes sweeter afterwards. ;-)

This is pretty much what floating offers: sensory starvation and you on your own. You may waste your time and never get to anything, or make even most out of that 1 hour than me.

Personally, I can’t wait to do nothing again.


1

Just another Autumn day in Berlin.

2

Goethe (and Friedrich Schiller). Correspondence Between Schiller and Goethe from 1794 to 1805. Translated by George H. Calvert.

\ No newline at end of file diff --git a/blog/journaling/index.html b/blog/journaling/index.html new file mode 100644 index 0000000..20c5b04 --- /dev/null +++ b/blog/journaling/index.html @@ -0,0 +1 @@ +What I've Learned by Simply Journaling | Diéssica Gurskas
diessi.caBlog
April 20, 2020

What I've Learned by Simply Journaling

In 2018, circumstances inevitably changed and I began taking up much more in life. I was under stress, regardless of being on the safe side, and the patterns that kept me grounded were no longer holding up.

Back then, seeing the big picture was unattainable with the stress snowballing and skewing my perspective. Dwelling in my head, paving the way to learned helplessness, I decided to try out journaling.

More than a year later, I can finally say alles gut. Although circumstances haven’t changed much, I certainly handle them better. I keep journaling as of today, and am excited to share my setup and (hopefully) motivating takeaways!

How I Journal

I did not go for the traditional diary format. I decided to Bullet Journal, a flexible journal method founded in quick lifelogging by means of a pen, paper, and bullet points.

Pen and paper pull me out of my head and let me continuously evolve my notebook as my needs change, since there is no predefined template. As for bullet points, we all know their efficacy: hasty logging and later reviewing at a glimpse.

Method

Peek into Bullet Journal official page for an overview, as I won't dive into the framework basics.

The Bullet Journal framework is made out of four fundamental “collections”: Index, Daily Log, Monthly Log, and Future Log, plus custom collections you find valuable. After a while of tinkering around, I came to some insights and tweaks.

  • Index turned out useful when I added custom collections, as those usually end up scattered across the journal and thus hard to find.

  • Daily Logs is where I keep track of notes, events, tasks, thoughts, and ideas. (All mixed together, which portrays a day accurately if you ask me.) I recommend using signifiers and nesting (for a tree-like view) in bullet points to convey meaning with ease, as Bullet Journal suggests.

  • Monthly Log didn’t work for me. I steer towards weekly or quarterly ranges. Also, my online calendar is more practical so I couldn’t bother drawing calendars every month.

  • Future Logs are useful to migrate tasks or events to upcoming months, for when you don’t get something done but can’t “nevermind” it either.

As for custom collections, the Bullet Journal ecosystem is huge! I’ve seen stuff of all kinds out there: finance/sleep/food/water trackers, recipes, trip planning, doodles, and whatnot. Yet, these are the ones I always come back to:

  • Diaries: longer diary entries or brain dumps without the limitation of bullet points, for when I feel like it.
  • Habit Trackers: a simple daily tracker to monitor or develop habits across weeks, e.g. meditation, alcohol intake, call family.
  • Weekly Logs: my weekly variation of “Monthly Log”, with upcoming events and small goals for the week. Usually done on Sunday or Monday.
  • Quarterly Logs: my quarterly variation of “Monthly Log”, with upcoming events and big goals for the quarter.
  • Year Retrospective: a straightforward year review regarding what did and did not go well, what to keep or let go from last year etc. I journal spontaneously throughout the day, but mostly in mornings or evenings. I do it every day, even when I don’t feel like it. In the long run, that’s gotten me to fathom my anxieties by having them logged as well as what was up days before. It goes a long way to flip through logs of piled up chores, social isolation, binge drinking, and sleep deprivation, to later find yourself taking down “I am anxious. Can’t do shit”.

Be that as it may, I don’t keep it all gloomy. With my throughput in mind, I may also soften up my daily logs with receipts from exquisite restaurants I come across, cute post-its from friends, or even silly useless quotes from fortune cookies.

At last, I have to say I’m not really a big planner so you can see that’s not what I optimise my journal for. All I strive for is a little awareness of whatever I’m doing for the time being. I enjoy a spontaneous and organic life, and that’s gotten me far enough to make me happy.

Pen & Paper

Notebooks on desk. On the left: Camel brown notebook with bear symbol on cover. On the right: Forest green notebook with deer symbol on cover.
My 2019 journal (left) and 2020 journal (right).

In 2019, I used an A5+ (slightly wider than regular A5) dot-grid notebook. It’s bulky to carry around but I don’t regret it: the pages are wide enough to encourage writing. The quality of its pleasing yellow paper is outstanding, thick enough to prevent ink from leaking through. I ended 2019 with a few pages empty.

This year, I went for something more portable: an A6 dot-grid notebook. It took me a while to get used to the size constraints, and I’ve been certainly more straightforward with my logs. I am pretty sure I will have no pages left this time. (Wondering what was the advantage of it all as I’m not going anywhere anyway thanks to COVID-19.)

As for pens, I use different colours of a 0.4 mm fineliner.

What I’ve Learned

I'd not assume these stem necessarily from the way I set myself up. Audio or video recordings, traditional diary, and other journal formats are worth exploring and might help just as well.

  • Less overwhelm, more time. To truly chill out when life gets overwhelming, you gotta plan ahead. Especially in already busy weeks, I use my journal to put down chores I commit to get done, prioritising what I signify as deadline-sensitive. Before, with my tendency to overfocus, I’d take up activities without planning and end up neglecting my responsibilities and needs. Imagine how far this can go!

  • Emotional awareness. I’ve gained a grasp of the phenomenology of my emotions and the lens through which I see life, markedly my cognitive distortions on stressful days. Attitudes like pessimism inevitably surface as you jot down negative thoughts all the time. Being mindful allowed me to reframe negative views, and turn obstacles into opportunities.

  • Better retainment. It’s easy to fall into the trap of “I have a bad memory” when one has been busy and mooning for so long. Leading a busy life mindlessly is not what I strive for, and journaling only feeds into that: I hold dear people, moments, promises, and no longer miss so many appointments (planning helped here too!).

  • Constant assessment. Journaling is a tool to assess the present as well as the past and the future. By peeping into where I’ve been, what did/didn’t go well, or who I have been with, for instance, I can ponder more sensibly on my growth and relationships. Early feedback on my own life, sort of, to leverage self-improvement in relationships, health, work, and so on.

Pitfalls

  • Perfectionism. Obsession over constant logging or perfection is right at the door for you to slip into. On social media (Pinterest, YouTube), everyone’s journal seems visually-appealing every day without fail. Even Bullet Journal, a method dead straightforward, can be a rabbit hole. Remind yourself to solve your problem in a way that enhances your daily life, not burdens it. You gain absolutely nothing from buying into slices of life people sell online.

  • Habit-building. When not a habit, journaling is just another chore. Make it effortless and engaging: establish a routine (if that’s your thing), designate it a place where it’s always within reach, or tailor the framework to your needs. If you enjoy drawing once in a while, why not? If you have no patience for 29872 different pen colours, why do it? If you want to write about your day with your partner in bullet points instead of coming up with a best-seller love story, who cares?

  • Procrastination. Journaling constantly nudges you to look back at your life and how you’ve been spending your time and energy. That can be challenging and won’t change. For starters, you might come to the unpleasant realisation that you self-sabotage, or that a certain relationship is fading away. If you are avoidant, you will most likely put off journaling often; not because of the method or routine, but fear of what you may find – fertile soil for procrastination.

  • For pen & paper
 No backup. Some companies have tried, but what’s hand-written won’t sync with a cloud server. You do carry the weight if traveling or taking it to work, and it’s probably gone if you spill coffee on it. I, though, think the trade-off is worth it and haven’t looked back.

Final Takeaway đŸ„Ą

I am all for simplicity, yet that didn’t keep my mind from boggling when I realised such a simple tool turned out to be a game-changer. Starting off was not easy, but the benefits showed up and kept me motivated – a rewarding feeling I wouldn’t expect so hastily while building a new habit. Today, it’s just effortless and natural.

Ultimately, I hope this stimulates you to try journaling in whatever way and to deem simple tools as helpful to uncomplicate and improve our lives.

References

\ No newline at end of file diff --git a/blog/long-time-no-see/index.html b/blog/long-time-no-see/index.html new file mode 100644 index 0000000..61bf3c9 --- /dev/null +++ b/blog/long-time-no-see/index.html @@ -0,0 +1 @@ +Long Time No See | Diéssica Gurskas
diessi.caBlog
June 30, 2023

Long Time No See

In the past three years, a wild mix of stuff dragged me away from writing. More time 🌳 offline ⛰, which was great. Then a demanding role in a small team, the chaotic grip of a global pandemic, increasing perfectionism, and a blossoming and ultimately collapsing relationship – which all conspired to shake up my pursuits and thrust me into an introspective whirlwind. And as if that wasn’t difficult enough, I lost two years’ worth of drafts in a backup blunder.

Whenever I attempted to restart, I found myself entangled in a web of what still resonated with me and what no longer did. But hey, listing more excuses would only scratch the surface. I recognize now, after seeing how little it takes for me to be back, that parts of me were simply in disarray. Yet, as I come together again, so does my motivation to reclaim what I enjoy, and make time for it despite the busyness and excuses.

So, last night, I did what I do best: I embarked on an in-one-sitting endeavor! I migrated this blog to Zola (a speedy static generator written in Rust), so this WeBpAg3 remains therefore static and snappy af, joining the <512 kB club. Letting my creativity flow with Tailwind, I gave my WeBpAg3 an extravagant-outrageous look, and made sure it’s accessible. I rewrote my introduction like a million times. I sifted through my writings, organising and archiving some, and lo and behold!: I stumbled upon those lost drafts hidden away in the depths of my physical backups. Pretty thrilling. As a friend once told me, good things happen when good things happen.

Long time no see! It all feels quite nice, if you ask me. 😉

\ No newline at end of file diff --git a/blog/mass-deleting-files-from-slack/index.html b/blog/mass-deleting-files-from-slack/index.html new file mode 100644 index 0000000..72bbb4d --- /dev/null +++ b/blog/mass-deleting-files-from-slack/index.html @@ -0,0 +1,4 @@ +Mass Deleting Files from Slack | Diéssica Gurskas
diessi.caBlog
April 17, 2016

Mass Deleting Files from Slack

Slack comes with limited file storage, so you eventually run out of space. Deleting files isn’t easy though: there is no way to bulk delete them using the web interface.

Slack forces you to delete one by one.

And although Slack can force humans, it can’t force JavaScript. So JavaScript to the rescue!

How to delete multiple files from Slack

In order to free up space, you’ll need;

Installing

Open your terminal and install slack-delete-files package globally using Node Package Manager:

$ npm install -g slack-delete-files
+

Running

$ slack-delete-files
+

You’ll be asked for your Slack token and whether you want to delete all files or only files older than 30 days.

Done!

Your space is probably back!

After deleting, you can uninstall the package:

$ npm uninstall -g slack-delete-files
+

Contribute on GitHub.

\ No newline at end of file diff --git a/blog/multiline-sass-comments/index.html b/blog/multiline-sass-comments/index.html new file mode 100644 index 0000000..039c5e7 --- /dev/null +++ b/blog/multiline-sass-comments/index.html @@ -0,0 +1,4 @@ +Multiline Sass Comments | Diéssica Gurskas
diessi.caBlog
August 17, 2015

Multiline Sass Comments

Since the beginning of this year, I’ve created a lot of different boilerplates for projects. Working as a freelancer makes you challenge yourself everyday to find out what fits better while working. Currently, it’s sometimes Stylus, sometimes Sass.

Stylus is flexible, and I love it. Sass isn’t, but it’s cool anyway. Sometimes I find it hard to bear its inflexibility, though.

On GitHub, there’s a closed issue about multiline comments on Sass (a Stylus feature!), where I shared a solution for multiline Sass comments. A lot of people still don’t agree.

I just want people on community to know it, because it needs to be discussed.

Solution

Start writing the comment as if it were single-line (//), then just follow its indentation. Example.

// Multine comment
+   Indent the text
+   And this will be a comment too
+

Is it available on Sass docs? Let me know!

\ No newline at end of file diff --git a/blog/my-hacking-adventure-in-lithuania/index.html b/blog/my-hacking-adventure-in-lithuania/index.html new file mode 100644 index 0000000..c9d58cf --- /dev/null +++ b/blog/my-hacking-adventure-in-lithuania/index.html @@ -0,0 +1 @@ +My Hacking Adventure in Lithuania | Diéssica Gurskas
diessi.caBlog
February 15, 2018

My Hacking Adventure in Lithuania

Exploring the country where my surname came from and hacking collaboratively at Science Hack Day Vilnius!

I love to hack stuff, and, this year, I’ve been pushing myself to do more of that along with people.

That’s how I found a hackathon called Science Hack Day, a weekend event with the goal of “making weird, silly or serious things with science”1 in collaboration with others. Although I missed the Berlin edition for just a few days after it happened in November, another event was about to come – this time, in Lithuania, where my surname “Gurskas” came from.

There it was the perfect replacement: the Science Hack Day Vilnius 2018 would be my great excuse to explore the country where my grandfather was born.

Right on the last minute, I got a bedroom in a cheap hotel booked, and my flight and event tickets ready. All set for the hacking adventure!

Welcome to Vilnius

Approximately 2 hours from Berlin by plane, there I was: Vilnius, the capital of Lithuania. A modest city, so small you can pretty much explore everything by feet.

Temperatures were more negative than in Berlin. Winter, and the city wasn’t the most colourful either, so the atmosphere was somewhat dark – even though the snow was painting all buildings, houses, and streets in a shining white.

The cold was totally dismissible as soon as I met the Lithuanians, warm and welcoming people who seemed to lead a simple life.

Science Hack Day Vilnius 2018

Trophies for different prize categories
Trophies for different prize categories. (Photo: Raitis Gocentas)

A Science Hack Day is a 2-day event run by volunteers. Since it’s a hackathon, it’s pretty hectic and leaves you exhausted at the end. However, also since it’s a hackathon, it’s remarkably rewarding at the end.

These were my days!

First Day

Early on Saturday, I walked to Technarium, where the event would happen. It’s a laid-back and community-operated hackerspace in Vilnius, where technology enthusiasts work or co-work on their projects and share knowledge. My perfect habitat, sort of.

Technarium space
Technarium. (Photo: Raitis Gocentas)

I found a seat in the middle of a diverse crowd of enthusiasts: kids, teenagers, and adults (in which you could also find scientists and professors). I had forgotten to adjust my clock to the local timezone when I arrived in Lithuania – 1 hour ahead of Berlin –, so I was kinda late and the talks on open science had already started.

With honestly no idea on how all that’d end up (a feeling I’m used to, since I always do unexpected stuff to myself anyway), I was watching the talks and telling myself that the worst that could happen was that I’d have no idea and no team, and would end up just exploring what others were building. It didn’t sound any bad at all! Being around creative people is always appreciated anyway.

Electronic hackable badge and stickers from Science Hack Day Vilnius 2018
Electronic hackable badge and some stickers I got for joining the event! The badge features a WiFi-enabled micro-controller and MicroPython, for some hardware hacking fun. Check the badge's GitHub repository.

After the talks, it was time for people to pitch about their potential projects. Most ideas involved Biology, Programming, Physics, Chemistry – anything related to (science) hacking! One of the ideas, from a team of 3 guys, was to build an audio visualiser.

“We need a Python engineer who understands some audio engineering”, they said, in Lithuanian (thanks person who was real-time translating everything!). Luckily, in a beautiful coincidence, I love music, Python, and also have been playing with spectrum analysis for audio visualisation in the last year – so I decided to take a shot and ask them to join the team.

They said they had no idea how to get the input from a microphone, and that they knew more about the hardware part, Arduino, and manipulating those machines in the hackerspace to come up with a cool design for our project. I’m just bad at things that require manual work that isn’t with the keyboard, so my manual help would be typing Python for 2 days on my laptop. They accepted it. So far, we had:

  • the idea;
  • an Arduino Nano;
  • a power supply;
  • long LED strip lights;
  • an acrylic sheet.

Since Arduino Nano isn’t powerful enough for that computation, it’d be only used for data acquisition, and the spectrometer would live in our Python program in my laptop, computing the Fourier transform of the audio signals.

By the end of the day, we managed to get input from the microphone, analyse its signals in the frequency domain with Python, and start mapping that data to be sent to our Arduino over a serial interface. Some libraries we played with were: pyaudio, numpy, pyserial, matplotlib.

Second Day

Now with the clock correctly set (thanks to my friend that asked what timezone I was in, otherwise I wouldn’t ever know), I was on my way to Technarium again, walking over and under snow in that early Sunday morning.

A day in the Science Hack Day Vilnius was a day with Lithuanian hearty lunch, black coffee, and hard work around kind people. (By the way, if you ever end up there, try the kibinai – I ate one filled with spinach and will never forget how it smelled and tasted.)

Most people there were Lithuanians and I didn’t know anything about their language besides “labas vakaras”2 (“good evening”), so I felt like an outsider sometimes. My teammates and other Lithuanians in the event – including kids –, though, were friendly and spoke English flawlessly, and fortunately even translated some stuff into English for me.

Curious fact: A teenager at the event told me that my surname was "wrong" – in Lithuania, single women get a different surname suffix, so my name should be Gurskaite ("skaite" suffix, instead of –kas). In Brazil, of course, they didn’t know that and only cloned my grandfather’s surname – with the "kas" suffix, since he was a man: Gurskas.

More talks in the morning on open hardware and software. They introduced everyone to GitHub, and many people, even students, were already familiar with it. The importance given to open source was impressive! That made me really happy.

Time flew on the second day! We had got the data we needed, and the next step was to decide on what would be more fun: to map amplitudes from the maximum frequency to RGB values for all LEDs, or map each LED to a frequency and change its colour depending on the amplitude? We picked up the latter, and got our LEDs to blink.


One of my teammates was learning Programming. He told me he didn’t know what programming languages to really sit down and learn, as seen that there were a lot of them out there. True, and a nice question! I gave him a biased answer, of course: “go for Python or JavaScript”. My reasons? Way more fun. Besides beginner-friendly, those languages have the most interesting, welcoming and lively ecosystems I know these days.


We were running out of time. While 2 of my teammates were building the LED tower, the other and I were testing the code and trying to improve our algorithm, everything at the same time. Eventually, we got our LEDs to blink the way we wanted them to, and the clock pointed 18:00 sharp. Time for presenting!

Laser project presentation
Project showing how lasers work. It emitted sounds too! (Photo: Raitis Gocentas)

Teams came up with a lot of cool things! Projects related to lasers, contactless payment systems security tests, shopping-cart-rocket launch (#SpaceXLithuania!), plant-watering automation, posters with LEDs crafted by kids celebrating the 100th year of the Lithuanian as an independent country
 And ours, of course.

Presenting the LED tower to the public
Two of my teammates (one's missing!) and me. I was weirdly concentrated uttering different notes to show how LEDs reacted to frequencies. (Photo: Raitis Gocentas)

There were different category prizes, and we won as the Best Data Hack!

I got the honor to take home not just this LED-powered trophy below, but also a memorable experience I had the pleasure to share with people I didn’t know in a country I didn’t know.

A trophy for Best Data Hack 2018 and a Raspberry Pi
A trophy for the Best Data Hack 2018 and a Raspberry Pi. Our prizes for having fun!

The Hack Day ended with a science show by N2! Lots of fun with liquid nitrogen and eating cookies at temperatures close to the absolute zero. My teammates, Physics students, knew a lot of the science behind that stuff so I got some extra explanations! (I have to say, though, that one of my greatest learnings of that day was to not to chew those cookies slowly – they stick to your tongue in a TORTURING way.)

N2 science show group playing with fire
Playing with fire. Literally. (Photo: Raitis Gocentas)

It’s always truly amazing to experience closely how creative and curious humans are! The event was awesome, well-organised, and, last but not least, fun. Organisers provided us all the materials (food included!), borrowing me even the single USB-C adapter they had!

Clearly, the only intent behind Science Hack Days is for people to share and learn openly. And that has been achieved just right.

Final words

Open knowledge is one of the most valuable things in this world. I have no doubt.

I’m happy to have picked such an eccentric travel destination for my weekend, and really grateful for everything I saw and everyone I’ve met on the way.

Gurskas written in snow
I don't feel my fingertips anymore since I did that. Writing in the snow: definitely NOT encouraged!

Lithuania was freezing, yes, but people were warm.

2

Special thanks to my father, who taught me that, otherwise I wouldn’t know anything really.

\ No newline at end of file diff --git a/blog/o-css-do-futuro/index.html b/blog/o-css-do-futuro/index.html new file mode 100644 index 0000000..fcd6014 --- /dev/null +++ b/blog/o-css-do-futuro/index.html @@ -0,0 +1,2 @@ +O CSS do Futuro | Diéssica Gurskas
diessi.caBlog
May 29, 2016

O CSS do Futuro

JĂĄ existem especificaçÔes garantindo funcionalidades incrĂ­veis para o CSS: variĂĄveis; uma nova sintaxe para media queries; nesting; novos seletores, valores e propriedades. E vocĂȘ pode usĂĄ-las, hoje.

Neste artigo, introduzo uma sĂ©rie de artigos relacionados Ă s principais funcionalidades do CSS do futuro, alĂ©m da ferramenta CSSNext, que permite que vocĂȘ as utilize sem esperar o suporte do navegador.

(A fins didåticos, é possível assemelhar o CSSNext ao Babel, que, por sua vez, também permite desenvolver com o JavaScript do futuro ao transpilar o código JavaScript da próxima geração para um código suportado pelos navegadores atuais.)

Ao final desse artigo, vocĂȘ saberĂĄ como desenvolver, hoje, com o CSS do futuro.


Introdução ao PostCSS

O CSSNext estĂĄ relacionado com PostCSS. Mas o que Ă© o PostCSS, afinal?

O PostCSS Ă© apenas uma ferramenta que permite (prĂ© ou pĂłs) processar o CSS atravĂ©s de plugins em JavaScript. Um desses plugins Ă© o CSSNext – assim como, por exemplo, o Autoprefixer, que trabalha na etapa de pĂłs-processamento do CSS, adicionando vendor prefixes.

A transformação de estilos Ă© viabilizada de forma integralmente agnĂłstica: nada Ă© dito sobre como e com o que serĂĄ feito. Com o PostCSS, vocĂȘ Ă© responsĂĄvel pelo workflow de processamento do estilo. É possĂ­vel utilizar funcionalidades prĂ©-processadas e/ou sintaxe do Sass, minificar e adicionar vendor prefixes – tudo de forma “plugĂĄvel”!

Como o PostCSS nunca Ă© utilizado sozinho, o prĂłximo passo Ă© plugar o CSSNext a ele.

Como usar o CSSNext

Se vocĂȘ quiser apenas testar as funcionalidades dos novos mĂłdulos do CSS, vocĂȘ pode brincar com o CSSNext no navegador.

No workflow

Em um ambiente de desenvolvimento, Ă© necessĂĄrio usĂĄ-lo com o PostCSS. A documentação do CSSNext guia vocĂȘ para configurĂĄ-lo em seu workflow, seja com Webpack, Browserify, Gulp, Grunt, [
], ou interface de linha de comando.

Em todos os casos, a configuração se resume a passar um array com os processadores desejados para o PostCSS. Nesse caso, o processador a ser plugado é apenas o postcss-cssnext:

$ npm install postcss-cssnext --save-dev
+

Principais Funcionalidades

Aprofunde-se nas principais funcionalidades do CSS do Futuro através dos artigos abaixo. Abra o playground do CSSNext e bons estudos!

\ No newline at end of file diff --git a/blog/o-que-ha-de-errado-com-a-cultura-jquery/index.html b/blog/o-que-ha-de-errado-com-a-cultura-jquery/index.html new file mode 100644 index 0000000..9b5be0a --- /dev/null +++ b/blog/o-que-ha-de-errado-com-a-cultura-jquery/index.html @@ -0,0 +1 @@ +O Que Hå de Errado com a "Cultura jQuery" | Diéssica Gurskas
diessi.caBlog
September 20, 2015

O Que HĂĄ de Errado com a "Cultura jQuery"

Este nĂŁo Ă© um artigo sobre jQuery. Este Ă© um artigo sobre ferramentas, sim, mas Ă©, principalmente, um artigo sobre anĂĄlise e o protagonismo do desenvolvedor front-end nesse processo.

Resumo

AplicaçÔes variam. Aprenda a definir a arquitetura da sua aplicação. Aprenda a reconhecer a necessidade de uma SPA (Single Page Application).

A “cultura jQuery” te afasta de tudo isso, e, portanto, distancia vocĂȘ do seu papel enquanto desenvolvedor front-end.


Introdução

Se existe uma cultura nas agĂȘncias digitais do Brasil que Ă© unĂąnime, Ă© a cultura do jQuery. NĂŁo a cultura de utilizar todo o poder da biblioteca, no entanto, mas o hĂĄbito intrĂ­nseco de importar o jqueryX.X.X.min.js em todo projeto.

(Sim, em 2015.)

Sobre o que hĂĄ de errado, serei sucinta, pois, para esse artigo, espero um pĂșblico-alvo preguiçoso e acomodado.

O que hĂĄ de errado


em usar jQuery em 2015? O que há de errado em importar jQuery ao iniciar o meu projeto?

Analisando superficialmente, nada.

Mas isso tem dado brecha a uma zona de conforto profunda e, na minha experiĂȘncia, com raĂ­zes difĂ­ceis de arrancar. Essa cultura se expande e transcende aquilo que lhe deu origem. Portanto, perceba:

Este nĂŁo Ă© um artigo sobre jQuery.

A comunidade de AngularJS é um exemplo de que isso não é sobre jQuery. Muitos migraram dele ao Angular sem abandonar a cultura. O resultado? Bem, muito tem sido dito sobre código Angular legado, que ninguém quer dar manutenção. A escolha errada jå foi feita, e isso é demasiadamente penoso para a manutenção de uma aplicação complexa.

O fato Ă© que a cultura nĂŁo mudou. Ainda se adota biblioteca ou framework em escala sem pensar duas vezes.

Aprendendo a evitar

Deve-se saber quando abranger uma visĂŁo holĂ­stica do projeto, e quando separar responsabilidades.

A separação de responsabilidades se daria pela análise dos requisitos da aplicação e dos desafios gerados, que trazem consigo o que chamo de “subproblemas” (necessidades que surgem durante a análise do desafio), que devem ser solucionados separadamente. A visão holística ajudaria a estruturar os componentes de forma consistente em um sistema, definindo uma arquitetura.

Falando de desenvolvimento front-end moderno (e, portanto, falando de front-end modular e de unidades encapsuladas e independentes, os componentes), essa separação de responsabilidades torna-se ainda mais fåcil! Vejamos, abaixo, alguns subproblemas que surgem durante a anålise de requisitos, apenas para exemplificar o que quero dizer quando trato a decisão de ferramentas como uma solução para um subproblema.

Os exemplos a seguir nĂŁo explicam o front-end modular na prĂĄtica. Adianto, no entanto, ferramentas como Browserify ou Webpack, que fazem parte do tooling necessĂĄrio.

1. ResiquiçÔes Ajax

Subproblema: escrever Ajax em JavaScript Ă© pouco intuitivo, difĂ­cil de ler e escrever.

Solução possĂ­vel: encapsular, no componente um mĂłdulo como Reqwest e httpinvoke. VocĂȘ pode, inclusive, utilizar apenas o Ajax do jQuery (e nĂŁo o jQuery inteiro!).

2. Manipulação excessiva do DOM

Subproblemas: manipular DOM com JavaScript pode ser bastante exaustivo. Também, manipular em um nível excessivo é extremamente custoso para a performance da aplicação.

Solução possível: Virtual DOM, que estå embutido em bibliotecas como React e Mithril. Ou, se precisar mesmo do DOM, considere pacotes como qwery ou Dominus, junto com domready.

E se precisĂĄssemos de Ajax no React, por exemplo? Este mau exemplo na documentação do React importa o jQuery inteiro. Como vocĂȘ faria? ;-)

Sobre arquitetura

Esse tópico deve ser tratado durante a visão holística do projeto, isso é, da aplicação enquanto sistema de componentes. O subproblema seria a necessidade de estrutura que uma aplicação requere.

Para isso, vocĂȘ nĂŁo precisa usar aquilo que Ă© tradicional (diretamente: vocĂȘ nĂŁo precisa usar MVC). Existem outras implementaçÔes de arquiteturas que nĂŁo a implementação feita pelo seu framework amado. Existem outras arquiteturas que nĂŁo Model-View-Controller.

Basicamente? Tenha um conhecimento decente de arquiteturas front-end (sugiro abrir a mente com Flux, que jå possui bastante materiais e implementaçÔes da arquitetura disponíveís), e não um conhecimento aprofundado de MVC.

ConclusĂŁo

Conheça o projeto e saiba como analisar seus requisitos. O resultado deve ser uma descrição explícita da sua aplicação, com subproblemas jå reconhecidos e, então, soluçÔes possíveis, todas envolvidas por uma solução possível maior, que é a da arquitetura (definida durante a anålise holística). Parece chato, mas vira håbito e acaba funcionando muito bem.

Lembre-se de que existem habilidades que a documentação de uma ferramenta nunca_ te ajudarå a desenvolver.

Com o tempo, vocĂȘ vai saber quando adotar um framework especĂ­fico em escala, quando optar por bibliotecas monolĂ­ticas, e terĂĄ, inclusive, seus preferidos a ponto de nĂŁo ter sempre que definir soluçÔes possĂ­veis para subproblemas que aplicaçÔes tĂȘm em comum.

(Em alguns projetos, vocĂȘ enxergarĂĄ padrĂ”es, por exemplo: qwery, domready e lodash sĂŁo usados juntos frequentemente.)

Um dia, no entanto, suas ferramentas falharĂŁo, outras ferramentas se adaptĂŁo melhor Ă  realidade de seus projetos, e, entĂŁo, o ciclo de anĂĄlise recomeça. E vocĂȘ jĂĄ sabe como proceder.

Seja curioso

No mais, seja curioso sobre arquiteturas de software, padrĂ”es de projeto, tooling — basta ser leitor(a). Seja curioso tambĂ©m sobre opiniĂ”es, principalmente quando elas tratam de desafios que ainda nĂŁo tivemos. A visĂŁo crĂ­tica Ă© ideal para abandonar a cultura jQuery.

O estudo permite que as soluçÔes possíveis surjam mais intuitivamente.

A pråtica virå com os desafios, e nesses desafios é que deve entrar o seu protagonismo de apresentar soluçÔes possíveis.

Notas

Esse Ă© um rascunho de pensamentos que venho acumulando hĂĄ algum tempo em razĂŁo de experiĂȘncias de trabalho que tive, e confesso que eles podem ter sido apresentados de forma confusa, embora eu tenha me esforçado. Mas isso aqui nĂŁo era para ser receita de bolo, de verdade! AtĂ© mesmo os exemplos citados nĂŁo devem passar de exemplos.

A minha abordagem possui falhas, e uma deles Ă© que exige de quem desenvolve um conhecimento vasto de ferramentas, quando se usava apenas uma para tudo. (Para isso, recomendo um recurso disponĂ­vel no npm e mecanismos de busca: a busca.)

Mas perceba que o conhecimento vasto Ă© apenas de ferramentas. O conhecimento exigido pelas ferramentas em si acaba sendo menor do que o exigido por aquelas all-in-one como jQuery e AngularJS. O fato de encapsularmos dependĂȘncias considerando a necessidade de cada componente no front-end Ă© um modo de mantermos a curva de aprendizagem fragmentada.

De acordo com o que venho experimentando, desenvolver essa mentalidade tem retornado experiĂȘncias maravilhosas e, inclusive, gerado menos cĂłdigo legado. Basta apenas aplicĂĄ-la Ă  Engenharia de Software com bom senso.

ConteĂșdo sugerido

Os complementos abaixo são apenas para despertar a curiosidade em relação aos conceitos apresentados neste artigo, e não devem substituir o estudo necessário para deixar de lado, na prática, a “cultura jQuery”.


Se vocĂȘ entendeu a razĂŁo pela qual a “cultura jQuery” distancia vocĂȘ do seu papel, a mensagem foi entregue com sucesso.

\ No newline at end of file diff --git a/blog/o-til-no-javascript/index.html b/blog/o-til-no-javascript/index.html new file mode 100644 index 0000000..2d4270d --- /dev/null +++ b/blog/o-til-no-javascript/index.html @@ -0,0 +1,33 @@ +O Til no JavaScript | Diéssica Gurskas
diessi.caBlog
October 31, 2015

O Til no JavaScript

Incompreendido, o operador til (~) é um mistério que ninguém discute. Primeiro, pois é um operador bitwise, e, segundo, pois seus casos de uso são bastante misteriosos


VocĂȘ consegue dizer


em valor e tipo de dado, o que serå impresso no console nas situaçÔes abaixo?

console.log(~~"1");
+console.log(~8.2);
+console.log(~false);
+console.log(~~"5.9");
+console.log(~~{});
+console.log(~~-5.5);
+console.log(~"Tudo bem?");
+

Não sabe? Well


O operador til

Ou melhor, o operador bitwise NOT.

É importante falar isso pois Ă© importante entender o que bitwise significa. Operadores bitwise sĂŁo especiais em JavaScript: eles tratam todos seus operandos como uma sequĂȘncia de 32 bits (0 e 1) – ou seja, trabalham com representaçÔes binĂĄrias (nĂŁo decimais, como de praxe) de nossos operandos, e nos entregam valores nĂșmericos como se nada tivesse acontecido.

O NOT significa que todos os bits do operando serĂŁo invertidos (0 vira 1, 1 vira 0). Parece inĂștil quando nĂŁo estamos trabalhando com nĂșmeros binĂĄrios, mas as aplicaçÔes criativas tornam o operador mais interessante.

Regras do ~

  1. Quando a expressĂŁo Ă© null ou undefined
 0.
  2. Objetos sĂŁo convertidos para strings.
  3. Strings sĂŁo convertidas para nĂșmeros, se possĂ­vel. Quando nĂŁo Ă© possĂ­vel
 0.
  4. Valores booleanos sĂŁo tratados como nĂșmeros (0 para false, 1 para true).
  5. Floating-points sĂŁo convertidos excluindo a parte fracionada.
  6. Todo nĂșmero inteiro n Ă© convertido para -(n + 1).

As duas Ășltimas regras sĂŁo as mais importantes, pois elas implicam nas principais aplicaçÔes do operador. JĂĄ temos a resposta de alguns:

console.log(~8.2); // => -9
+console.log(~false); // => -1
+console.log(~"Tudo bem?"); // => -1
+

Os nĂșmeros foram convertidos de acordo com a fĂłrmula -(n + 1). -9 Ă© resultado de - 8 - 1, por exemplo.

Dupla negação

Podemos usar dois operadores til (double bitwise NOT). Aqui, basta entender o trabalho do outro til: reinverter os bits.

Considerando ~n, como anteriormente, temos -(n + 1) = - n - 1. Considerando ~~n, temos -[-(n + 1)] = n + 1.

Perceba que as equaçÔes, quando somadas, se anulam. Pois essa é a grande sacada de usar dois operadores til! Temos, então:

console.log(~~"1"); // => 1
+console.log(~~"5.9"); // => 5
+console.log(~~{}); // => 0
+console.log(~~-5.5); // => -5
+

AplicaçÔes

Truncar nĂșmeros

Pelo fato do operador converter removendo a parte fracionada, utilizĂĄ-lo para truncar nĂșmeros de forma fĂĄcil Ă© a aplicação mais comum:

let data = 7.8926152;
+const integer = ~~data;
+
+console.log(integer); // => 7
+

Embora o ~~ tenha sido, por muito tempo, usado no lugar de Math.floor(), o método mais parecido com ele que temos em JavaScript hoje é o Math.trunc() do ES2015.

Converter string para nĂșmero

Uma aplicação simples que se baseia em uma das regras de funcionamento do til: converter strings para nĂșmeros sempre que possĂ­vel; afinal, Ă© com nĂșmeros que o operador trabalha.

let data = "2";
+const dataAsNumber = ~~data;
+
+console.log(dataAsNumber); // => 2
+

Verificar a existĂȘncia de um item no array

let women = ["Ada Lovelace", "Joan of Arc", "Marie Curie"];
+
+if (~women.indexOf("Ada Lovelace")) {
+  console.log("Ada Lovelace was such an important woman!");
+}
+

É difĂ­cil de compreender humanamente que o if estĂĄ verificando se Ada Lovelace estĂĄ incluĂ­da no array women, mas Ă© exatamente isso que estĂĄ acontecendo. VocĂȘ entendeu a razĂŁo pela qual isso funciona?

PoderĂ­amos verificar sem o ~, mas nĂŁo funcionaria em casos em que o item do array Ă© o primeiro (Ă­ndice zero, e 0 retorna false como booleano). O operador til viabiliza essa verificação, em razĂŁo da conversĂŁo de um nĂșmero inteiro n para -(n + 1).

O equivalente humano, utilizando Lodash (_), seria:

let women = ["Ada Lovelace", "Joan of Arc", "Marie Curie"];
+
+if (_(women).contains("Ada Lovelace")) {
+  console.log("Ada Lovelace was such an important woman!");
+}
+

Performance

Usar ~~ em vez de Math.floor ou Math.trunc é geralmente mais råpido. Dependendo da JavaScript engine do navegador e do caso de uso, no entanto, pode não fazer muita diferença e até ser mais lento. Veja o teste no JSPerf.

De qualquer forma, a pĂ©ssima performance de quem lĂȘ um cĂłdigo com o desumano ~ pode nĂŁo valer o ganho de performance – que Ă© ignorĂĄvel de tĂŁo mĂ­nimo – em uma aplicação.

ConsideraçÔes

No geral, operadores bitwise, principalmente ~, | e &, possuem aplicaçÔes interessantes e bastante criativas.

Quanto ao ~~, nĂŁo acredito que chegarĂĄ a se popularizar como aconteceu com o !!, que converte para um valor booleano. Em anos, a prĂĄtica com til nunca se tornou realmente popular, talvez pelo fato de ser um operador bitwise – e, portanto, pouco compreendido – e ter casos de uso bastante excĂȘntricos.

Ficam à título de curiosidade suas aplicaçÔes bastante criativas. ;-)

\ No newline at end of file diff --git a/blog/omg-climate/index.html b/blog/omg-climate/index.html new file mode 100644 index 0000000..12d10c9 --- /dev/null +++ b/blog/omg-climate/index.html @@ -0,0 +1 @@ +OMG Climate: Reflecting Together on the Climate Catastrophe | Diéssica Gurskas
diessi.caBlog
May 30, 2019

OMG Climate: Reflecting Together on the Climate Catastrophe

NASA's illustration of Planet Earth warming process across the years
Credits: NASA’s Scientific Visualization Studio/Kathryn Mersmann.

Planet Earth, May 2019. The UK has announced a state of emergency for climate change and Canada considers the same; we are more confident about our model to capture rising global temperatures, and students all around the world walk out of school protesting the lack of climate action. Yet, not enough of us are genuinely concerned about the role we’ve played on this catastrophe.

A Saturday afternoon of May and a few square meters in Berlin were what a couple of people needed to open– and voluntarily discuss how we impact the Planet to change and how those changes impact us. Topics ranged from radical solarpunk utopia to more down-to-earth and short-term ideas within our generation’s reach today: musings about climate change awareness, sustainability policies for companies, traveling sustainably, tech tools for political change, and how to get out of our bubbles and active listen to other realities.

In this post, I’ll be sharing my personal notes on that engaging and constructive afternoon. There will be, also, references at the end of this post so you can keep yourself posted.

Pitching and picking topics for discussion

OMG Climate is an unconference, meaning that attendees proactively come up with the agenda and topics to be discussed. To kick it off, we got instructed to pitch topics for discussion that’d be prioritised also by ourselves into tracks, attended based off our preferences. Everyone was expected to have at least a certain knowledge, even if rather tacit, about the challenges we’re facing right now with the climate emergency.

These were the tracks of the first OMG Climate:

  • Track 1: “Low-carbon travel” / “Green Mafia” / “How do you sleep at night? Coping with climate anxiety”
  • Track 2: “Tech tools for political action” / “Circular economies: Re-use and tech” / “Company sustainability policy template”
  • Track 3: “Solarpunk, imagination and excitement” / “CO2 Offsets as an API and tracking carbon” / “Climate change awareness in developing countries”

We had enough attendees for tracks to make for productive discussions. Listening and talking to one another, while facilitated by a volunteer, did the job on keeping up an constructive flow between finding root causes and ways to take action.

People sitting in a circle, listening attentively to one
During the "Green Mafia" discussion.

I’ve joined “Low-carbon travel”, “Green mafia”, and “Climate change awareness in developing countries”, so these are the ones I have more insights about. Towards the end, we all got together to wrap it up, and I have to say: all tracks were interesting, so don’t restrain yourself to this post!

The following notes don't reflect directly what's happened or everything that's been said in the event, it's rather my personal perspective. They are also somewhat vague, but I hope you can benefit from them somehow.

Low-carbon travel

Air travel, even when occasional, has an environmental impact difficult to make up for no matter how many bamboo toothbrushes we gift our friends, how often we commute by bike or how vegan is our diet.

With low airplane ticket prices getting more popular than ever and enabling people to travel more, how can we make traveling sustainable when not traveling to begin with is not an option? That was the question we kicked off the “low-carbon travel” discussion with.

Meeting notes

Piece of paper sticked to the wall with sketches
Collective sketch notes about the low-carbon travel track
  • In our circle, everyone seemed to have access to the privilege that is air flying.
  • We began exploring traveling by breaking it down into traveling for work vs. pleasure.
  • Ground travel might be an option; however, it’s rather time-consuming and hence less appealing in a capitalist society where time translates to money. How can we shift the paradigm?
  • Instead of seeing longer trips as wasted time, we should begin seeing the journey as part of the trip.
  • Traveling less: We often optimise our trips to visit as many places as possible; instead, we can optimise for depth and start going to fewer places for a longer time. Think: going to a European country and making the most of it, instead of going to 999 different countries just because they are 1-hour-flight away from each other.
  • Share practical solutions for people to make trade-offs, EcoCost rather than overwhelming scientific evidence.
  • What if companies supported employees whose carbon footprint is the least?
  • Green travel agencies and flying policies.
  • Search engines for flights obviously don’t suggest alternative ways to get to a place when a plane is definitely not the best option.
  • BVG app, on the other hand, recommends walking instead of taking public transport sometimes.
  • Transport apps could also order route options by the least environmental impact.
  • The car industry should be ashamed of its climate record.
  • The train industry is not modernised and integrated, rather rigid.
  • Investment on 10 km of autobahn could pay off the renovation for bike lanes all over Berlin.
  • Globalisation vs. environmental footprint: IT workers immigrating usually go back to their countries often since they have the need and resources. I asked whether there was data available on how that situation in particular could’ve increased our carbon emissions coming from aviation.
  • Business trips by train are possible only among those who have the privilege of a flexible work schedule, such as freelancers.
  • Making the most out of idle time: we tend to be more creative in idle times, while in a train; not hunching over a keyboard or in an office environment.
  • “Fast-moving home/office” as an alternative to turn the journey time into productive time.
  • Frequent flyer levy: A fairer tax system according to how often people fly. Those that fly more should pay more. (More information: A Free Ride)
  • Airline campaigns often promote the image that everyone should become part of a group of young, urban frequent flyers, visiting another city every few weeks for very low costs.

Action points

  • everyone to shift mindsets in regard to traveling.
  • everyone to vote instead of buying a bamboo toothbrush.
  • everyone to use and promote tools with different options of transport within a route, instead of blindly going to specific train or flight websites.
  • everyone to keep consuming local goods.
  • airline companies to stop promoting flying as a status symbol.
  • travel agencies to work out more sustainable ways to travel and consider it in their branding.

Green Mafia

How corporate interests and ideologues work to undermine science and make countries doubt about the risks of climate change? Think what stopped Australia, 25 years ago, to act on climate change.

We should fight back! We mused about beating off lobby groups representing the coal, car, oil, electricity, and aluminium industries using their same sneaky techniques, as a Green Mafia. An intriguing and fun topic!

The brainstorming served as a tool to get a grasp on the way those mafias function, and discuss whether the ethical approach is always the way to go when facing a crisis.

Meeting notes

Piece of paper sticked to the wall with sketches
Collective sketch notes about the Green Mafia track
  • Leverage civil disobedience and tools of intimidation to influence green policies for the climate, fight extreme wealth and weaken existing mafias such as the oil industry.
  • How far should one go with non-ethical practices, such as blackmailing or public shaming of those who harm the planet?
  • What’s ethics after all?
  • Could we use illegal money to fund our causes?
  • Could we use legal money to fund our cases? There are ways to get money from the state in licit ways such as from green parties.
  • What if we made the green cause as profitable for the mafia as oil?
  • Sell a belief system, or use an existing one such as “harmony with nature”.
  • Cyber hacking/hijacking internet algorithms to spread awareness instead of climate change denial and fake news as it happens today.

Awareness in developing countries

The rich, the poor and the Earth.

World’s richest 10% produce half of the global carbon emissions, while the poorest half contribute a mere 10%; but climate change affects the poorest people the most. Moreover, developing countries are the most responsible for climate change now, and vulnerable too.1

Coming from a developing country, I was looking forward to this topic! Apart from Brazil, we had people from India too. There was a range of issues that could be tackled within this track, such as the risk of massive displacements of people in developing countries, the need of support to adapt, environment destruction for the sake of economic prosperity, how to approach climate change education etc.

Meeting notes

  • We are building awareness, not “teaching” others about climate change.
  • Climate change is an existential threat to life, but it seems rather remote if you think about poverty, disease and economic stagnation. How do we educate children for the long-term if, for some of them, not showing up at school tomorrow means not eating at all?
  • How do we let them know about the risk of massive displacements of people who have no resources whatsoever to move?
  • Just by existing in a developed country in Europe, our carbon footprint is more impactful than any developing country.
  • Indigenous people are already defenders and protectors of the environment more than we will ever be in our generation.
  • Economic development is a priority in developing countries, and politicians may ignore environmental impact for the sake of it. (See Brazil’s natural resources open for business, says Bolsonaro)
  • Developing countries idealisation of economic development, influenced by “developed world standards”: tall buildings and industries all over the place, where often we don’t see the green implications of “success”.
  • What about a model of development thats puts together the simple living of developing countries with the green development of developed ones?
  • How waste affects developing countries; example of Philippines to sail garbage back to Canada.
  • We could shift the discussion to think about environmental impact in terms of social classes instead of countries. After all, rich lifestyles and “status” in general damage the environment in untold ways.
  • The Swadeshi movement brought back self-manufactured clothing in India to boycott foreign goods, a part of a movement to liberate India from British control and industrialisation.
  • When teaching, consider what’s in people’s context, reach and language instead of what’s “out there”.
  • We should actively listen more to those communities and what’s happening in those countries. Sometimes, instead of thinking that there is something to be taught, we should rather learn from their realities so we can bring about a meaningful conversation.
  • This is a problem not to be approached by technology, remotely. It’s rather about Politics and Education.

Action points

  • everyone to assure inclusivity, cooperation and engagement across boundaries, first and foremost.
  • countries to keep cooperating efforts internationally through policies, institutional frameworks for development and investments in infrastructure.

Conclusion

Well-led communities that strive for welcoming environments enable the best out of people. OMG Climate has shown that – its unconference format got everyone to take responsibility and engage towards constructive and meaningful discussions about climate change.

Participant presenting using microphone, all sketch notes of the unconference sticked to the wall, on background
Final presentations wrapping up the tracks.

Although most of us had a tech background, everyone seemed aware: tech alone will not solve all problems, but we are eager to address them either way.

Learn about Climate Change

More on OMG Climate

\ No newline at end of file diff --git a/blog/react-and-form-management-is-redux-form-worth-it/index.html b/blog/react-and-form-management-is-redux-form-worth-it/index.html new file mode 100644 index 0000000..2059d43 --- /dev/null +++ b/blog/react-and-form-management-is-redux-form-worth-it/index.html @@ -0,0 +1 @@ +React and Form Management: Is Redux Form Worth It? | Diéssica Gurskas
diessi.caBlog
May 21, 2018

React and Form Management: Is Redux Form Worth It?

This is an improvement over my answer to a question in a Brazilian forum: "is using Redux for forms worth it?", in Portuguese. It assumes previous knowledge with React and Redux, and also mentions Redux Form, a library for managing forms in React.

It depends.

I know “it depends” is far from an interesting answer, yet that’s the perfect-generic answer to any “is using X worth it?” question. It really depends, yes, but more often you don’t need that.

Last year I picked Redux Form to build a multi-step form wizard, each step containing different forms, with its own fields and validations (some of them asynchronous!). In the end, all forms would be merged into one JavaScript object to be sent at some point.

So, I’d like to share my experiences and hopefully help you to figure it out what your problem is, and help you to decide by telling you how I’ve solved mine.

Where Redux Form thrives

Redux Form is useful for larger and more complex forms where ease of development, high control (especially), consistency, and persistence (especially) are required. There are advantages from:

  1. the state form being in the Redux store, and
  2. Redux Form’s abstraction itself.

Which are two different things. You might need both, just one, or none at all.

Ease of development

Considering you are using Redux Form’s Field and wrap your form in its higher-order component – you’re done. Your form will work out of the box.

Yes, you could also get to build forms in a productive way with only React, but I think it's still worth-mentioning that Redux Form makes it really painless.

High control

You can manipulate forms from anywhere in the application: you trigger Redux actions provided by Redux Form and that’s all. No need to create your own Redux reducers and actions.

Redux Form is also flexible on what can be an input. Anything works as a field: custom 3rd-party inputs, a regular HTML input, a fancy select component without any standard form element at all
 Just pass the right props to it.

You can set up validation at the form and field level, supporting either synchronous or asynchronous validation. The errors triggered are also in the store – which makes it sweet to give useful feedbacks for users from anywhere, and also to debug! 👌

Consistency

All forms have the same data structure so you’d have the exact same information for every form and its fields, such as field values, field/form validity and further information (is the field touched? Pristine? Dirty?) in the Redux store.

Of course you can build forms consistently just by using React itself, but using Redux Form definitely enforces it.

Persistence

Since the state is already in the Redux store, Redux Form is easily pluggable with tools from the ecosystem.

Let’s say you want to save drafts from user’s inputs so people can finish and submit the form later. Redux Form + redux-persist make it pretty easy: the rehydrate process in the Redux store autofills the UI like magic!

Where Redux Form might die

In the thread, someone mentioned the article Redux Form is dead. TL;DR: It's not fucking dead, as any library, framework and whatsoever that has an "X is dead" post for it.

Let’s not forget that the JavaScript community is flooded with “X is dead” articles for everything in the ecosystem. That post, in particular, mentions valid points to consider such as ephemerality of the state (quoting Dan Abramov), performance issues within Redux Form, and the project maintenance/activity. I will go through them a bit.

Form data in the Redux store

Dan Abramov, creator of Redux, said: “Use React for ephemeral state that doesn’t matter to the app globally and doesn’t mutate in complex ways. For example, a toggle in some UI element, a form input state. [
]”.

Which is completely accurate. Where your state should live in your app depends entirely on its ephemerality – how trivial it is for the application as a whole when it comes to reading, updating it and so on.

In the post, that quote is used to support the claim that Redux Form fucks up when stores all form data in the Redux store by default – a pretty bold design decision for sure.

However, Dan did not write that in stone – he never does and he’s clear about it. That should serve as an encouragement for developers to think better about where your application’s states should go into. So, yes, you should think twice – and that doesn’t kill Redux Form.

The state of a form wizard, whose input data persists until the end of the steps (in a session or local level, for instance), whose inputs may trigger UI changes, whose inputs gets touched and changed by external components, it’s definitely not as ephemeral as the state of a newsletter sign up or a contact form. In the former, the form state is important for the whole application. Just notice that’s a very specific case.

Performance issues

Redux Form has reached a well-optimised (see redux-form #529 and redux-form #1405) state.

When it comes to performance, though, you should never rest easy anyway. If you measure and find that your forms are slow, you should find bottlenecks and optimise from that.

Project activity

Regarding the project activity, it is something to consider when deciding, and should always be. Is it active? Are there people maintaining it? Can YOU help to maintain it?

Yes, Erik (the author) has recently started working on another solution called Final Form, which moves the form state out of the Redux store. However, Redux Form is mature, still well maintained (check GitHub, and he even said it himself on Reddit), and its documentation is great.

Final words

Only if the state of your form is non-trivial enough to live in the Redux store, I’d give it a chance for Redux Form, especially if you are considering making your own solution. Redux Form has suffered and evolved a lot and nowadays it has a very stable and mature API you can count on, I’d say.

Other React form management solutions you should definitely be looking at are Formik and react-final-form, by Redux Form’s author. They don’t rely on Redux for state management and are most likely what you need now – or not.

The price is the abstraction, of course, it always is. 🙄 However, their everyday API is indeed minimal though, just be prepared to go through the documentation when you need to achieve specific stuff. In return, don’t forget you’ll get a consistent and solid structure to build forms upon.

Have fun building forms! 🎉

\ No newline at end of file diff --git a/blog/shared-variables-between-javascript-and-css/index.html b/blog/shared-variables-between-javascript-and-css/index.html new file mode 100644 index 0000000..5b4b53a --- /dev/null +++ b/blog/shared-variables-between-javascript-and-css/index.html @@ -0,0 +1,78 @@ +Shared Variables Between JavaScript and CSS | Diéssica Gurskas
diessi.caBlog
January 15, 2017

Shared Variables Between JavaScript and CSS

Because it assures consistency throughout the project and avoids magic numbers, sharing variables between JavaScript and CSS code may help you to keep your project codebase tidy and easier to reason about.

For this article, when talking about CSS, the word “variable” may mean custom property or custom media query.

Getting Started

First, create a object containing your variables and export it.

My JS file containing the object will be called variables.js.

export default {
+  mainColor: "#000",
+  secondaryColor: "#fff000",
+  fullHeight: "100vh",
+};
+

No magic is needed to use those variables in your JS files – just import them when you need it. But in order to communicate those variables to your CSS files and use them with var(), some magic is needed.

For this, I will be using cssnext, a PostCSS plugin, and injecting that object into our stylesheets as custom properties.

Webpack example:

import cssNext from "postcss-cssnext";
+import myVars from "./variables";
+
+module.exports = {
+  // Entry, loaders, plugins...
+
+  postcss: () => [
+    cssNext({
+      features: {
+        customProperties: { variables: myVars },
+      },
+    }),
+  ],
+};
+

Since I’m just using postcss-cssnext API, it’s also possible to do it with the build tool of your choice. Check docs on passing options to cssnext features.

Getting Real-world with Breakpoints

Sharing breakpoints between JavaScript and your stylesheets is a great real-world example.

It’s time for variables.js to grow then!

export const properties = {
+  mainColor: "#000",
+  secondaryColor: "#fff000",
+  fullHeight: "100vh",
+};
+
+export const mediaQueries = {
+  secondaryColor: "#fff000",
+  desktop: "(min-width: 1024px)",
+  tablet: "(min-width: 768px)",
+  mobile: "(min-width: 320px)",
+};
+

Because it’s not possible to create a media query containing a custom property, we need to inject mediaQueries as custom media queries.

Let’s update the previous Webpack example in order to let cssnext to know about both custom media queries and properties.

import cssNext from "postcss-cssnext";
+import { properties, mediaQueries } from "./variables";
+
+module.exports = {
+  // Entry, loaders, plugins...
+
+  postcss: () => [
+    cssNext({
+      features: {
+        customProperties: { variables: properties },
+        customMedia: { extensions: mediaQueries },
+      },
+    }),
+  ],
+};
+

Done! Some usage examples for CSS, JS and even React are provided below.

Usage

CSS Example

Using custom properties and custom media queries according to settings from variables.js file.

.banner {
+  background: red;
+  height: var(--fullHeight); /* Custom property */
+
+  @media (--desktop) {
+    /* Custom media query */
+    width: 50%;
+  }
+}
+

JavaScript example

Example below uses enquire.js library.

import enquire from "enquire.js";
+import { customMedia } from "./variables";
+
+enquire
+  .register(customMedia.tablet, () => {
+    console.log("Matched tablet resolution");
+  })
+  .register(customMedia.mobile, () => {
+    console.log("Matched mobile resolution");
+  });
+

React example

Rendering a component only on desktop resolutions.

Example below uses react-responsive library.

import MediaQuery from "react-responsive";
+import { customMedia } from "./variables";
+
+function DesktopOnlyComponent() {
+  /* (min-width: 1024px), according to variables.js */
+
+  return (
+    <MediaQuery query={customMedia.desktop}>
+      <p>My desktop-only component!</p>
+    </MediaQuery>
+  );
+}
+

Final Words

A non-consistent front-end codebase is just messy.

I really use this technique on everyday work, and it’s a cheap way to significantly improve the quality of the front-end codebase.

So, don’t underestimate it! Besides breakpoints, there are infinite possibilities for this, such as project colors, layout dimensions and other shared stuff that can easily get out of hand while working on a large project.

\ No newline at end of file diff --git a/blog/svg-images-as-react-components-with-webpack/index.html b/blog/svg-images-as-react-components-with-webpack/index.html new file mode 100644 index 0000000..36b938e --- /dev/null +++ b/blog/svg-images-as-react-components-with-webpack/index.html @@ -0,0 +1,48 @@ +SVG Images as React Components with Webpack | Diéssica Gurskas
diessi.caBlog
August 02, 2016

SVG Images as React Components with Webpack

If you’ve ever tried to load inline SVG (using svg-inline-loader) into React, you know it seriously hurts people’s eyes.

import React from "react";
+import IconRemove from "./icons/remove.svg";
+const RemoveButton = () => (
+  <button>
+    <div dangerouslySetInnerHTML={{ __html: IconRemove }} />
+    <span>Remove</span>
+  </button>
+);
+

So what if it looked like this instead?

import React from "react";
+import IconRemove from "./icons/remove.svg";
+const RemoveButton = () => (
+  <button>
+    <IconRemove />
+    <span>Remove</span>
+  </button>
+);
+

Much better, don’t you think?

That’s what svg-react-loader does. It process your SVG file and returns a React component, which is compiled with Babel (more on this below).

Using the Loader

npm install svg-react-loader --save-dev
+

Refer to Webpack docs for more information on loaders usage. Also, make sure you have installed svg-react-loader’s dependencies.

1. In Module Request

The simplest method, although the configuration convention is preferred. Using svg-react-loader and babel-loader, import your icon just like:

import IconRemove from "babel!svg-react!./icons/remove.svg";
+

Add in your Webpack configuration file’s loaders array.

{
+  test: /\.svg$/,
+  loader: 'babel!svg-react'
+}
+

Import your icon just like:

import IconRemove from "./icons/remove.svg";
+

Usage Examples

Loader in module request method (1):

import React from "react";
+import IconRemove from "babel!svg-react!./icons/remove.svg";
+const RemoveButton = () => (
+  <button>
+    <IconRemove />
+    <span>Remove</span>
+  </button>
+);
+

Loader in Webpack config file method (2):

import React from "react";
+import IconRemove from "./icons/remove.svg";
+const RemoveButton = () => (
+  <button>
+    <IconRemove />
+    <span>Remove</span>
+  </button>
+);
+

A Note on SVG Loaders

Sometimes, we don’t want all of our SVG files to be loaded as React components. If you use a SVG in a img element, for example, it may lead to conflicts. Fortunately, you can avoid them by being more specific in test regular expression:

{
+  test: /\.inline.svg$/,
+  loader: 'babel!svg-react'
+},
+{
+  test: /\.jpe?g$|\.gif$|\.png$|^(?!.*\.inline\.svg$).*\.svg$/,
+  loader: 'url'
+}
+

Now, only SVG files ending with .inline.svg will be loaded as React components. You’re good to go!

\ No newline at end of file diff --git a/blog/tchau/index.html b/blog/tchau/index.html new file mode 100644 index 0000000..18b8faa --- /dev/null +++ b/blog/tchau/index.html @@ -0,0 +1 @@ +Tchau | Diéssica Gurskas
diessi.caBlog
May 13, 2017

Tchau

de ViamĂŁo, Brasil para Berlim, Alemanha. đŸ‡©đŸ‡Ș

– Tu tem que ver o que Ă© pra ti, sabe? Se tu ficar aĂ­, tu provavelmente vai ficar nessa mesma por bastante tempo. É isso que tu quer?

– Não, meu sonho sempre foi morar fora, do país.

– O meu tambĂ©m Ă©. Esse Ă© o meu foco, pra sempre. Eu nunca tirei isso da mente.

A memória parece distante agora, mas não faz muito tempo que eu tive essa conversa. 30 de Março de 2016. Jå faz um pouco mais de um ano. Falåvamos de indecisÔes, insatisfaçÔes e mudanças, quando sonhos vieram à tona.

Sonhos. Pessoalmente, penso neles como desejos fixos que habitam a nossa consciĂȘncia junto a outros desejos, mais efĂȘmeros, e que, assim que vocĂȘ os deixa de lado (nem que seja um pouco), inconvenientemente voltam a te atormentar; lembrar que eles ainda estĂŁo lĂĄ e nĂŁo sĂŁo como os outros desejos.


Esse Ă© o meu foco, pra sempre. Eu nunca tirei isso da mente.

Palavras minhas. Confesso, me assustam. Ou melhor, me assustavam. O que me assusta mais agora Ă© o fato de eu ter lido isto em menos de um ano depois:

I’m personally very happy to say that after everything we’ve heard and seen, we think you’re a great match for us and would love for you to join our team here in Berlin.

([
] Pessoalmente, estou muito feliz de dizer que, depois de tudo que nĂłs ouvimos e vimos, achamos que vocĂȘ tem tudo a ver com a gente e gostarĂ­amos que se juntasse ao nosso time aqui em Berlim!)

O que seria para sempre o meu foco, o desejo que eu descorri por 30 linhas no meu LG R510 em uma carta de maio de 2012, aquilo que eu nunca havia tirado da mente, naquele momento surgia como uma oportunidade. Eu topei.

Foram vårios passos antes disso, e eu lembro de estar ansiosa antes de cada um deles. Encontrei pessoas maravilhosas durante o caminho, com um coração tão grande como o meu. Tanto na vida quanto nessa entrevista em particular.

Nas entrevistas, o processo simplesmente fluiu. Penso e gosto de pensar que é o que acontece quando os aspectos técnicos são vistos como meros meios necessårios para aquilo que realmente importa: criar.

Desde aquele momento até hoje, o dia do meu voo, o tempo pareceu nunca passar em alguns momentos, e, em outros, passar råpido demais. Mesmo com a percepção confusa do tempo, tenho certeza de que poder enviar a mensagem abaixo é algo que eu não imaginava para tão cedo.

Just got the call! [
] That’s an important moment of my life for sure. I’m just, you know, happy. Thank you for this.

The call. A ligação se referia a do Consulado Geral da Alemanha de Porto Alegre que recebi no dia 8 de maio, dizendo o que esperei 2 semanas (ou toda a minha vida?) para ouvir. O meu visto estava aprovado. Ali estava, sem dĂșvidas, um momento importante da minha vida.

Do resto do telefonema, confesso, nĂŁo lembro muito. Minha maior memĂłria desses instantes foi a de andar com o coração cheio atĂ© o centro de Porto Alegre como se fosse a Ășltima vez. E foi, pelo menos por um bom tempo.


Um sonho pode, afinal, terminar de 2 maneiras: sendo abandonado ou realizado.

Meu caso Ă© o segundo, e, sinceramente, nĂŁo estĂĄ fĂĄcil acreditar. Se vocĂȘ me disser que a partir de hoje eu jĂĄ nĂŁo moro mais onde cresci, que meu voo hoje Ă© sĂł de ida, essa informação serĂĄ processada de forma que ela nĂŁo faça sentido na minha realidade. Eu nĂŁo vou acreditar.

Por outro lado, nesse momento da minha vida em que a gratidão transcende o mérito, acredito em vårias outras coisas. A principal é que sou o resultado do fenÎmeno que acontece quando a oportunidade encontra o anseio: alguém, no passado, acreditou em mim; alguém, no presente, acredita em mim. E eu não as deixei decepcionar.


Hoje estou voando para Berlim, a capital da Alemanha, para fazer o que amo na HelloFresh, que me ajudou em todo o processo. Sou grata por isso, por tudo.

Quanto à realidade, não é que eu não tenha medo. Eu tenho. Eu tive medo em todas as vezes que ousei. Desde o primeiro emprego que fui atrås no Brasil (no tédio do meu Ensino Médio), dos projetos além do meu conhecimento, até o meu primeiro emprego fora do Brasil
 eu tive medo em todos eles.

Eu sĂł jamais deixaria o sonho terminar do outro jeito, entĂŁo eu topei tudo mesmo assim.

\ No newline at end of file diff --git a/blog/the-bitter-reality-of-ebooks/index.html b/blog/the-bitter-reality-of-ebooks/index.html new file mode 100644 index 0000000..ad31637 --- /dev/null +++ b/blog/the-bitter-reality-of-ebooks/index.html @@ -0,0 +1 @@ +The Bitter Reality of Ebooks and the Kindle Model | Diéssica Gurskas
diessi.caBlog
August 16, 2023

The Bitter Reality of Ebooks and the Kindle Model

A few years back, I jumped into the world of ebooks to broaden my reading without stacking so many physical books. I went with the ever-popular Kindle; yet the full weight of “owning” ebooks, particularly from Amazon, was not something I understood.


Until I decided to break up with Amazon, despite its convenience. You know the drill: Amazon exploits workers, aggressively avoids taxes, dominates markets, and I was just itching to explore alternative bookstores. The hiccup? My Kindle was firmly rooted and entangled in Amazon’s ecosystem. Without Amazon, I could no longer conveniently or legally read books on my Kindle, and without Kindle, I could not legally read books I once purchased on Amazon.

Here’s what I’ve learned while attempting to part ways.

It all begins with “DRM”

Digital Rights Management (“DRM”) might not be a household term, yet its fingerprints are everywhere. Ever wondered how we consume content via proprietary software, rather than owning the content?

Think Spotify (you never own the music), Netflix (you never own the film), Adobe Creative Cloud (you never own the software), Steam (you never own the game), and Amazon Kindle (you never own the ebook). You download those proprietary software on your device, not the content itself. While you may have a license to the content, but it’s not truly yours.

The use and distribution of the copyrighted content provided by those services (and many others) are restricted by DRM (“Digital Rights Management”) technologies, implemented in various ways, increasingly restrictive and controversial. While DRM aims to address the legitimate need of copyright protection, it fundamentally reshapes the landscape of intellectual consumption, often at the expense of user privacy and freedom. For example:

  • Content Sharing: DRM often limits, or restricts altogether, the ability to share, lend and gift content outside of the same ecosystem.

  • Content Portability: DRM can authorise content to only a specific set of devices or apps, and restrict the supported file formats (even to a proprietary format). That limits content migration across platforms, technologies and devices that better suit you.

The points above reveal an alarming side-effect: dependency on the ecosystem, or "vendor lock-in", which is detrimental to individual freedom and market competition. When content is tightly bound to the platform, disengaging becomes challenging. And when you're limited to sharing only within an ecosystem, your social circle gets roped in too. Kinda seem like cute digital mutualism until it's a toxic relationship you can't leave.

  • Content Perpetuity: DRM cannot guarantee perpetual access to content. If a service or platform discontinues the content or themselves entirely, you may simply lose what you purchased. In fact, that has already happened, more than once or twice.

  • Content Geographical Restrictions: DRM can prevent access to certain content based on location. With the internet alone, we could technically provide equal access to cultural and educational resources – DRM kills that.

  • Content Offline Access: DRM often requires online authentication or periodic online checks. Not very nice in low connectivity areas or during travel.

  • Personal Identification: DRM requires authentication to consume content. By withholding identifiable information, DRM systems may also monitor behavior and consumption patterns and then profile you. You’ve got nothing to hide? Well, perhaps it at least bothers you to have to login? (And if that keeps going on we might soon have login on physical books too?! And there will be no refresh token cookie irl?!?????)

All those “side-effects” (given they are actually unintended 😉) of copyright protection through DRM conveniences corporations. Corporations may not only protect their profit but also actively profit through DRM, charging high customer cost while delivering zero customer value.

Finally, because DRM implementations vary so much, it’s nearly impossible to determine your rights without diving into lengthy terms of use agreements. The restrictions are rather obscured by clever marketing – you’ll soon see.

Leaving Amazon, and failing

Do you still remember I was trying to break up with Kindle? I get too hung up sometimes but let’s not forget why we’re both here, right!!?!

First things first, let me make it clear – I did not want to give up ebooks. It’d been a pleasure to be able to dive into new literature and keep only the gems in my bedroom bookshelf. And I could also carry a multitude of stories effortlessly during my travels.

Secondly, I had no intention of trashing my Kindle. It was a fully functional piece of hardware, and it worked well.

So here was my grand plan: I’d log out of my Amazon account on the Kindle, and source my ebooks somewhere else. Seems pretty straightforward, right? But the hurdles kicked in right from the very first step.

FuN fACt: Kindle sales are not very profitable to Amazon, as they hope to make up for it with e-book and app sales.

As it turns out, signing out of my Amazon account meant every single piece of content I’d ever acquired through Kindle would vanish into thin air. On Kindle, your books are tied to your Amazon account.

That was an unforeseen repercussion. I naïvely expected to hold rights over books I’d purchased regardless of whether they were digitally or physically distributed. So I was disappointed and surprised – with myself, the state of things; both. And yes, I clearly had not read Kindle terms of use back when I got into the ecosystem (otherwise you wouldn’t be reading this! 😉).

FINALLY reading Kindle Terms of Use

The latest Kindle Store Terms of Use (Last updated: November 30, 2022), determines a set of restrictions you buy into when you decide to buy Kindle and Kindle content, DRM-protected or not. The “Use of Kindle Content” section states a couple of DRM-ish things:

  1. ebooks are meant to be consumed only on Kindle, or Kindle apps.

Upon your download or access of Kindle Content and payment of any applicable fees (including applicable taxes), the Content Provider grants you a non-exclusive right to view, use, and display such Kindle Content an unlimited number of times (for Subscription Content, only as long as you remain an active member of the underlying membership or subscription program), solely through a Kindle Application or as otherwise permitted as part of the Service, solely on the number of Supported Devices specified in the Kindle Store, and solely for your personal, non-commercial use. [...]

  1. when you click “Buy Now”1, you are actually buying a license i.e. renting.

Kindle Content is licensed, not sold, to you by the Content Provider. [...]

Coming from DRM-based services like Spotify or Netflix, where you subscribe for access to a collection of music or film, the Kindle model might be a surprise.

Within the Kindle ecosystem, you are able to buy individual content, which does evoke a stronger sense of direct ownership. Yet, when you do so, you’re essentially obtaining a license: every ebook is an one-off payment to a mini-subscription. And that was absolutely not straightforward or intuitive to me.

  1. you may not lend or sell your ebooks.

Unless specifically indicated otherwise, you may not sell, rent, lease, distribute, broadcast, sublicense, or otherwise assign any rights to the Kindle Content or any portion of it to any third party [...]

  1. your books might disappear anytime.

We may change, suspend, or discontinue the Service, in whole or in part, including adding or removing Subscription Content from a Service, at any time without notice.

(Funny enough, I checked Wayback Machine and noticed that one was amended around March 2015, after reports of disappearing ebooks years before. đŸ€·)


And embracing the sacrifice

Delving into the Kindle’s terms brought the truth crashing down on me: I never really had a choice to transition away from Amazon while retaining my content. Severing ties with Kindle came at a cost I hadn’t anticipated, and I felt very exploited for it.

Some might argue I actually had the “choice” to enter Kindle’s ecosystem. And sure, it’s true – I did it willingly, no one coerced me into becoming a Kindle user. But, hey, there’s a nuanced reality here you can’t brush aside: we make our individual choices within systems. There’s an entire environment lying behind the notion of individual choice.

Systems can be designed to subtly exert control or exploit personal choice in ways that aren’t always apparent. You can’t look at individual choice alone overseeing the environment in which those decisions are made. In no defensiveness, blaming on individual choice is, I dare to say, exactly how exploitative systems maintain their facade of legitimacy. And I don’t think being exploited or not should be a choice to be made.

Yeah, a bitter pill to swallow, but a new plan has to emerge out of my anger: to log out of my Amazon account, and therefore leave books I’ve purchased behind, and use Kindle only as an e-reader, not a shop.

Leaving Amazon, and failing less

After logging out of my Amazon account, I’m left with an anonymised Kindle (I hope). At this point I wonder if I even have the right to keep the hardware I’ve purchased, but so far nobody hasn’t taken it away from me. 😉 So, how can I rebuild my e-book library?

Using Kindle with other bookstores

Before buying ebooks elsewhere, one needs to understand what file formats are supported by Kindle. The file formats supported by Kindle are MOBI, PRC, PDF, and primarily the proprietary AZW, and the files may or may not be DRM-protected depending on the publisher. Only Amazon sells AZW books2. So my options are:

  • MOBI. But no bookstores sell them these days.
  • PDF. But formatting sucks for reading books.
  • PRC. I don’t know what that is.

So I have no options. \😎/ Bookstores sell EPUB books, an open standard well supported by all e-readers in the market but Kindle. Fortunately, you can manually convert EPUB books into one of the Kindle-compatible formats above. Unfortunately, if the book is DRM-protected (very likely!), you would need to strip out DRM before conversion which is downright illegal LMAOOOOOO!!!!! This drives me CRAZY, but let’s move on.

For ebook format conversions, Amazon fortunately offers Kindle Previewer, a publishing software, but it’s just a little too bloated for my goal. So I went with Calibre, a free and open source e-book manager that does it all. It works wonders!

If you keep your Amazon account, importing EPUB into is easier with Send to Kindle. It's a more convenient option but it often messes up with the book formatting.

Ultimately, using non-Amazon ebooks on a Kindle device can involve various technical and legal considerations, especially when dealing with DRM-protected content. DRM-free book shopping is also limited – DRM is an industry standard! So using a Kindle without Amazon is not just very inconvenient, it’s barely legal. 😉

The most promising plan seems to be tossing Kindle altogether, and choose an open standard e-reader with less hostile DRM platforms, but that’s for another time.

Amazon caters for publishers, not consumers

It all makes sense when you put it all together. When traditional publishing giants contemplated the world of e-readers and online stores, they had to be a bit careful about it. With physical distribution, they already had a model that offered a clear sense of ownership and control. Then, remember the music industry’s digital transformation, marked by piracy and revenue decline3? Obviously publishers would be wary of a similar fate.

But in comes a compelling offer from Amazon: a tight grip on digital ownership of books, and a shortcut into an already profitable book marketplace. All or nothing. A captivating promise of control and access which publishers, late to digital transformation, did not pass up. And so seamlessly, Amazon paved the way towards market dominance. 👏

Today, Amazon also positions itself as a platform for emerging writers and attracts independent publishers. So does Spotify for musicians, and Steam for game developers. For both publishers and consumers, content discovery is what’s great about such platforms, despite their license model.

Alternatives like Bandcamp (music) and GOG.com (games) also promote publishers’ content. In contrast, their DRM-free4 model ethically caters to both consumers and publishers: the consumer has direct ownership to content, and publishers get their content secured, even earning more5. How does that work? Fingerprinting content files (i.e. watermarks), but above all, cultivating consumer trust and transparency, and a sense of community and support for artists.

Final words

While writing this, an analogy came to mind.

Picture when you buy a physical book from a store. You know that book will patiently await you right where you left it and not vanish into thin air, whether you frequent the store or it eventually shuts down. That store is unaware of your identity. It doesn’t know when you open or close the book, nor does it know which passages you’ve highlighted. You can even lend the book to a friend, regardless of whether they shop at the same store or if the store recognizes them. And that both of you can go buy books elsewhere later with no strings attached.

But I know that’s kinda corny. It’s an oversimplification. Digital content IS different, and copying files is far easier technically than producing physical copies. We do have new challenges.

Yet, while the analogy might not outright invalidate DRM as a solution, it can serve as a reminder of the current asymmetry of our digital rights today. A nudge to the way our essential rights are exploited within the current framework of digital copyright protection. And, ultimately, it extends an invitation to reimagine it from the ground up. Perhaps looking at how other platforms like Bandcamp have already done so brilliantly, perhaps radically starting at copyright itself.

Keep reading


on how despite massive technical effort and corporate interest, DRM is a flawed security model.

1

As of 16/08/2023, Amazon’s checkout button for Kindle ebooks is labeled “Buy Now”.

5

In comparison to Spotify, whose profit margin for publishers is often questioned. See Ben Sinano: Musicians Say Streaming Doesn’t Pay. Can the Industry Change?.

\ No newline at end of file diff --git a/blog/ttt/index.html b/blog/ttt/index.html new file mode 100644 index 0000000..bd2b6f5 --- /dev/null +++ b/blog/ttt/index.html @@ -0,0 +1 @@ +T. T. T. | Diéssica Gurskas
diessi.caBlog
April 01, 2018

T. T. T.

Put up in a place
where it's easy to see
the cryptic admonishment
      T. T. T.

When you feel how depressingly
slowly you climb,
it’s well to remember that
      Things Take Time.

Piet Hein

\ No newline at end of file diff --git a/blog/ui-components-that-abstract-mistakes/index.html b/blog/ui-components-that-abstract-mistakes/index.html new file mode 100644 index 0000000..4bb2672 --- /dev/null +++ b/blog/ui-components-that-abstract-mistakes/index.html @@ -0,0 +1,11 @@ +UI Components that Abstract Mistakes | Diéssica Gurskas
diessi.caBlog
October 14, 2017

UI Components that Abstract Mistakes

2017, October 14th.

A cloudy day 1 of Autumn in Berlin, probably something else in the place you live, and you’ve read the same date twice and this introduction actually doesn’t matter. But let me tell you about something that matters.

Everything is made up of <div>s and <span>s again, utterly hidden behind abstractions proudly called components. No one seems to remember (or do they?) the difference between p and span, let alone the point of using section rather than div.

Bad decisions – to not just to say bad and even invalid HTML markup – are buried in components developers find awesome to compose user interfaces with. The web, and people, pay the price.


Creating components

From now on, to explain my point, I'll be assuming some familiarity with React (a JavaScript library), although this applies to any kind of component abstraction.

Let’s say you just started a brand new React web app. You need to create a button at some point, and, because it’s reused in other parts of the app, has custom styles and also a fancy icon, you decide to introduce a component with all that abstracted out. Nice! You could do it like this:

const Button = ({ onClick, children }) => (
+    <span class="my-horrible-button" onClick={onClick}>
+        <i class="my-terrible-font-awesome-icon"></i>
+        {children}
+    </span>
+)
+

The user interface is then composed as the following:

<h1>Brazilian Bananas (1 kg)</h1>
+<p>Sweet and healthy bananas!</p>
+<p>Absolutely the best.</p>
+<Button onClick={() => alert('🍌')}>Buy $0.99</button>
+

It looks good! You were born for this, weren’t you?

Quite easy to miss what’s wrong when components are just used like that. A button, isn’t it? The engineering team can easily grasp what that means and what that does, after all.

It could also be a <FormLabel /> or <Paragraph /> as span elements, or divs all over that place. Although they all work, mistakes are abstracted in components.

I specifically talk about markup as the mistake throughout this article, however it could be anything really. Components look inoffensive when you're using them.

The web isn’t your abstraction

Now that HTML is all abstracted through JavaScript libraries and frameworks (which is not wrong), I wonder whether developers only went for semantic elements for the sake of making markup more readable for themselves. With React, your <Header> now may be a div. Out of the abstraction, though, you’d think twice before going for a div to make a header – you’d rather use HTML5’s header.

Because of the abstraction, output markup isn’t something we talk that much about anymore.

Did we really get the benefits of HTML5 and why new elements were introduced? Why button? 2 What’s header useful for? Why should one use section at all?

By the way, do you know how many occurrences of header, article, section I've found on Netflix's landing page? Zero. It's all div soup.

Matter of fact is that browser engines and people – nothing less than the ones who you really write code for – won’t ever know about your abstractions. A screen reader won’t know your “button” is actually a button3. (They will definitely get to know the span though, and that won’t help.)

xkcd, comic #1444
xkcd: Tags

Also, it’s never been easier to write invalid markup without even realizing it! After React, it seems acceptable to place a button inside an anchor link, and even giant elephants inside span. Has anyone ever thought why they are considered invalid markup in the first place?

Don’t make it hard

Browsers and assistive technologies are smarter than ever4, indeed, yet they still count on developers to write code they can understand and people can benefit from. By doing so, you make it easy for:

  1. people, who will be able to navigate around the website, skipping over navigation sections or quickly jumping from one article to another5.
  2. yourself, so you don’t have to reimplement default browser behaviours.

Therefore, please: don’t waste features that technologies try to give users, and developers, out of the box.

Remember who you write code for.

1

If I had managed to publish this yesterday, the day would be sunny. I’ve missed the opportunity to make the article seems a little happier.

2

The button element was first introduced in HTML4. (Source)

3

What’s wrong with using a non-semantic element as a button? Well, if the button is accessible, nothing really. But doing so demands extra work that nobody is up for, besides that fact that you can’t actually create a button.

4

Technologies may even process <span class="tel">123-456-7890</span> as a telephone, and allow for automatic dialling of it. See microformat for more information.

5

Why not, right? After all, articles are for independent pieces of content, e.g., an user-submitted comment or a forum post. (Source)

\ No newline at end of file diff --git a/blog/var-that-this-nah/index.html b/blog/var-that-this-nah/index.html new file mode 100644 index 0000000..4fbaf19 --- /dev/null +++ b/blog/var-that-this-nah/index.html @@ -0,0 +1,33 @@ +var that = this? Nah. | Diéssica Gurskas
diessi.caBlog
March 15, 2017

var that = this? Nah.

Tried JavaScript for some minutes? You probably already wrote the following.

var that = this;
+

(Or one of its variants, such as var self = this.)

That’s a pretty common pattern when you found yourself in a situation where:

  1. you have a function nested inside of an object’s method, and
  2. you want to access the object’s properties, but
  3. JavaScript’s this is bound in an unexpected way.

Workarounding unexpected callback scope is one of the main situations where developers write var self = this.

Let’s assume a piece of code with a callback function.

function Requester(data, req) {
+  this.data = data;
+
+  req.done(function () {
+    console.log(this.data); // undefined
+  });
+}
+

You’d expect this.data to be the data argument. Yet, JavaScript tells you that it is actually undefined.

So, because Stack Overflow says so, you do the following:

function Requester(data, req) {
+  this.data = data;
+  var self = this; // NOOOOOoOooo
+
+  req.done(function () {
+    console.log(self.data);
+  });
+}
+

And never stops doing it in your life.

Still do it? I’m flattered to tell you that you don’t need that extra variable anymore.

Arrow functions

Go with arrow functions instead. Besides having a shorter syntax, arrow functions bind to the parent scope by default.

The scope that was firstly intuitive to you will work as expected now.

function Requester(data, req) {
+  this.data = data;
+
+  req.done(() => {
+    console.log(this.data); // intuitive as hell!
+  });
+}
+

You can count on them most of the time, but they also have unexpected behaviour in more advanced cases. After all, you're dealing with the `this` keyword. So don't just go around refactoring all anonymous functions into arrow ones and expecting everything to work.

You may also .bind()!

If for some reason (such as no support for IE) you can’t use them, check JavaScript’s bind. It’s not as awesome as arrow functions, but does the job.

function Requester(data, req) {
+  this.data = data;
+
+  req.done(
+    function () {
+      console.log(this.data);
+    }.bind(this)
+  );
+}
+
\ No newline at end of file diff --git a/blog/we-misunderstand-learning/index.html b/blog/we-misunderstand-learning/index.html new file mode 100644 index 0000000..49b34c1 --- /dev/null +++ b/blog/we-misunderstand-learning/index.html @@ -0,0 +1 @@ +We Misunderstand Learning | Diéssica Gurskas
diessi.caBlog
September 19, 2024

We Misunderstand Learning

We misunderstand learning. We think learning happens as we consume information, so we insist on consumption, hoping it will make sense. Reading sparks new ideas—yet often we merely seek out validation for the ones we already have. We misunderstand learning. We cling to theory like a lifeline, as though it can stand on its own, while overlooking the experimental space where it transforms: practice. Perhaps we gamify it. (Unlearning our addictions is another matter entirely.) We escape the confusion that must linger–it slips us that lingering isn’t forever. We misunderstand learning. Through edutainment, we satisfy the illusion of smooth progress, estimated reading times, chapter after chapter. True learning is too disjointed, unpredictable, and fraught with setbacks. We obsess over minimising gaps between repetitions, but are these gaps learning breaks, or learning itself? I recall the first time I picked up a guitar: my fingers aching to stretch, shredding like crazy against the strings. The morning after, I played the chord—not through conscious effort or passion, but because my fingers developed dexterity and calluses overnight. We misunderstand learning. Technique matters, yes, but some processes of embedding patterns are handled in their own time. Others have it easier, and we feel ashamed. I won’t lie–some do have it easier. But most often we don’t know, we weren’t there to see behind the ease, and nobody’s quite vulnerable these days.

We misunderstand learning, but once, we were in intimate touch with it. Back when we hadn’t yet been subjected to environments of comparison, deadlines, narrow molds, and had our complexities and neuro-diversities amassed into pure functions. I’m not immune to this. At times, learning as an adult feels like a endless chase of the instinctive dance of curiosity it once was. Throw at it: Pomodoro timers, habit trackers and productivity hacks. Yet, it’s only when I sit down to an unmysterious learning practice and truly welcome confusion, chaos, and seeming non-productivity that I feel like I can dance with curiosity again, and learn.

\ No newline at end of file diff --git a/blog/working-better-with-git-for-a-clear-history/index.html b/blog/working-better-with-git-for-a-clear-history/index.html new file mode 100644 index 0000000..6b99c53 --- /dev/null +++ b/blog/working-better-with-git-for-a-clear-history/index.html @@ -0,0 +1,69 @@ +Working Better with Git for a Clear History | Diéssica Gurskas
diessi.caBlog
August 04, 2018

Working Better with Git for a Clear History

Your teammate worked on a few improvements in all forms of the company’s website. At some point you, also a programmer, are asked for a code review.

This is the feature branch’s commit history you get in the Pull Request:

[290xx26] Resolve merge conflicts
+[9efxxf2] Refactor event listener for form fields
+[5d9xx5a] Update snapshots
+[948xxfa] Update dispatch event
+[f5xxea1] WIP
+[f8xxaae] Revert change
+[49xxf55e] Revert changes
+[02xxdf1] Update snapshots
+[21xx329] Pass down prop
+[28xxa865] Fix onChange event and add minimal design  in form
+[cfxx37c] U[date snapshots
+[cfxx36c] Update form to handle onChange event for autofill
+[242xx25] Fix another bug with onChange
+[f7xx738] Update form component
+[09xx868] Update snapshots
+

It seems like a lot, when actually those improvements are simply 1) fixing a bug with event handling and 2) introducing a minimal style to them. It just that it takes time to visualise that.

Indeed, committing often to a branch is a good practice1 and commits are supposed to be low-level rather than huge. However, a commit is applicable when you have a meaningful, self-contained batch of work to log to the history – and updating Jest snapshots is not it.

How about the following history?

[9efxxf2] Refactor event listener for form fields
+[cfxx37c] Add minimal design in form
+[cfxx36c] Update form to handle onChange event for autofill
+

That history communicates in a clear way what in the codebase has been changed in order to get the improvements done. If you want to know how it’s changed, it’s just a matter of checking out a particular commit.

Why a clear history matters

Apart from facilitating code reviews, since reviewers could grasp the context of the changes right at the first glimpse, a clear Git history is healthy for the project.

When commits started to reflect one’s workflow rather than the work done itself, the history turns into a mess of both meaningful and meaningless logs, hard to navigate through and undo changes (since commits are “checkpoints” of work). It’s highly likely that, as time goes by, developers will stop caring about the source code history as the powerful resource it is.

*The final Git history should reflect your work not the way you worked.

You begin to lose the benefit of source code management with a messy history, which was supposed to reflect how the codebase evolved over time.

A better relationship with Git

There are very common comprehensible reasons – yet not excuses at all! – for developers to unnecessarily commit. I can think of:

  1. “I had to update snapshots/fix unit test/code formatting/a typo in something I introduced.”
  2. “I had to merge master.”
  3. “I wanted to save my work.”
  4. “I don’t necessarily follow a clear flow – I am productive when I work in iterative way and usually do a lot of things at once.”

They can all be worked out by developing a better relationship with Git itself. That might take a while at first, but when it’s part of your daily workflow, you barely think about it at all. (I promise!)

First, let’s talk Git rebasing

Git rebase is a very powerful tool to reorganise your commits. It does a lot, so I won’t get deep into it.

The command git rebase has an important tool you should get comfortable with: interactive rebase. Let’s say we want to reorganise the latest 3 commits:

git rebase --interactive HEAD~3
+

HEAD points to the current branch in your Git repository. You can use @ as an alias as well: @~3, or the commit hash.

Interactive rebase will provide you a text interface with the list of the commits (in this case, within the range HEAD~3..HEAD) that are about to be rebased and actions you can apply to them:

pick [242xx25] Fix another bug with onChange
+pick [f7xx738] Update form component
+pick [09xx868] Update snapshots
+
+# Rebase 242xx25..09xx868 onto 242xx25
+#
+# Commands:
+#  p, pick = use commit
+#  r, reword = use commit, but edit the commit message
+#  e, edit = use commit, but stop for amending
+#  s, squash = use commit, but meld into previous commit
+#  f, fixup = like "squash", but discard this commit's log message
+#  x, exec = run command (the rest of the line) using shell
+#
+# These lines can be re-ordered; they are executed from top to bottom.
+#
+# If you remove a line here THAT COMMIT WILL BE LOST.
+#
+# However, if you remove everything, the rebase will be aborted.
+#
+# Note that empty commits are commented out
+

pick just means that commit is included. It's the default.

Editing that file (either by applying actions to commits or reordering them) and closing it will reapply those commits to the branch. We’ll explore some scenarios where that is useful.

Rebase instead of merge

The branch that you branched from has been updated (let’s call it master), so you need to fetch latest changes and merge that into yours with git pull. Instead of merging and introducing an ugly new commit for that, you can rebase and pretend that nothing ever happened in the first place.

git pull origin master --rebase
+

"Why isn't that the default then?", you might ask. I'd guess they didn't want to make a feature that rewrites history part of the default behaviour.

Squash commits when you can

You need to fix a typo, update a test, or include anything else that should have actually been part of a commit previously introduced. You can create a new commit and later squash it to the initial one with rebase.

git commit -m "Update contact form tests"
+git rebase -i HEAD~2 # act on top of latest 2 commits
+

Interactive rebase will show up, and you can mark that “Update contact form tests” as the commit to be squashed into a previous one by changing pick to s (squash).

The squashed commit has to come exactly before the commit you want to squash into, so you might have to some reordering.

Fix up and save time

Using the --fixup flag along with the commit hash of the previous commit will mark a commit as a fix of an existing one. Then, when you rebase with --autosquash, they will
 well, automatically get squashed.

Let’s say we have fixed a typo in the commit i2r923:

git commit --fixup i2r923
+git rebase --autosquash 9ef00f2  # one commit before above
+

You can configure Git to use the --autosquash flag by default when rebasing. I do that so you can check my dotfiles if you're curious.

Quite often, you’ll know how far you’re traveling from the current commit (HEAD). Instead of specifying hashes, you can just use HEAD as a reference to previous commits:

git commit --fixup HEAD            # fix 1 commit before HEAD
+git rebase --autosquash -i HEAD~1  # squash latest 2 commits
+

Stash to save your work in progress

You want to check or change other branch’s files, but don’t want to commit unfinished work either. You can stash your work in progress (“WIP”):

git stash
+

That stores everything from your working directory into stash. It’s so useful in my day-to-day work that I honestly often cry using it.

On how to get your work back, name your WIPs, or stash specific files, refer to the docs on Git staging. No way I am better at explaining than the documentation itself!

Commit selected chunks of your work

Remember the “I work in a very messy way, iterating between features” excuse? This helps. (It helped me yesterday when I refactored and introduced something new to it – should not be done altogether! –  at the same time without noticing.)

Besides only adding a specific file to your commit with git add, you may want to add only a chunk of the file’s code to a commit. That can be achieved with the --patch flag:

git add --patch
+

That’s another interface you’ll have to get comfortable with. You can also try out its --interactive option.

Using VS Code?

VS Code has a powerful built-in Git editor that allows you to add chunks of code to a commit. To stage specific lines to commit later, open VS Code’s Git editor, select the lines of code you feel should go into a commit, and “Stage selected changes” by right-clicking on it.

Showing how to use 'Stage Selected Changes' in VS Code
Changed the whole thing but want to commit only a chunk of it? VS Code has got you covered.

The Command Palette also has a “Git: Stage selected changes” option.

Rename commit messages for meaning

You had a look at the final history and found out your commit messages need some love. To change your latest commit (HEAD), you can just do git commit --amend; for other commits, you’ll have to rebase.

Let’s say you want to fix the latest 5 commits:

git rebase -i @~5
+

That will open up the interactive rebase you’re already familiar with. Find the commit you want, change pick to e (edit), and save and close the file; after Git rewinds to that commit, edit its message with git commit --amend, and run git rebase --continue when you’re done.

Got a clear history? Push it!

Commit Often, Perfect Later, Publish Once.1

Make sure that your branch has got a clear, readable and meaningful history


git log --oneline
+

Then push it into the remote repository!

git push origin head
+

If you have already pushed (Y THO???!), you can (carefully) use the force option (-f) to rewrite the remote history.

Extra: Fixing the first history

Remember the first history? We can fix it. It’s definitely harder to change it after it’s done, but totally doable with rebase -i. A possible solution would be:

squash [290xx26] Resolve merge conflicts
+pick [9efxxf2] Refactor event listener for form fields
+squash [5d9xx5a] Update snapshots
+squash [948xxfa] Update dispatch event
+delete [f5xxea1] WIP
+delete [f8xxaae] Revert change
+delete [49xxf55e] Revert changes
+squash [02xxdf1] Update snapshots
+squash [21xx329] Pass down prop
+pick [28xxa865] Fix onChange event and add minimal design  in form
+squash [cfxx37c] U[date snapshots
+pick [cfxx36c] Update form to handle onChange event for autofill
+fixup [242xx25] Fix another bug with onChange
+squash [f7xx738] Update form component
+squash [09xx868] Update snapshots
+

Be mindful about your decisions and make sure you are not losing work along the way. I deleted commits unused commits (WIP then reverted), squashed “fix” and “update tests” commits, and then picked only those that are meaningful batches of work.

I could have also split Fix onChange event and add minimal design in form into two separate commits
 But that’s for a future post.

Final considerations

Nowadays, I can say for sure that Git helps me to work better. Those techniques you’ve learned are all part of my daily workflow.

There is always something I don’t know about Git though, so I keep exploring. I recommend you do to do the same, and you can start right from your command line:

git help -w reset
+

Finally, if somehow you don’t feel comfortable with moving around your work from the command line, I’d recommend Git GUI clients2 – they are powerful and simplify visualising branches and its commits, especially when it gets tough3.

I hope you have better, more sane, work days after that!

2

Some clients I can think of: GitHub’s Git client (free), Git Kraken (free), Git Tower (paid).

3

It will get tough, because source code management is not easy. Anyhow, it’s always tougher when you care about things anyway. Easiest thing is not to care about anything at all.

\ No newline at end of file diff --git a/blog/writing-mode-in-vs-code/index.html b/blog/writing-mode-in-vs-code/index.html new file mode 100644 index 0000000..42fdb31 --- /dev/null +++ b/blog/writing-mode-in-vs-code/index.html @@ -0,0 +1,28 @@ +Writing Mode in VS Code | Diéssica Gurskas
diessi.caBlog
February 28, 2018

Writing Mode in VS Code

I’m a big fan of writing. I’m also a big fan of using my code editor and Markdown for that!

Screenshot of the VS Code in the zen mode without any clutter
My "writing mode" in VS Code, with the dark theme enabled.

Code editors are usually packed with a bunch of useful features, such as multi-selection, syntax highlighting, a file tree easy to operate, and sometimes even Markdown support – which I need for writing my articles, notes, to-do lists, and absolutely everything I can write using Markdown. I love having a consistent workflow and that’s crucial to me, so why not?

After configuring my editor of choice, VS Code, to get rid of the coding mode clutter (and also after an important update on its zen mode ❀), I’ve finally achieved a totally distraction-free writing experience!

Setting up the “Writing Mode”

1. User Settings

There are some important details to achieve total focus on writing. No line numbers, word wrap enabled, comfortable line height, no rulers, are some of them.

Since I only write in Markdown, I only set up those settings (and other tweaks) specifically for that language.

// github.com/diessica/dotfiles/blob/master/vscode/settings.json
+{
+  ....
+
+  "[markdown]": {
+    // force centering in zen mode
+    "zenMode.centerLayout": true,
+    // use the beautiful duospace font when available
+    "editor.fontFamily": "iA Writer Duospace, monospace",
+    // enable word wrap, since horizontal scroll while writing isn't human
+    "editor.wordWrap": true,
+    // i don't need line numbers, i'm not coding
+    "editor.lineNumbers": "off",
+    // light by default, but can be easily toggled to dark
+    "workbench.colorTheme": "Default Light+",
+    // i don't need rules, i'm not coding
+    "editor.rulers": [],
+    // larger text, to improve focus on writing
+    "editor.fontSize": 14,
+    // more comfortable line height
+    "editor.lineHeight": 25,
+    // disable editor suggestions based on previous words
+    "editor.quickSuggestions": false,
+  },
+
+  ...
+}
+

You can learn more about this file by checking the docs on "User and Workspace Settings".

Now, toggle zen mode in VS Code (see Keybindings, or View > Toggle Zen Mode) and check if that fits you!

2. Theme

Honestly, I think the default themes provided by VS Code do a great job. I use Dark+ as the dark theme; for light themes, either Quiet Light or Solarized Light.

If you don't like them, feel free to pick anything else, since most themes provide sufficient Markdown support anyway. Just don't procrastinate – a good theme won't make you a better writer.

3. Font

My font of choice for writing is the Duospace, designed by the people behind the text editor iaWriter. It’s a free and beautiful font shaped for the perfect writing experience.

4. Extensions

Extra tips

  • VS Code’s Markdown Preview is your friend – use it when you’re done with writing!
  • Configure the spell checker for your language, there are dictionary extensions for that available in the marketplace. I also have the Brazilian Portuguese package installed, for instance.
  • Like extensions? Keep exploring! The extension alex, for instance, catches insensitive, inconsiderate writing in texts.
  • Learn the Markdown keybindings provided by the All in One extension for a better workflow.

Happy writing! 🌟

\ No newline at end of file diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..c04a40a --- /dev/null +++ b/css/style.css @@ -0,0 +1 @@ +/*! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.prose{color:var(--tw-prose-body);max-width:65ch}.prose :where([class~=lead]):not(:where([class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.prose :where(a):not(:where([class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.prose :where(strong):not(:where([class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.prose :where(a strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(blockquote strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(thead th strong):not(:where([class~=not-prose] *)){color:inherit}.prose :where(ol):not(:where([class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.prose :where(ol[type=A]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=A s]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.prose :where(ol[type=a s]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.prose :where(ol[type=I]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type=I s]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.prose :where(ol[type=i s]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.prose :where(ol[type="1"]):not(:where([class~=not-prose] *)){list-style-type:decimal}.prose :where(ul):not(:where([class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.prose :where(ol>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.prose :where(ul>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.prose :where(hr):not(:where([class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:3em;margin-top:3em}.prose :where(blockquote):not(:where([class~=not-prose] *)){border-left-color:var(--tw-prose-quote-borders);border-left-width:.25rem;color:var(--tw-prose-quotes);font-style:italic;font-weight:500;margin-bottom:1.6em;margin-top:1.6em;padding-left:1em;quotes:"\201C""\201D""\2018""\2019"}.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose] *)):before{content:open-quote}.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose] *)):after{content:close-quote}.prose :where(h1):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-weight:800;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.prose :where(h1 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:900}.prose :where(h2):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-weight:700;line-height:1.3333333;margin-bottom:1em;margin-top:2em}.prose :where(h2 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:800}.prose :where(h3):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-weight:600;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.prose :where(h3 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(h4):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.prose :where(h4 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.prose :where(img):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose :where(figcaption):not(:where([class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.prose :where(code):not(:where([class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.prose :where(code):not(:where([class~=not-prose] *)):before{content:"`"}.prose :where(code):not(:where([class~=not-prose] *)):after{content:"`"}.prose :where(a code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(h1 code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(h2 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.875em}.prose :where(h3 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.9em}.prose :where(h4 code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(blockquote code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(thead th code):not(:where([class~=not-prose] *)){color:inherit}.prose :where(pre):not(:where([class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;color:var(--tw-prose-pre-code);font-size:.875em;font-weight:400;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;overflow-x:auto;padding:.8571429em 1.1428571em}.prose :where(pre code):not(:where([class~=not-prose] *)){background-color:transparent;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.prose :where(pre code):not(:where([class~=not-prose] *)):before{content:none}.prose :where(pre code):not(:where([class~=not-prose] *)):after{content:none}.prose :where(table):not(:where([class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-bottom:2em;margin-top:2em;table-layout:auto;text-align:left;width:100%}.prose :where(thead):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.prose :where(thead th):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-bottom:.5714286em;padding-left:.5714286em;padding-right:.5714286em;vertical-align:bottom}.prose :where(tbody tr):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.prose :where(tbody tr:last-child):not(:where([class~=not-prose] *)){border-bottom-width:0}.prose :where(tbody td):not(:where([class~=not-prose] *)){vertical-align:baseline}.prose :where(tfoot):not(:where([class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.prose :where(tfoot td):not(:where([class~=not-prose] *)){vertical-align:top}.prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.prose :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.prose :where(video):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(figure):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.prose :where(li):not(:where([class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.prose :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.375em}.prose :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.375em}.prose :where(.prose>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.prose :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.prose :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.prose :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.5714286em}.prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose :where(.prose>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.prose :where(.prose>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.prose-sm{font-size:.875rem;line-height:1.7142857}.prose-sm :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em}.prose-sm :where([class~=lead]):not(:where([class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-bottom:.8888889em;margin-top:.8888889em}.prose-sm :where(blockquote):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-left:1.1111111em}.prose-sm :where(h1):not(:where([class~=not-prose] *)){font-size:2.1428571em;line-height:1.2;margin-bottom:.8em;margin-top:0}.prose-sm :where(h2):not(:where([class~=not-prose] *)){font-size:1.4285714em;line-height:1.4;margin-bottom:.8em;margin-top:1.6em}.prose-sm :where(h3):not(:where([class~=not-prose] *)){font-size:1.2857143em;line-height:1.5555556;margin-bottom:.4444444em;margin-top:1.5555556em}.prose-sm :where(h4):not(:where([class~=not-prose] *)){line-height:1.4285714;margin-bottom:.5714286em;margin-top:1.4285714em}.prose-sm :where(img):not(:where([class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(video):not(:where([class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(figure):not(:where([class~=not-prose] *)){margin-bottom:1.7142857em;margin-top:1.7142857em}.prose-sm :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.prose-sm :where(figcaption):not(:where([class~=not-prose] *)){font-size:.8571429em;line-height:1.3333333;margin-top:.6666667em}.prose-sm :where(code):not(:where([class~=not-prose] *)){font-size:.8571429em}.prose-sm :where(h2 code):not(:where([class~=not-prose] *)){font-size:.9em}.prose-sm :where(h3 code):not(:where([class~=not-prose] *)){font-size:.8888889em}.prose-sm :where(pre):not(:where([class~=not-prose] *)){border-radius:.25rem;font-size:.8571429em;line-height:1.6666667;margin-bottom:1.6666667em;margin-top:1.6666667em;padding:.6666667em 1em}.prose-sm :where(ol):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em;padding-left:1.5714286em}.prose-sm :where(ul):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em;margin-top:1.1428571em;padding-left:1.5714286em}.prose-sm :where(li):not(:where([class~=not-prose] *)){margin-bottom:.2857143em;margin-top:.2857143em}.prose-sm :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.4285714em}.prose-sm :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.4285714em}.prose-sm :where(.prose-sm>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.5714286em;margin-top:.5714286em}.prose-sm :where(.prose-sm>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(.prose-sm>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.1428571em}.prose-sm :where(.prose-sm>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.1428571em}.prose-sm :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.5714286em;margin-top:.5714286em}.prose-sm :where(hr):not(:where([class~=not-prose] *)){margin-bottom:2.8571429em;margin-top:2.8571429em}.prose-sm :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(table):not(:where([class~=not-prose] *)){font-size:.8571429em;line-height:1.5}.prose-sm :where(thead th):not(:where([class~=not-prose] *)){padding-bottom:.6666667em;padding-left:1em;padding-right:1em}.prose-sm :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose-sm :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose-sm :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.6666667em 1em}.prose-sm :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.prose-sm :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.prose-sm :where(.prose-sm>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.prose-sm :where(.prose-sm>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.right-0{right:0}.top-0{top:0}.z-10{z-index:10}.z-20{z-index:20}.mx-auto{margin-left:auto;margin-right:auto}.my-8{margin-bottom:2rem;margin-top:2rem}.my-12{margin-bottom:3rem;margin-top:3rem}.mb-2{margin-bottom:.5rem}.mb-8{margin-bottom:2rem}.mb-5{margin-bottom:1.25rem}.mb-10{margin-bottom:2.5rem}.mb-1{margin-bottom:.25rem}.mb-4{margin-bottom:1rem}.mb-3{margin-bottom:.75rem}.mr-1\.5{margin-right:.375rem}.mr-1{margin-right:.25rem}.mr-3{margin-right:.75rem}.ml-2{margin-left:.5rem}.block{display:block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.hidden{display:none}.min-h-\[calc\(100vh-16px\)\]{min-height:calc(100vh - 16px)}.min-h-screen{min-height:100vh}.w-full{width:100%}.w-auto{width:auto}.w-max{width:-moz-max-content;width:max-content}.grow{flex-grow:1}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.flex-col{flex-direction:column}.justify-between{justify-content:space-between}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.space-x-8>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(2rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(2rem*var(--tw-space-x-reverse))}.self-center{align-self:center}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.scroll-smooth{scroll-behavior:smooth}.whitespace-nowrap{white-space:nowrap}.rounded-xl{border-radius:.75rem}.rounded{border-radius:.25rem}.border-b-2{border-bottom-width:2px}.border-green{--tw-border-opacity:1;border-color:rgb(105 255 0/var(--tw-border-opacity))}.bg-index{--tw-bg-opacity:1;background-color:rgb(21 7 25/var(--tw-bg-opacity))}.bg-blog{--tw-bg-opacity:1;background-color:rgb(255 237 254/var(--tw-bg-opacity))}.bg-green{--tw-bg-opacity:1;background-color:rgb(105 255 0/var(--tw-bg-opacity))}.bg-amber-100{--tw-bg-opacity:1;background-color:rgb(254 243 199/var(--tw-bg-opacity))}.p-40{padding:10rem}.p-2{padding:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.py-8{padding-bottom:2rem;padding-top:2rem}.py-10{padding-bottom:2.5rem;padding-top:2.5rem}.py-12{padding-bottom:3rem;padding-top:3rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.pr-10{padding-right:2.5rem}.pb-1\.5{padding-bottom:.375rem}.pb-1{padding-bottom:.25rem}.pb-8{padding-bottom:2rem}.pt-1{padding-top:.25rem}.text-center{text-align:center}.font-body,.font-display{font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-6xl{font-size:3.75rem;line-height:1}.text-4xl{font-size:2.25rem;line-height:2.5rem}.font-extrabold{font-weight:800}.font-bold{font-weight:700}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-loose{line-height:2}.leading-none{line-height:1}.tracking-widest{letter-spacing:.1em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-green{--tw-text-opacity:1;color:rgb(105 255 0/var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-slate-200{--tw-text-opacity:1;color:rgb(226 232 240/var(--tw-text-opacity))}.text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity))}.text-slate-900{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity))}.text-purple{--tw-text-opacity:1;color:rgb(150 0 255/var(--tw-text-opacity))}.text-slate-800{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity))}.no-underline{text-decoration-line:none}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-30{opacity:.3}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.footnote-definition{display:block;font-size:.875rem;line-height:1.25rem;margin-bottom:.5rem}.footnote-definition p{display:inline;padding-left:.5rem;padding-right:.5rem}.footnote-definition-label{font-weight:700}body :focus{--tw-bg-opacity:1;--tw-text-opacity:1;background-color:rgb(150 0 255/var(--tw-bg-opacity));color:rgb(255 255 255/var(--tw-text-opacity));outline:2px solid transparent;outline-offset:2px}a{text-decoration-line:underline}a:hover{text-decoration-line:none}::marker{color:#9600ff!important}.note{--tw-border-opacity:1;border-color:rgb(105 255 0/var(--tw-border-opacity));border-left-width:3px;border-style:solid;color:rgb(71 85 105/var(--tw-text-opacity));font-size:.875rem;padding-left:1.25rem}.note,.summary{--tw-text-opacity:1;line-height:1.5rem}.summary{color:rgb(100 116 139/var(--tw-text-opacity));font-size:1rem;font-style:italic;margin-bottom:2.5rem;margin-top:-2rem;text-align:center}@media (min-width:1280px){.summary{margin-left:-14rem;margin-right:-14rem}}b,strong{font-weight:800}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:normal;font-weight:300;src:url(/fonts/JetBrainsMono-Light.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:italic;font-weight:300;src:url(/fonts/JetBrainsMono-LightItalic.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:normal;font-weight:400;src:url(/fonts/JetBrainsMono-Regular.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:italic;font-weight:400;src:url(/fonts/JetBrainsMono-Italic.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:normal;font-weight:500;src:url(/fonts/JetBrainsMono-SemiBold.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:italic;font-weight:500;src:url(/fonts/JetBrainsMono-SemiBoldItalic.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:normal;font-weight:600;src:url(/fonts/JetBrainsMono-Bold.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:italic;font-weight:600;src:url(/fonts/JetBrainsMono-BoldItalic.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:normal;font-weight:800;src:url(/fonts/JetBrainsMono-ExtraBold.woff2) format("woff2")}@font-face{font-display:swap;font-family:JetBrains Mono;font-style:italic;font-weight:800;src:url(/fonts/JetBrainsMono-ExtraBoldItalic.woff2) format("woff2")}.hover\:border-b-2:hover{border-bottom-width:2px}.hover\:border-green:hover{--tw-border-opacity:1;border-color:rgb(105 255 0/var(--tw-border-opacity))}.hover\:text-slate-700:hover{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity))}.hover\:text-slate-600:hover{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity))}.prose-headings\:w-max :is(:where(h1,h2,h3,h4,h5,h6,th):not(:where([class~=not-prose] *))){width:-moz-max-content;width:max-content}.prose-headings\:font-display :is(:where(h1,h2,h3,h4,h5,h6,th):not(:where([class~=not-prose] *))){font-family:JetBrains Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.prose-headings\:font-extrabold :is(:where(h1,h2,h3,h4,h5,h6,th):not(:where([class~=not-prose] *))){font-weight:800}.prose-headings\:text-slate-800 :is(:where(h1,h2,h3,h4,h5,h6,th):not(:where([class~=not-prose] *))){--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity))}.prose-a\:text-white :is(:where(a):not(:where([class~=not-prose] *))){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.prose-blockquote\:border-0 :is(:where(blockquote):not(:where([class~=not-prose] *))){border-width:0}.prose-blockquote\:text-center :is(:where(blockquote):not(:where([class~=not-prose] *))){text-align:center}.prose-blockquote\:text-xl :is(:where(blockquote):not(:where([class~=not-prose] *))){font-size:1.25rem;line-height:1.75rem}.prose-blockquote\:text-current :is(:where(blockquote):not(:where([class~=not-prose] *))){color:currentColor}.prose-strong\:text-white :is(:where(strong):not(:where([class~=not-prose] *))){--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.prose-pre\:rounded-none :is(:where(pre):not(:where([class~=not-prose] *))){border-radius:0}.prose-hr\:mx-auto :is(:where(hr):not(:where([class~=not-prose] *))){margin-left:auto;margin-right:auto}.prose-hr\:my-4 :is(:where(hr):not(:where([class~=not-prose] *))){margin-bottom:1rem;margin-top:1rem}.prose-hr\:h-0\.5 :is(:where(hr):not(:where([class~=not-prose] *))){height:.125rem}.prose-hr\:h-0 :is(:where(hr):not(:where([class~=not-prose] *))){height:0}.prose-hr\:w-48 :is(:where(hr):not(:where([class~=not-prose] *))){width:12rem}.prose-hr\:rounded :is(:where(hr):not(:where([class~=not-prose] *))){border-radius:.25rem}.prose-hr\:border-0 :is(:where(hr):not(:where([class~=not-prose] *))){border-width:0}.prose-hr\:bg-black :is(:where(hr):not(:where([class~=not-prose] *))){--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.prose-hr\:opacity-20 :is(:where(hr):not(:where([class~=not-prose] *))){opacity:.2}@media (prefers-color-scheme:dark){.dark\:bg-indigo-900{--tw-bg-opacity:1;background-color:rgb(49 46 129/var(--tw-bg-opacity))}.dark\:text-slate-300{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity))}.dark\:text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity))}.hover\:dark\:text-slate-300:hover{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity))}}@media (min-width:768px){.md\:prose{color:var(--tw-prose-body);max-width:65ch}.md\:prose :where([class~=lead]):not(:where([class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;line-height:1.6;margin-bottom:1.2em;margin-top:1.2em}.md\:prose :where(a):not(:where([class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline}.md\:prose :where(strong):not(:where([class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.md\:prose :where(a strong):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(blockquote strong):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(thead th strong):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(ol):not(:where([class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.md\:prose :where(ol[type=A]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.md\:prose :where(ol[type=a]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.md\:prose :where(ol[type=A s]):not(:where([class~=not-prose] *)){list-style-type:upper-alpha}.md\:prose :where(ol[type=a s]):not(:where([class~=not-prose] *)){list-style-type:lower-alpha}.md\:prose :where(ol[type=I]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.md\:prose :where(ol[type=i]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.md\:prose :where(ol[type=I s]):not(:where([class~=not-prose] *)){list-style-type:upper-roman}.md\:prose :where(ol[type=i s]):not(:where([class~=not-prose] *)){list-style-type:lower-roman}.md\:prose :where(ol[type="1"]):not(:where([class~=not-prose] *)){list-style-type:decimal}.md\:prose :where(ul):not(:where([class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-left:1.625em}.md\:prose :where(ol>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.md\:prose :where(ul>li):not(:where([class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.md\:prose :where(hr):not(:where([class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:3em;margin-top:3em}.md\:prose :where(blockquote):not(:where([class~=not-prose] *)){border-left-color:var(--tw-prose-quote-borders);border-left-width:.25rem;color:var(--tw-prose-quotes);font-style:italic;font-weight:500;margin-bottom:1.6em;margin-top:1.6em;padding-left:1em;quotes:"\201C""\201D""\2018""\2019"}.md\:prose :where(blockquote p:first-of-type):not(:where([class~=not-prose] *)):before{content:open-quote}.md\:prose :where(blockquote p:last-of-type):not(:where([class~=not-prose] *)):after{content:close-quote}.md\:prose :where(h1):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-weight:800;line-height:1.1111111;margin-bottom:.8888889em;margin-top:0}.md\:prose :where(h1 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:900}.md\:prose :where(h2):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-weight:700;line-height:1.3333333;margin-bottom:1em;margin-top:2em}.md\:prose :where(h2 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:800}.md\:mb-12{margin-bottom:3rem}.md\:prose :where(h3):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-weight:600;line-height:1.6;margin-bottom:.6em;margin-top:1.6em}.md\:prose :where(h3 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.md\:prose :where(h4):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;margin-bottom:.5em;margin-top:1.5em}.md\:prose :where(h4 strong):not(:where([class~=not-prose] *)){color:inherit;font-weight:700}.md\:prose :where(img):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.md\:inline{display:inline}.md\:prose :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.md\:prose :where(figcaption):not(:where([class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;line-height:1.4285714;margin-top:.8571429em}.md\:prose :where(code):not(:where([class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-weight:600}.md\:prose :where(code):not(:where([class~=not-prose] *)):before{content:"`"}.md\:prose :where(code):not(:where([class~=not-prose] *)):after{content:"`"}.md\:prose :where(a code):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(h1 code):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(h2 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.875em}.md\:prose :where(h3 code):not(:where([class~=not-prose] *)){color:inherit;font-size:.9em}.md\:prose :where(h4 code):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(blockquote code):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(thead th code):not(:where([class~=not-prose] *)){color:inherit}.md\:prose :where(pre):not(:where([class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;color:var(--tw-prose-pre-code);font-size:.875em;font-weight:400;line-height:1.7142857;margin-bottom:1.7142857em;margin-top:1.7142857em;overflow-x:auto;padding:.8571429em 1.1428571em}.md\:prose :where(pre code):not(:where([class~=not-prose] *)){background-color:transparent;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.md\:prose :where(pre code):not(:where([class~=not-prose] *)):before{content:none}.md\:prose :where(pre code):not(:where([class~=not-prose] *)):after{content:none}.md\:prose :where(table):not(:where([class~=not-prose] *)){font-size:.875em;line-height:1.7142857;margin-bottom:2em;margin-top:2em;table-layout:auto;text-align:left;width:100%}.md\:prose :where(thead):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.md\:prose :where(thead th):not(:where([class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-bottom:.5714286em;padding-left:.5714286em;padding-right:.5714286em;vertical-align:bottom}.md\:prose :where(tbody tr):not(:where([class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.md\:prose :where(tbody tr:last-child):not(:where([class~=not-prose] *)){border-bottom-width:0}.md\:prose :where(tbody td):not(:where([class~=not-prose] *)){vertical-align:baseline}.md\:prose :where(tfoot):not(:where([class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.md\:prose :where(tfoot td):not(:where([class~=not-prose] *)){vertical-align:top}.md\:prose{--tw-prose-body:#374151;--tw-prose-headings:#111827;--tw-prose-lead:#4b5563;--tw-prose-links:#111827;--tw-prose-bold:#111827;--tw-prose-counters:#6b7280;--tw-prose-bullets:#d1d5db;--tw-prose-hr:#e5e7eb;--tw-prose-quotes:#111827;--tw-prose-quote-borders:#e5e7eb;--tw-prose-captions:#6b7280;--tw-prose-code:#111827;--tw-prose-pre-code:#e5e7eb;--tw-prose-pre-bg:#1f2937;--tw-prose-th-borders:#d1d5db;--tw-prose-td-borders:#e5e7eb;--tw-prose-invert-body:#d1d5db;--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:#9ca3af;--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:#9ca3af;--tw-prose-invert-bullets:#4b5563;--tw-prose-invert-hr:#374151;--tw-prose-invert-quotes:#f3f4f6;--tw-prose-invert-quote-borders:#374151;--tw-prose-invert-captions:#9ca3af;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:#d1d5db;--tw-prose-invert-pre-bg:rgba(0,0,0,.5);--tw-prose-invert-th-borders:#4b5563;--tw-prose-invert-td-borders:#374151;font-size:1rem;line-height:1.75}.md\:prose :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.25em;margin-top:1.25em}.md\:prose :where(video):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.md\:prose :where(figure):not(:where([class~=not-prose] *)){margin-bottom:2em;margin-top:2em}.md\:prose :where(li):not(:where([class~=not-prose] *)){margin-bottom:.5em;margin-top:.5em}.md\:prose :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.375em}.md\:prose :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.375em}.md\:prose :where(.md\:prose>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.md\:prose :where(.md\:prose>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.md\:prose :where(.md\:prose>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.md\:prose :where(.md\:prose>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.25em}.md\:prose :where(.md\:prose>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.25em}.md\:prose :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.md\:prose :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.md\:prose :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.md\:prose :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.md\:prose :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.md\:prose :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.md\:prose :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.md\:prose :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.5714286em}.md\:prose :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.md\:prose :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.md\:prose :where(.md\:prose>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.md\:prose :where(.md\:prose>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.md\:flex-row{flex-direction:row}.md\:space-y-0>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(0px*var(--tw-space-y-reverse));margin-top:calc(0px*(1 - var(--tw-space-y-reverse)))}.md\:space-x-3>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.75rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.75rem*var(--tw-space-x-reverse))}.md\:border-\[10px\]{border-width:10px}.md\:border-solid{border-style:solid}.md\:border-purple{--tw-border-opacity:1;border-color:rgb(150 0 255/var(--tw-border-opacity))}.md\:px-8{padding-left:2rem;padding-right:2rem}.md\:px-10{padding-left:2.5rem;padding-right:2.5rem}.md\:px-1{padding-left:.25rem;padding-right:.25rem}.md\:pr-0{padding-right:0}.md\:pt-1\.5{padding-top:.375rem}.md\:pt-1{padding-top:.25rem}.md\:text-9xl{font-size:8rem;line-height:1}.md\:text-5xl{font-size:3rem;line-height:1}.md\:text-lg{font-size:1.125rem;line-height:1.75rem}.prose-hr\:md\:my-10 :is(:where(hr):not(:where([class~=not-prose] *))){margin-bottom:2.5rem;margin-top:2.5rem}}@media (min-width:1024px){.lg\:min-h-\[calc\(100vh-20px\)\]{min-height:calc(100vh - 20px)}.lg\:w-3\/5{width:60%}.lg\:prose-lg{font-size:1.125rem;line-height:1.7777778}.lg\:prose-lg :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em}.lg\:prose-lg :where([class~=lead]):not(:where([class~=not-prose] *)){font-size:1.2222222em;line-height:1.4545455;margin-bottom:1.0909091em;margin-top:1.0909091em}.lg\:prose-lg :where(blockquote):not(:where([class~=not-prose] *)){margin-bottom:1.6666667em;margin-top:1.6666667em;padding-left:1em}.lg\:prose-lg :where(h1):not(:where([class~=not-prose] *)){font-size:2.6666667em;line-height:1;margin-bottom:.8333333em;margin-top:0}.lg\:prose-lg :where(h2):not(:where([class~=not-prose] *)){font-size:1.6666667em;line-height:1.3333333;margin-bottom:1.0666667em;margin-top:1.8666667em}.lg\:prose-lg :where(h3):not(:where([class~=not-prose] *)){font-size:1.3333333em;line-height:1.5;margin-bottom:.6666667em;margin-top:1.6666667em}.lg\:prose-lg :where(h4):not(:where([class~=not-prose] *)){line-height:1.5555556;margin-bottom:.4444444em;margin-top:1.7777778em}.lg\:prose-lg :where(img):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.lg\:prose-lg :where(video):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.lg\:prose-lg :where(figure):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.lg\:prose-lg :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.lg\:prose-lg :where(figcaption):not(:where([class~=not-prose] *)){font-size:.8888889em;line-height:1.5;margin-top:1em}.lg\:prose-lg :where(code):not(:where([class~=not-prose] *)){font-size:.8888889em}.lg\:prose-lg :where(h2 code):not(:where([class~=not-prose] *)){font-size:.8666667em}.lg\:prose-lg :where(h3 code):not(:where([class~=not-prose] *)){font-size:.875em}.lg\:prose-lg :where(pre):not(:where([class~=not-prose] *)){border-radius:.375rem;font-size:.8888889em;line-height:1.75;margin-bottom:2em;margin-top:2em;padding:1em 1.5em}.lg\:prose-lg :where(ol):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-left:1.5555556em}.lg\:prose-lg :where(ul):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-left:1.5555556em}.lg\:prose-lg :where(li):not(:where([class~=not-prose] *)){margin-bottom:.6666667em;margin-top:.6666667em}.lg\:prose-lg :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.4444444em}.lg\:prose-lg :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.4444444em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.lg\:prose-lg :where(.lg\:prose-lg>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.lg\:prose-lg :where(.lg\:prose-lg>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.lg\:prose-lg :where(.lg\:prose-lg>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.lg\:prose-lg :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.lg\:prose-lg :where(hr):not(:where([class~=not-prose] *)){margin-bottom:3.1111111em;margin-top:3.1111111em}.lg\:prose-lg :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(table):not(:where([class~=not-prose] *)){font-size:.8888889em;line-height:1.5}.lg\:prose-lg :where(thead th):not(:where([class~=not-prose] *)){padding-bottom:.75em;padding-left:.75em;padding-right:.75em}.lg\:prose-lg :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.lg\:prose-lg :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.lg\:prose-lg :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.75em}.lg\:prose-lg :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.lg\:prose-lg :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.lg\:prose-lg :where(.lg\:prose-lg>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.lg\:prose-lg :where(.lg\:prose-lg>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.lg\:px-16{padding-left:4rem;padding-right:4rem}}@media (min-width:1280px){.xl\:-mx-56{margin-left:-14rem;margin-right:-14rem}.xl\:my-4{margin-bottom:1rem;margin-top:1rem}.xl\:inline{display:inline}.xl\:w-1\/2{width:50%}.xl\:max-w-\[900px\]{max-width:900px}.xl\:py-20{padding-bottom:5rem;padding-top:5rem}.xl\:text-6xl{font-size:3.75rem;line-height:1}.xl\:text-2xl{font-size:1.5rem;line-height:2rem}.xl\:text-base{font-size:1rem;line-height:1.5rem}}@media (min-width:1536px){.\32xl\:w-\[700px\]{width:700px}.\32xl\:max-w-\[1000px\]{max-width:1000px}.\32xl\:prose-lg{font-size:1.125rem;line-height:1.7777778}.\32xl\:prose-lg :where(p):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em}.\32xl\:prose-lg :where([class~=lead]):not(:where([class~=not-prose] *)){font-size:1.2222222em;line-height:1.4545455;margin-bottom:1.0909091em;margin-top:1.0909091em}.\32xl\:prose-lg :where(blockquote):not(:where([class~=not-prose] *)){margin-bottom:1.6666667em;margin-top:1.6666667em;padding-left:1em}.\32xl\:prose-lg :where(h1):not(:where([class~=not-prose] *)){font-size:2.6666667em;line-height:1;margin-bottom:.8333333em;margin-top:0}.\32xl\:prose-lg :where(h2):not(:where([class~=not-prose] *)){font-size:1.6666667em;line-height:1.3333333;margin-bottom:1.0666667em;margin-top:1.8666667em}.\32xl\:prose-lg :where(h3):not(:where([class~=not-prose] *)){font-size:1.3333333em;line-height:1.5;margin-bottom:.6666667em;margin-top:1.6666667em}.\32xl\:prose-lg :where(h4):not(:where([class~=not-prose] *)){line-height:1.5555556;margin-bottom:.4444444em;margin-top:1.7777778em}.\32xl\:prose-lg :where(img):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.\32xl\:prose-lg :where(video):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.\32xl\:prose-lg :where(figure):not(:where([class~=not-prose] *)){margin-bottom:1.7777778em;margin-top:1.7777778em}.\32xl\:prose-lg :where(figure>*):not(:where([class~=not-prose] *)){margin-bottom:0;margin-top:0}.\32xl\:prose-lg :where(figcaption):not(:where([class~=not-prose] *)){font-size:.8888889em;line-height:1.5;margin-top:1em}.\32xl\:prose-lg :where(code):not(:where([class~=not-prose] *)){font-size:.8888889em}.\32xl\:prose-lg :where(h2 code):not(:where([class~=not-prose] *)){font-size:.8666667em}.\32xl\:prose-lg :where(h3 code):not(:where([class~=not-prose] *)){font-size:.875em}.\32xl\:prose-lg :where(pre):not(:where([class~=not-prose] *)){border-radius:.375rem;font-size:.8888889em;line-height:1.75;margin-bottom:2em;margin-top:2em;padding:1em 1.5em}.\32xl\:prose-lg :where(ol):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-left:1.5555556em}.\32xl\:prose-lg :where(ul):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em;margin-top:1.3333333em;padding-left:1.5555556em}.\32xl\:prose-lg :where(li):not(:where([class~=not-prose] *)){margin-bottom:.6666667em;margin-top:.6666667em}.\32xl\:prose-lg :where(ol>li):not(:where([class~=not-prose] *)){padding-left:.4444444em}.\32xl\:prose-lg :where(ul>li):not(:where([class~=not-prose] *)){padding-left:.4444444em}.\32xl\:prose-lg :where(.\32xl\:prose-lg>ul>li p):not(:where([class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.\32xl\:prose-lg :where(.\32xl\:prose-lg>ul>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.\32xl\:prose-lg :where(.\32xl\:prose-lg>ul>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.\32xl\:prose-lg :where(.\32xl\:prose-lg>ol>li>:first-child):not(:where([class~=not-prose] *)){margin-top:1.3333333em}.\32xl\:prose-lg :where(.\32xl\:prose-lg>ol>li>:last-child):not(:where([class~=not-prose] *)){margin-bottom:1.3333333em}.\32xl\:prose-lg :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose] *)){margin-bottom:.8888889em;margin-top:.8888889em}.\32xl\:prose-lg :where(hr):not(:where([class~=not-prose] *)){margin-bottom:3.1111111em;margin-top:3.1111111em}.\32xl\:prose-lg :where(hr+*):not(:where([class~=not-prose] *)){margin-top:0}.\32xl\:prose-lg :where(h2+*):not(:where([class~=not-prose] *)){margin-top:0}.\32xl\:prose-lg :where(h3+*):not(:where([class~=not-prose] *)){margin-top:0}.\32xl\:prose-lg :where(h4+*):not(:where([class~=not-prose] *)){margin-top:0}.\32xl\:prose-lg :where(table):not(:where([class~=not-prose] *)){font-size:.8888889em;line-height:1.5}.\32xl\:prose-lg :where(thead th):not(:where([class~=not-prose] *)){padding-bottom:.75em;padding-left:.75em;padding-right:.75em}.\32xl\:prose-lg :where(thead th:first-child):not(:where([class~=not-prose] *)){padding-left:0}.\32xl\:prose-lg :where(thead th:last-child):not(:where([class~=not-prose] *)){padding-right:0}.\32xl\:prose-lg :where(tbody td,tfoot td):not(:where([class~=not-prose] *)){padding:.75em}.\32xl\:prose-lg :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose] *)){padding-left:0}.\32xl\:prose-lg :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose] *)){padding-right:0}.\32xl\:prose-lg :where(.\32xl\:prose-lg>:first-child):not(:where([class~=not-prose] *)){margin-top:0}.\32xl\:prose-lg :where(.\32xl\:prose-lg>:last-child):not(:where([class~=not-prose] *)){margin-bottom:0}.\32xl\:px-32{padding-left:8rem;padding-right:8rem}} \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..84555a3 Binary files /dev/null and b/favicon.ico differ diff --git a/fonts/JetBrainsMono-Bold.woff2 b/fonts/JetBrainsMono-Bold.woff2 new file mode 100644 index 0000000..4917f43 Binary files /dev/null and b/fonts/JetBrainsMono-Bold.woff2 differ diff --git a/fonts/JetBrainsMono-BoldItalic.woff2 b/fonts/JetBrainsMono-BoldItalic.woff2 new file mode 100644 index 0000000..536d3f7 Binary files /dev/null and b/fonts/JetBrainsMono-BoldItalic.woff2 differ diff --git a/fonts/JetBrainsMono-ExtraBold.woff2 b/fonts/JetBrainsMono-ExtraBold.woff2 new file mode 100644 index 0000000..8f88c54 Binary files /dev/null and b/fonts/JetBrainsMono-ExtraBold.woff2 differ diff --git a/fonts/JetBrainsMono-ExtraBoldItalic.woff2 b/fonts/JetBrainsMono-ExtraBoldItalic.woff2 new file mode 100644 index 0000000..d1478ba Binary files /dev/null and b/fonts/JetBrainsMono-ExtraBoldItalic.woff2 differ diff --git a/fonts/JetBrainsMono-Italic.woff2 b/fonts/JetBrainsMono-Italic.woff2 new file mode 100644 index 0000000..d60c270 Binary files /dev/null and b/fonts/JetBrainsMono-Italic.woff2 differ diff --git a/fonts/JetBrainsMono-Light.woff2 b/fonts/JetBrainsMono-Light.woff2 new file mode 100644 index 0000000..6538498 Binary files /dev/null and b/fonts/JetBrainsMono-Light.woff2 differ diff --git a/fonts/JetBrainsMono-LightItalic.woff2 b/fonts/JetBrainsMono-LightItalic.woff2 new file mode 100644 index 0000000..66ca3d2 Binary files /dev/null and b/fonts/JetBrainsMono-LightItalic.woff2 differ diff --git a/fonts/JetBrainsMono-Medium.woff2 b/fonts/JetBrainsMono-Medium.woff2 new file mode 100644 index 0000000..669d04c Binary files /dev/null and b/fonts/JetBrainsMono-Medium.woff2 differ diff --git a/fonts/JetBrainsMono-MediumItalic.woff2 b/fonts/JetBrainsMono-MediumItalic.woff2 new file mode 100644 index 0000000..80cfd15 Binary files /dev/null and b/fonts/JetBrainsMono-MediumItalic.woff2 differ diff --git a/fonts/JetBrainsMono-Regular.woff2 b/fonts/JetBrainsMono-Regular.woff2 new file mode 100644 index 0000000..40da427 Binary files /dev/null and b/fonts/JetBrainsMono-Regular.woff2 differ diff --git a/fonts/JetBrainsMono-SemiBold.woff2 b/fonts/JetBrainsMono-SemiBold.woff2 new file mode 100644 index 0000000..5ead7b0 Binary files /dev/null and b/fonts/JetBrainsMono-SemiBold.woff2 differ diff --git a/fonts/JetBrainsMono-SemiBoldItalic.woff2 b/fonts/JetBrainsMono-SemiBoldItalic.woff2 new file mode 100644 index 0000000..c5dd294 Binary files /dev/null and b/fonts/JetBrainsMono-SemiBoldItalic.woff2 differ diff --git a/footnotes.js b/footnotes.js new file mode 100644 index 0000000..343e663 --- /dev/null +++ b/footnotes.js @@ -0,0 +1,20 @@ +// Workaround to support footnotes within the Markdown parser +// Ref: github.com/raphlinus/pulldown-cmark/issues/142 + +const references = document.getElementsByClassName("footnote-reference") + +for (const reference of references) { + const link = reference.firstChild + const id = link.getAttribute("href").slice(1) // skip the '#' + link.setAttribute("id", `${id}_ref`) +} + +const footnotes = document.getElementsByClassName("footnote-definition") + +for (const footnote of footnotes) { + const id = footnote.getAttribute("id") + const backReference = document.createElement("a") + backReference.setAttribute("href", `#${id}_ref`) + backReference.textContent = "↩" + footnote.append(backReference) +} diff --git a/humans.txt b/humans.txt new file mode 100644 index 0000000..8d5c5a5 --- /dev/null +++ b/humans.txt @@ -0,0 +1,47 @@ +heyo, nice to meet you! + +this website is powered by Zola (getzola.org), Tailwind (tailwindcss.com) and Markdown. + +name: DiĂ©ssica Gurskas +email: hey at this domain +twitter: @diessicode +location: Berlin, DE +humans.txt last updated: 01-07-2023 + +tschĂŒĂŸ! +𝔡𝔩𝔱𝔰𝔰 + + + ..^~7JGPP#########&&&#################&&&&&&&&&&G7:.......:::::::::::::::^^ + .:~??JPBB######BBBB####BBBBBBBBGGGBB###&&&&&&&&&&G7:......:::::::::::::::^^ + ::!JP#B###BBBGGGPPPGGGGGP5555555PPPPGB##&&&&&&&&&&G?!^:..::::::::::::::::^^ + ^!!7P###GP55YYYJJYYYYYYYJJJ????JJJYY5PGB##&&&&&&&&BJ?7~^:::::::::::::::::^^ + .^J5J!JBBPYJJJJJJJJ????????????????7777?JYPGB&&&&&&&GJJ7~7^::::::::::::::::^^ +:.. .~YPGPYJPPYJJJJJJJJJ????????7?????????7777??YPB#&&&&#GGJ?^!~::::::::::::::^^^^ +7!^:.. ..^7YGBGGGBGY?JJJJJJJJ???????777????????7777777JPB#&&&&BG5J!~~:::::::::^^^^^^^^^ +7!^::. ....^7JPGGBB#BY???JJJJJJ?????????77777777777777777?YG#&&&&&##PJ7~:::::::^^^^^^^^^^~ +!~^:. .~?JY5GBBBP!!?????????????7???77777777777777777?JPB&&&&#BB5J7^:::::::::^^^^^^~~~ +~~::. ...:::^!???JPGGPJ^:!?JJJJJJJ?????????????JJJJJYYYYJ???JPB#&&#BG5J?!^^::::^^^:::^^^^^^^ +~^::. ~?JJJJJJJJ?????JJ??7~~!?J5PPPP5YYJJJ???JJY5PGBBBBBGP55YJY5GB#&#BG57!~!?YJ?7!JJ?7!7~^^^^^^ +~^:.. !555YYYJJJJJJYYJJJJ??????YPGBGGGPY?!7?JJJ5PGBBGGGBBBPPPPPPPPG##BBG?!^^^~?Y5555YYJJJJ7!~^^^ +~^:.. .!YYYYYYYYYYYYYYYYYYY5YJJ5PGB###BBBBP5PGGGBB###BBBBBBBBB##&&&#BGP55J!^::::::~J5PPP55YYJJJ?7! +~^:. !Y55YY555YYYYYJ?7!~755Y!JGG5GB########GPY5GB&&&&&&&&&&&&&&&&&GPJ?!^~~^^::::~!!~~7J5PPP55PP5Y +~^:. .~Y55555P555YYJ!:...::~YJ!!5B###########B5JJ5G#&##&&&&&&&&&&&&GYJ!^::^^^^...:^:....:^!JYPGGGPP +~^:. .~J555555555Y!:. .:..~?7^?PB#########BPJ?7?5G#&&&&&&&&&#&&#BY7!^:::::::.......:::::::^~?5PGG +^::. :J55YY55555Y!. .. .~7?5G########BPYJ?777YPB#&&&&&&&&&BP?7~^^^^::::::::::::^:::::::::^!J5 +^:...?55YYYYY555J~. .:^~!?JYPGBBBBGP55YJ??7777JY5PGBBBBGPY?7~~~^::::::::::::^::::::::::::::^~ +^:..:Y5YYYYYYYYYYY?~. ..^~7????77777??JJJJJJJJ?777777?JJJJJJJ?77!!~^:^::::::::::::::::::::::^^~7?Y5 +~::.^55YYYJJJYYYYYJJ?777???????7!!~^:~7????JJJJJ??77???JJJJJJ??7!!~^:::::::::::::::::^^::::^^~J5PGPP +~::.75YYJJJJJYYJJJJ???????77??JYJJY7^:!???JJJJYYJJJ??????JJJ??77!~:::::::::::::::::::^^^^^^~?5PPPGPP +^:.:?YYJJJJJJJJJ????777777J5GGB####J7^:!JJJYYYYYYJJJJJJJYYYJJ?7~:::::::::::::::::::::~^^^^75PPPP5YJY +^:.~JYJ??????JJ??7777777JPB#BB#####G77!^!YYY55PPP55P5555Y55YJ777^:...:::::::::::::::.^!~~JPGPP5Y?JPG +^::7YYJ????????77777777JB#BBBB######G?77!7JYYY5555555YYJJJJJ7~7##G?7~:.:::::::::::::..~?5PPP5YY5PGPP +^:^JYJJ????????7!!!!775BBBBBBBBBBB###BY???7?JJJJJJJJJJJ????7!!P&&&&&&P7^::::::::::::.:?GGGG55PGGPP5Y +^^?YJJJ????777777777JGBBBBBBBBBBBBBB###GY??7??JJJJJJJJJJ??7!7G&&&&&&&&&B5J!~^^::::::::!YPYPPGP5J?7!~ +^!JJJ??????????77?YPBBBBBBGGBBBBBBBBB####B5J?77??????????77YB&&&&&&&&&&&&&&##BGY7~:.::..7J???!^^^~~~ +7JJJJ???????????5GBBBBBBBBGBBBBBBBBBBBB#####BPYJ???????JYPB&&&&&&&&&&&&&&&&&&&&&&#G?:...:?7:^!!!!!!! +JJJJJ??????????PBGGBBBBBBBBBBBBBBBBBBBBBB####&&##BBGGBB#&&&&&&&&&&&&&&&&&&&&&&&&&@@&5^...^7777?7777! +JJJJ??????777?PBGGGGGGBBBGBBBBBBBBBBBBBBB#######&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&@@@@@&J::::!7!!!!7!!! +JJJJ??????77?5BGGGGGGGGGGGGBGBBBBBBBBBBBBBB#########&&&&&&&&&&&&&&&&&&&&&&@@@@@@@@@@&B7^~!7??!~~^~~~ +JJJ???77777?JGBBGGGGGGGGGGGGGGGGGGBBBBBBBBBBB##########&&&&&&&&&&&&&&&&&&&@@@@@@@@@&&&P~!7!?5Y?7!?J7 +JJJ???77777?5GBBBBGGGGGGGGGGGGGGGGGBBBBBBBBBBB##########&&&&&&&&&&&&&&&&&&@@@@@@@@&&@&&57J7!?5P5JJ?? \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..4e1ecb5 --- /dev/null +++ b/index.html @@ -0,0 +1 @@ +Home | DiĂ©ssica Gurskas
diessi.caBlog

I'm DiĂ©ssica Gurskas. 👋
I immerse myself in nature, sound, cycling, and the wonders of human-computer interaction.

I'm based in ever-changing Berlin, but grew up in never-changing ViamĂŁo, a humble town in Brazil which taught me to be resourceful. Whether it was making kites out of bags and twigs, playing DIY football and cricket on muddy dirt roads, or ringing neighbors' doorbells and dashing away, I hacked whatever came my way.

That ultimately led me to unearth a fascination for computers. Back when I hacked my first game and setup a pirate server just so everything was free, I felt empowered by how computers could help solve our problems. Coming of age, I also realised how they may create new ones. 😉

Having honed my skills, and developed a passion for audio along the way, I am nowadays a Lead Software Engineer at Native Instruments. I manage web architecture and operations for leading audio brands, including iZotope.

Raised by the internet, I wholeheartedly support and draw on open knowledge to teach myself, experiment, and have fun. I wish nothing but for everyone to empower themselves towards never-ending exploration as I do.

____
\ No newline at end of file diff --git a/keybase.txt b/keybase.txt new file mode 100644 index 0000000..6f95a96 --- /dev/null +++ b/keybase.txt @@ -0,0 +1,75 @@ +================================================================== +https://keybase.io/diessica +-------------------------------------------------------------------- + +I hereby claim: + + * I am an admin of https://diessi.ca + * I am diessica (https://keybase.io/diessica) on keybase. + * I have a public key with fingerprint 4302 C586 30C5 2251 35E4 07A4 449A A724 D631 01B2 + +To do so, I am signing this object: + +{ + "body": { + "key": { + "eldest_kid": "0120c2ee894d3a532403315abd1286e80ee3245566c9405b35f3078835f66d6bd0600a", + "fingerprint": "4302c58630c5225135e407a4449aa724d63101b2", + "host": "keybase.io", + "key_id": "449aa724d63101b2", + "kid": "01018fbb8563b64f4402fda4c9a56f78869299b72a4407dd248da57eb55d6925a35a0a", + "uid": "80c2b902f6438ee3657715451871c819", + "username": "diessica" + }, + "service": { + "hostname": "diessi.ca", + "protocol": "https:" + }, + "type": "web_service_binding", + "version": 1 + }, + "ctime": 1537532089, + "expire_in": 157680000, + "prev": "95359140301f30e8c90770914e96635bbd95cb78bbdddb134083e30667dfa6c1", + "seqno": 12, + "tag": "signature" +} + +which yields the signature: + +-----BEGIN PGP MESSAGE----- +Version: Keybase OpenPGP v2.0.77 +Comment: https://keybase.io/crypto + +yMNqAnicbVJtUFRVGF6EdFgiMTAl+oAbLtUweO7HOffeNRgto7XBicKSEKH7cRZu +wO66u4CAFMFMSfFhBKMhGiAOTskIC0RkRiwoQ9pAOSLWEA3gyqhTjhSZY2PnMvmj +mc6fc85znvd5n/d9z3Cwv8Hot7mxPXqC9vP4nR1syDfsaPulv4SS7WoRZS6hcvDS +hnNV7HJn5mgqZaYAzQCFwVgQOZWVIMtwgGVpKMkqzQgICwBjgkGIkCJyAMostLKA +FwSyI6QiWQUIAImKpayaLQs7HU7N5iayHAsYBQqIBQpkGEizEHOAlziOEyWJZzgV +sTSgZYYEZttdegQxJ0suHKfZCUYumUv2/od/zzegBassCxCxMuKsHAcYqypxiihB +ZCUGkciIoswzJCfgVZXhBFWCPJYhVMkTlFgoLfnOX5ITSBNkkUggjhVIyQjyPA05 +SAs8rQi0qBNd2GmT8jBhqxp2uTRFokpjKYIWaArWG6tX8h9GnKJncDjtbrtizyVw +ttvtcJn1MHeRQ+cVYjnzX4VMWbOppIkkogA7XZrdRplpwlTcmi5JQ5Yn4wGCGEvh +3Q7NiTM1nQF5JACy9Dy4gEiKkIUiTcYIaDIqLCgi4HlAECwixEJZVkWoyLxADqoq +0ywHBBazACFetUpIoSm9pl02O9FmiE8pi2i6tCyb5M53YqrUO5geYPAzGpbft0z/ +XQZjYMi9P7cpbeXd10xPUlOJ7M6X0ZzDKuR8MljYmTbRXhNQVPpYbfTC1FMR/ft9 +ZysivftOj8SMmR+vsFjuH2I+77llCtucimP6Vvkvjn31gKdt/Ofuvrc/rHm1abYh +4JszdsvMTOSj246FKRGtXZVtizfWRf4d5b5WL09F7blZZWru2edsWJNqA8sPxIfP +H84oX1EX/oG5bNOLp0IXa3qvzo9Om/fYZs99Gz139NKl7dcTfeGPPON/OHDhN+6L +zEVDrGHibkXr8bKxopzU4e0nSs7d7H33jfJXOioDa7s6Lkgpd0YO5K3N9VXnGoYH +G93rx4wZzbDr1MD+qihTYuSAJez1o9lx3ts7j0e4R9NMGbOr+6ON7X1bt/zUUtq4 +IyXgZPVFPHrEkpLv+DQr4dC6pqDP4v5YnVD3+3Mjbe8EN4QdrFzono6cMjXKxlFP +yY/jH3188mIzZ/1OzO59KTg5uS7/0KJ7Rdn56yL0DXWWdbzXWvy8OFn7q8t6Z/72 +KvEhYauB9Wz4emHt1Rso1DZXdWXgzxy4N967e3JXQnfY+72pz04e63ki1JN8q1O7 +4mssMBkdnrfe/EE0FCSJ4wdDQpo2/uXtbCu8Nj/ul/Rluq9mZkNxYOlkkpeq4IPM +l20PWloy1mysX7klt379GZweH1LtudySmtcaM70Q9HTMhaETxS+cfrjl+2Urj5wv +74lHe7O5bf8A+5q5NQ== +=mYMo +-----END PGP MESSAGE----- + +And finally, I am proving ownership of this host by posting or +appending to this document. + +View my publicly-auditable identity here: https://keybase.io/diessica + +================================================================== diff --git a/media/2015/knowledge-diagram.png b/media/2015/knowledge-diagram.png new file mode 100644 index 0000000..7ba8fb7 Binary files /dev/null and b/media/2015/knowledge-diagram.png differ diff --git a/media/2015/knowledge-diagram_2x.png b/media/2015/knowledge-diagram_2x.png new file mode 100644 index 0000000..a76b185 Binary files /dev/null and b/media/2015/knowledge-diagram_2x.png differ diff --git a/media/2015/moinhos-de-vento.jpg b/media/2015/moinhos-de-vento.jpg new file mode 100644 index 0000000..15746e4 Binary files /dev/null and b/media/2015/moinhos-de-vento.jpg differ diff --git a/media/2015/moinhos-de-vento_medium.jpg b/media/2015/moinhos-de-vento_medium.jpg new file mode 100644 index 0000000..0b43db5 Binary files /dev/null and b/media/2015/moinhos-de-vento_medium.jpg differ diff --git a/media/2015/moinhos-de-vento_small.jpg b/media/2015/moinhos-de-vento_small.jpg new file mode 100644 index 0000000..2f70dbd Binary files /dev/null and b/media/2015/moinhos-de-vento_small.jpg differ diff --git a/media/2016/twelfth-floor.jpg b/media/2016/twelfth-floor.jpg new file mode 100644 index 0000000..9da1a68 Binary files /dev/null and b/media/2016/twelfth-floor.jpg differ diff --git a/media/2016/twelfth-floor_medium.jpg b/media/2016/twelfth-floor_medium.jpg new file mode 100644 index 0000000..06fd4f9 Binary files /dev/null and b/media/2016/twelfth-floor_medium.jpg differ diff --git a/media/2016/twelfth-floor_small.jpg b/media/2016/twelfth-floor_small.jpg new file mode 100644 index 0000000..f891fb2 Binary files /dev/null and b/media/2016/twelfth-floor_small.jpg differ diff --git a/media/2017/catalysis-diagram.png b/media/2017/catalysis-diagram.png new file mode 100644 index 0000000..537bebc Binary files /dev/null and b/media/2017/catalysis-diagram.png differ diff --git a/media/2017/catalysis-diagram_2x.png b/media/2017/catalysis-diagram_2x.png new file mode 100644 index 0000000..cd2750f Binary files /dev/null and b/media/2017/catalysis-diagram_2x.png differ diff --git a/media/2017/dad-2005.jpg b/media/2017/dad-2005.jpg new file mode 100644 index 0000000..fe31265 Binary files /dev/null and b/media/2017/dad-2005.jpg differ diff --git a/media/2017/macos_desktop.mp4 b/media/2017/macos_desktop.mp4 new file mode 100644 index 0000000..df4d2fc Binary files /dev/null and b/media/2017/macos_desktop.mp4 differ diff --git a/media/2017/noorder-amstelkanaal.jpg b/media/2017/noorder-amstelkanaal.jpg new file mode 100644 index 0000000..ea12634 Binary files /dev/null and b/media/2017/noorder-amstelkanaal.jpg differ diff --git a/media/2017/noorder-amstelkanaal_medium.jpg b/media/2017/noorder-amstelkanaal_medium.jpg new file mode 100644 index 0000000..c0e14f0 Binary files /dev/null and b/media/2017/noorder-amstelkanaal_medium.jpg differ diff --git a/media/2017/noorder-amstelkanaal_small.jpg b/media/2017/noorder-amstelkanaal_small.jpg new file mode 100644 index 0000000..8a0114b Binary files /dev/null and b/media/2017/noorder-amstelkanaal_small.jpg differ diff --git a/media/2018/abstract-syntax-tree.png b/media/2018/abstract-syntax-tree.png new file mode 100644 index 0000000..381bd3b Binary files /dev/null and b/media/2018/abstract-syntax-tree.png differ diff --git a/media/2018/benjamin-franklin-routine.jpg b/media/2018/benjamin-franklin-routine.jpg new file mode 100644 index 0000000..3610fdf Binary files /dev/null and b/media/2018/benjamin-franklin-routine.jpg differ diff --git a/media/2018/clicker-flow.jpg b/media/2018/clicker-flow.jpg new file mode 100644 index 0000000..8341170 Binary files /dev/null and b/media/2018/clicker-flow.jpg differ diff --git a/media/2018/creativity.png b/media/2018/creativity.png new file mode 100644 index 0000000..ba0815d Binary files /dev/null and b/media/2018/creativity.png differ diff --git a/media/2018/gurskas-snow.jpg b/media/2018/gurskas-snow.jpg new file mode 100644 index 0000000..19a89c9 Binary files /dev/null and b/media/2018/gurskas-snow.jpg differ diff --git a/media/2018/mary-glass-syntax-tree.png b/media/2018/mary-glass-syntax-tree.png new file mode 100644 index 0000000..940f170 Binary files /dev/null and b/media/2018/mary-glass-syntax-tree.png differ diff --git a/media/2018/sdhv18-badge.jpg b/media/2018/sdhv18-badge.jpg new file mode 100644 index 0000000..d416306 Binary files /dev/null and b/media/2018/sdhv18-badge.jpg differ diff --git a/media/2018/sdhv18-lasers.jpg b/media/2018/sdhv18-lasers.jpg new file mode 100644 index 0000000..da50621 Binary files /dev/null and b/media/2018/sdhv18-lasers.jpg differ diff --git a/media/2018/sdhv18-n2-fire.jpg b/media/2018/sdhv18-n2-fire.jpg new file mode 100644 index 0000000..31a5eb0 Binary files /dev/null and b/media/2018/sdhv18-n2-fire.jpg differ diff --git a/media/2018/sdhv18-prize.jpg b/media/2018/sdhv18-prize.jpg new file mode 100644 index 0000000..6f61e56 Binary files /dev/null and b/media/2018/sdhv18-prize.jpg differ diff --git a/media/2018/sdhv18-spectrogram.jpg b/media/2018/sdhv18-spectrogram.jpg new file mode 100644 index 0000000..afd4eb8 Binary files /dev/null and b/media/2018/sdhv18-spectrogram.jpg differ diff --git a/media/2018/sdhv18-technarium.jpg b/media/2018/sdhv18-technarium.jpg new file mode 100644 index 0000000..c6c4241 Binary files /dev/null and b/media/2018/sdhv18-technarium.jpg differ diff --git a/media/2018/sdhv18-trophies.jpg b/media/2018/sdhv18-trophies.jpg new file mode 100644 index 0000000..1f382c2 Binary files /dev/null and b/media/2018/sdhv18-trophies.jpg differ diff --git a/media/2018/vs-code-stage-selected-changes.png b/media/2018/vs-code-stage-selected-changes.png new file mode 100644 index 0000000..e54d1bc Binary files /dev/null and b/media/2018/vs-code-stage-selected-changes.png differ diff --git a/media/2018/vs-code-writing-mode.png b/media/2018/vs-code-writing-mode.png new file mode 100644 index 0000000..7270aac Binary files /dev/null and b/media/2018/vs-code-writing-mode.png differ diff --git a/media/2018/yellow-bike-lock.jpg b/media/2018/yellow-bike-lock.jpg new file mode 100644 index 0000000..5569811 Binary files /dev/null and b/media/2018/yellow-bike-lock.jpg differ diff --git a/media/2019/guitar-rig-macos-mojave-setup/audio-midi-setup.png b/media/2019/guitar-rig-macos-mojave-setup/audio-midi-setup.png new file mode 100644 index 0000000..a0eed55 Binary files /dev/null and b/media/2019/guitar-rig-macos-mojave-setup/audio-midi-setup.png differ diff --git a/media/2019/guitar-rig-macos-mojave-setup/guitar-rig.png b/media/2019/guitar-rig-macos-mojave-setup/guitar-rig.png new file mode 100644 index 0000000..b69d4e3 Binary files /dev/null and b/media/2019/guitar-rig-macos-mojave-setup/guitar-rig.png differ diff --git a/media/2019/omg-climate/discussion.jpg b/media/2019/omg-climate/discussion.jpg new file mode 100644 index 0000000..28f3e05 Binary files /dev/null and b/media/2019/omg-climate/discussion.jpg differ diff --git a/media/2019/omg-climate/global-warming-nasa.gif b/media/2019/omg-climate/global-warming-nasa.gif new file mode 100644 index 0000000..ac7d6fb Binary files /dev/null and b/media/2019/omg-climate/global-warming-nasa.gif differ diff --git a/media/2019/omg-climate/green-mafia.jpg b/media/2019/omg-climate/green-mafia.jpg new file mode 100644 index 0000000..6402e3e Binary files /dev/null and b/media/2019/omg-climate/green-mafia.jpg differ diff --git a/media/2019/omg-climate/low-carbon.jpg b/media/2019/omg-climate/low-carbon.jpg new file mode 100644 index 0000000..0111bce Binary files /dev/null and b/media/2019/omg-climate/low-carbon.jpg differ diff --git a/media/2019/omg-climate/presentation.jpg b/media/2019/omg-climate/presentation.jpg new file mode 100644 index 0000000..7f35a23 Binary files /dev/null and b/media/2019/omg-climate/presentation.jpg differ diff --git a/media/2020/bullet-journal.jpg b/media/2020/bullet-journal.jpg new file mode 100644 index 0000000..e21f89e Binary files /dev/null and b/media/2020/bullet-journal.jpg differ diff --git a/robots.txt b/robots.txt new file mode 100644 index 0000000..49b6b2e --- /dev/null +++ b/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Disallow: +Allow: / +Sitemap: /sitemap.xml diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..520d090 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,262 @@ + + + + / + + + /blog/ + + + /blog/5-bibliotecas-essenciais-para-desenvolver-react-apps/ + 2016-03-21T23:00:00 + + + /blog/a-better-es2015-and-jsx-workflow-in-vs-code/ + 2016-10-30T00:00:00 + + + /blog/a-bit-on-random-numbers-in-javascript/ + 2016-11-15T16:50:00 + + + /blog/a-cascata-das-variaveis-do-css/ + 2016-05-30T22:00:00 + + + /blog/a-fantastica-diversidade-do-front-end/ + 2016-04-09T15:10:00 + + + /blog/a-guide-to-favicons-and-touch-icons/ + 2015-09-06T10:53:00 + + + /blog/a-minimal-workspace-on-macos/ + 2017-05-04T19:45:57 + + + /blog/archive/i-travelled-to-photographs/ + 2017-04-19T10:13:00 + + + /blog/catalysis/ + 2017-04-13T11:27:00 + + + /blog/choose-life-in-berlin/ + 2017-05-12T19:15:00 + + + /blog/como-eu-vi-a-braziljs-2015/ + 2015-08-26T02:10:32 + + + /blog/computer-and-human-languages/ + 2018-06-20T18:06:00 + + + /blog/creativity/ + 2018-02-05T21:25:00 + + + /blog/dental-health-and-habits/ + 2017-12-21T08:58:09 + + + /blog/desmitificando-seletores-complexos/ + 2013-11-28 + + + /blog/dont-blame-it-on-react-or-redux/ + 2017-03-18T13:49:00 + + + /blog/encadeamento-de-metodos-em-javascript/ + 2016-08-06T16:11:32 + + + /blog/expressive-javascript-conditionals/ + 2017-10-30 + + + /blog/extra/ + + + /blog/fetch-npm-package-without-npm-install/ + 2024-08-25T16:30:00 + + + /blog/guitar-rig-macos-mojave-setup/ + 2019-08-18T22:19:05 + + + /blog/horizontal-and-vertical-align-anything-with-css/ + 2016-11-06T19:10:01 + + + /blog/how-i-lock-my-bike-in-berlin/ + 2018-08-30T07:00:00 + + + /blog/how-to-exclude-css-images-anything-from-unit-tests/ + 2016-11-19T09:54:29 + + + /blog/how-to-spy-on-a-prop-with-jest/ + 2019-10-31T14:15:42 + + + /blog/i-m-tired-of-beautiful-looking-interfaces/ + 2016-10-23T12:50:35 + + + /blog/isolation-tank/ + 2018-12-02T08:01:00 + + + /blog/journaling/ + 2020-04-20T00:10:15 + + + /blog/long-time-no-see/ + 2023-06-30T11:19:00 + + + /blog/mass-deleting-files-from-slack/ + 2016-04-17T00:10:15 + + + /blog/multiline-sass-comments/ + 2015-08-17 + + + /blog/my-hacking-adventure-in-lithuania/ + 2018-02-15 + + + /blog/o-css-do-futuro/ + 2016-05-29T23:21:51 + + + /blog/o-que-ha-de-errado-com-a-cultura-jquery/ + 2015-09-20T09:56:05 + + + /blog/o-til-no-javascript/ + 2015-10-31 + + + /blog/omg-climate/ + 2019-05-30T11:39:14 + + + /blog/react-and-form-management-is-redux-form-worth-it/ + 2018-05-21T18:14:00 + + + /blog/shared-variables-between-javascript-and-css/ + 2017-01-15T15:00:00 + + + /blog/svg-images-as-react-components-with-webpack/ + 2016-08-02T22:00:00 + + + /blog/tchau/ + 2017-05-13T16:12:00 + + + /blog/the-bitter-reality-of-ebooks/ + 2023-08-16T13:55:00 + + + /blog/ttt/ + 2018-04-01T23:36:00 + + + /blog/ui-components-that-abstract-mistakes/ + 2017-10-14T18:06:00 + + + /blog/var-that-this-nah/ + 2017-03-15T09:00:00 + + + /blog/we-misunderstand-learning/ + 2024-09-19T13:13:42 + + + /blog/working-better-with-git-for-a-clear-history/ + 2018-08-04T07:00:00 + + + /blog/writing-mode-in-vs-code/ + 2018-02-28T02:30:00 + + + /tags/ + + + /tags/activism/ + + + /tags/books/ + + + /tags/climate-change/ + + + /tags/css/ + + + /tags/design/ + + + /tags/digital-rights/ + + + /tags/essay/ + + + /tags/html/ + + + /tags/javascript/ + + + /tags/language/ + + + /tags/music/ + + + /tags/personal/ + + + /tags/productivity/ + + + /tags/pt-br/ + + + /tags/react/ + + + /tags/script/ + + + /tags/software/ + + + /tags/test/ + + + /tags/travel/ + + + /tags/work/ + + + /tags/workflow/ + + diff --git a/tags/activism/index.html b/tags/activism/index.html new file mode 100644 index 0000000..d9a4a67 --- /dev/null +++ b/tags/activism/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: activism

OMG Climate: Reflecting Together on the Climate Catastrophe

[current_path](/tags/activism/)
\ No newline at end of file diff --git a/tags/books/index.html b/tags/books/index.html new file mode 100644 index 0000000..14c71ff --- /dev/null +++ b/tags/books/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: books

The Bitter Reality of Ebooks and the Kindle Model

[current_path](/tags/books/)
\ No newline at end of file diff --git a/tags/climate-change/index.html b/tags/climate-change/index.html new file mode 100644 index 0000000..bb9c25f --- /dev/null +++ b/tags/climate-change/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: climate change

OMG Climate: Reflecting Together on the Climate Catastrophe

[current_path](/tags/climate-change/)
\ No newline at end of file diff --git a/tags/css/index.html b/tags/css/index.html new file mode 100644 index 0000000..93abb1b --- /dev/null +++ b/tags/css/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: css

Shared Variables Between JavaScript and CSS

Horizontal and Vertical Align Anything with CSS

A Cascata das VariĂĄveis do CSS

O CSS do Futuro

Multiline Sass Comments

Desmitificando Seletores Complexos

[current_path](/tags/css/)
\ No newline at end of file diff --git a/tags/design/index.html b/tags/design/index.html new file mode 100644 index 0000000..4bfc899 --- /dev/null +++ b/tags/design/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: design

I'm Tired of Beautiful-Looking User Interfaces

[current_path](/tags/design/)
\ No newline at end of file diff --git a/tags/digital-rights/index.html b/tags/digital-rights/index.html new file mode 100644 index 0000000..4aea1b8 --- /dev/null +++ b/tags/digital-rights/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: digital rights

The Bitter Reality of Ebooks and the Kindle Model

[current_path](/tags/digital-rights/)
\ No newline at end of file diff --git a/tags/essay/index.html b/tags/essay/index.html new file mode 100644 index 0000000..4f22ca6 --- /dev/null +++ b/tags/essay/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: essay

Creativity

[current_path](/tags/essay/)
\ No newline at end of file diff --git a/tags/html/index.html b/tags/html/index.html new file mode 100644 index 0000000..ba9d299 --- /dev/null +++ b/tags/html/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: html

UI Components that Abstract Mistakes

A Guide to Favicons and Touch Icons

[current_path](/tags/html/)
\ No newline at end of file diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 0000000..84717fc --- /dev/null +++ b/tags/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/tags/javascript/index.html b/tags/javascript/index.html new file mode 100644 index 0000000..e456824 --- /dev/null +++ b/tags/javascript/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: javascript

React and Form Management: Is Redux Form Worth It?

Expressive JavaScript Conditionals (for Humans)

UI Components that Abstract Mistakes

Don't Blame it on React or Redux

var that = this? Nah.

Shared Variables Between JavaScript and CSS

How to Exclude CSS, Images, Anything from Unit Tests

A Bit on Random Numbers in JavaScript

Encadeamento de MĂ©todos em JavaScript

SVG Images as React Components with Webpack

5 Bibliotecas Essenciais para Desenvolver React Apps

O Til no JavaScript

O Que HĂĄ de Errado com a "Cultura jQuery"

[current_path](/tags/javascript/)
\ No newline at end of file diff --git a/tags/language/index.html b/tags/language/index.html new file mode 100644 index 0000000..65c5ec5 --- /dev/null +++ b/tags/language/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: language

Computer and Human Languages

[current_path](/tags/language/)
\ No newline at end of file diff --git a/tags/music/index.html b/tags/music/index.html new file mode 100644 index 0000000..e4e13df --- /dev/null +++ b/tags/music/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: music

Setup for Audio Interface with Guitar Rig 5 on macOS Mojave

[current_path](/tags/music/)
\ No newline at end of file diff --git a/tags/personal/index.html b/tags/personal/index.html new file mode 100644 index 0000000..1a54363 --- /dev/null +++ b/tags/personal/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: personal

Long Time No See

What I've Learned by Simply Journaling

I've Sensory-Deprived Myself In a Tank

How I Lock My Bike in Berlin

T. T. T.

My Hacking Adventure in Lithuania

Dental Health and Habits

Tchau

Choose Life đŸ‡©đŸ‡Ș

I Travelled to Photographs

Catalysis

I'm Tired of Beautiful-Looking User Interfaces

Como Eu Vi a BrazilJS 2015

[current_path](/tags/personal/)
\ No newline at end of file diff --git a/tags/productivity/index.html b/tags/productivity/index.html new file mode 100644 index 0000000..a4b26ba --- /dev/null +++ b/tags/productivity/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: productivity

What I've Learned by Simply Journaling

A Minimal Workspace on macOS

[current_path](/tags/productivity/)
\ No newline at end of file diff --git a/tags/pt-br/index.html b/tags/pt-br/index.html new file mode 100644 index 0000000..88c126b --- /dev/null +++ b/tags/pt-br/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: pt-BR

Tchau

Encadeamento de MĂ©todos em JavaScript

A Cascata das VariĂĄveis do CSS

O CSS do Futuro

A FantĂĄstica Diversidade do Front-end

5 Bibliotecas Essenciais para Desenvolver React Apps

O Til no JavaScript

O Que HĂĄ de Errado com a "Cultura jQuery"

Como Eu Vi a BrazilJS 2015

Desmitificando Seletores Complexos

[current_path](/tags/pt-br/)
\ No newline at end of file diff --git a/tags/react/index.html b/tags/react/index.html new file mode 100644 index 0000000..36f792a --- /dev/null +++ b/tags/react/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: react

How to Spy on a React Prop with Jest

React and Form Management: Is Redux Form Worth It?

Don't Blame it on React or Redux

How to Exclude CSS, Images, Anything from Unit Tests

A Better ES2015+ and JSX Workflow in VS Code

SVG Images as React Components with Webpack

5 Bibliotecas Essenciais para Desenvolver React Apps

[current_path](/tags/react/)
\ No newline at end of file diff --git a/tags/script/index.html b/tags/script/index.html new file mode 100644 index 0000000..f1a1f06 --- /dev/null +++ b/tags/script/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: script

Mass Deleting Files from Slack

[current_path](/tags/script/)
\ No newline at end of file diff --git a/tags/software/index.html b/tags/software/index.html new file mode 100644 index 0000000..5ea0a16 --- /dev/null +++ b/tags/software/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: software

Working Better with Git for a Clear History

Computer and Human Languages

[current_path](/tags/software/)
\ No newline at end of file diff --git a/tags/test/index.html b/tags/test/index.html new file mode 100644 index 0000000..4c3a3b5 --- /dev/null +++ b/tags/test/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: test

How to Exclude CSS, Images, Anything from Unit Tests

[current_path](/tags/test/)
\ No newline at end of file diff --git a/tags/travel/index.html b/tags/travel/index.html new file mode 100644 index 0000000..53da6c3 --- /dev/null +++ b/tags/travel/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: travel

I Travelled to Photographs

[current_path](/tags/travel/)
\ No newline at end of file diff --git a/tags/work/index.html b/tags/work/index.html new file mode 100644 index 0000000..7777e2a --- /dev/null +++ b/tags/work/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: work

A FantĂĄstica Diversidade do Front-end

[current_path](/tags/work/)
\ No newline at end of file diff --git a/tags/workflow/index.html b/tags/workflow/index.html new file mode 100644 index 0000000..eb6a172 --- /dev/null +++ b/tags/workflow/index.html @@ -0,0 +1 @@ +
diessi.caBlog
Tag: workflow

Writing Mode in VS Code

A Better ES2015+ and JSX Workflow in VS Code

[current_path](/tags/workflow/)
\ No newline at end of file