<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Matt Dionis on Medium]]></title>
        <description><![CDATA[Stories by Matt Dionis on Medium]]></description>
        <link>https://medium.com/@mattdionis?source=rss-6387214b750d------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*2zlfaE8MTVWdl58ZXAjVeQ.jpeg</url>
            <title>Stories by Matt Dionis on Medium</title>
            <link>https://medium.com/@mattdionis?source=rss-6387214b750d------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 16 May 2026 18:12:00 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@mattdionis/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Unleashing the Power of Data Portability: Empowering Users for an AI-Driven Future]]></title>
            <link>https://medium.com/@mattdionis/unleashing-the-power-of-data-portability-empowering-users-for-an-ai-driven-future-2950da08a53d?source=rss-6387214b750d------2</link>
            <guid isPermaLink="false">https://medium.com/p/2950da08a53d</guid>
            <category><![CDATA[tech]]></category>
            <category><![CDATA[web3]]></category>
            <category><![CDATA[digital-identity]]></category>
            <category><![CDATA[decentralization]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <dc:creator><![CDATA[Matt Dionis]]></dc:creator>
            <pubDate>Tue, 05 Sep 2023 18:18:33 GMT</pubDate>
            <atom:updated>2023-09-05T18:18:33.644Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*x9DTipKTy1M32-KYul2RAQ.png" /><figcaption>Strolling through the city of tomorrow, people wear glowing backpacks highlighting the power of data portability, symbolizing a future where our digital essence travels with us. (Image generated with <a href="https://stability.ai/stablediffusion">Stable Diffusion XL</a>)</figcaption></figure><p>This is the second post in an ongoing series where we discuss <em>“improving how we represent our identities, what we own, and how we pay, play, and engage on the internet.”</em> Building on our first discussion on <a href="https://medium.com/@mattdionis/shaping-a-future-of-digital-privacy-with-llms-and-encrypted-messaging-a9b0f79decfb"><em>“Shaping a Future of Digital Privacy with LLMs and Encrypted Messaging,”</em></a> we next dive into the concept of data portability.</p><h3>Data Portability</h3><h4>Why Data Portability Matters in Today’s Digital Landscape</h4><p>The beginning of the twenty-first century has witnessed the digitization of virtually all data, including personal data, about each of us. This data has quickly evolved from simple information to a lucrative treasure trove for the companies whose products and services we rely on daily. The actual value of this data hinges on its efficient movement, accessibility, and portability. Many modern companies thrive not merely on the products they sell but on the data they accumulate. This shift has led to data-centric business models where the data becomes a revenue stream.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*k6-RVwJA5E-6FXMTC7edNg.png" /><figcaption>Chart <a href="https://www.idc.com/">courtesy of IDC</a> showing the recent growth rate of data creation and replication.</figcaption></figure><p>The concept of data portability is not merely a technical one; it signifies a groundbreaking shift in our perception of digital rights. Platforms have the upper hand over their users, and limited data portability is a key contributor to this power differential. Data portability is about much more than simply data transfer. True data portability would guarantee user empowerment and control and lead to a more nurturing and innovative digital environment. Users should own their digital footprints.</p><h4>Significance of Data Portability</h4><p><em>“Data portability”</em> might seem technical, but its implications deeply touch our personal lives. <a href="https://www.brookings.edu/articles/data-portability-and-interoperability-a-primer-on-two-policy-tools-for-regulation-of-digitized-industries-2/">The Brookings report “Data portability and interoperability: A primer on two policy tools for regulation of digitized industries”</a> defines it as <em>“a user’s ability to move their data from one tech service to another.”</em> This freedom ensures competition thrives, compelling providers to innovate and prioritize user choice.</p><p>However, data portability is even more than that simple explanation can do justice. The past few decades have seen a seismic shift in how we live. From how we communicate, shop, work, and even find love, everything has been transformed by the digital revolution. Central to this transformation is data. Financial juggernauts have been built upon our data. By ensuring data portability, we’re not just talking about a technical feature but about a fundamental right in the digital age. This right may upend the current tech landscape as companies will need to find more innovative ways to attract and retain customers; profiting off their data will no longer be nearly as lucrative.</p><h4>Impact of Data Portability on User Control and Innovation</h4><p>In a liberated ecosystem, innovation thrives. Seamless data portability allows new market players to build on existing platforms, introducing enhanced services and features. On the flip side, restricted data portability can suppress innovation. <a href="https://www.weforum.org/agenda/2021/06/harness-ai-data-portability-financial-inclusion/">The World Economic Forum discusses this</a>, stating, <em>“Genuine data portability can unleash innovations, offering users superior services and features.”</em> The repercussions of limited data portability are multi-faceted, from dwindling competition to established platforms’ reduced incentive to innovate.</p><h4>Data Silos and Their Implications</h4><p>For all its advantages, the digital revolution also introduced data silos — isolated repositories that trap data, obstructing its free movement. These silos don’t just pose technical challenges; they are barriers to genuine user empowerment. As data remains confined, users face fragmented experiences and limited choices.</p><p>The existence of data silos creates multiple issues. First, they lead to redundant storage, increasing operational costs for organizations. Secondly, they hinder the holistic analysis of data. Data silos can also slow decision-making processes, as accessing and integrating data from disparate sources becomes cumbersome.</p><h4>Pain Points and Limitations in Data Portability</h4><p>Data portability, despite its immense potential, is laden with challenges. A significant hurdle is the absence of standardized data formats. Platforms often have proprietary formats, making seamless data transfer a complex endeavor. Moreover, concerns about data privacy and security further complicate things.</p><h3>Web3</h3><h4>The Evolution from Web2 to Web3</h4><p>Before we begin discussing web2 and comparing it to web3, let’s define the different <em>“eras”</em> of the internet. Web1 describes the early public internet and traces its beginnings back to the early 1990s. The release of the Mosaic web browser in 1993 is often pointed to as a key milestone that ushered in web1. This era of the internet can be thought of mainly as a <em>“read-only”</em> phase. In the early to mid-2000s, the web2 era began. Web2 is characterized by user-generated content, increased interactivity, and the growth of social media platforms.</p><p>Web2 was groundbreaking. However, it has also been an era where platforms capitalize on user data. As <a href="https://www.notion.so/Unleashing-the-Power-of-Data-Portability-Empowering-Users-for-an-AI-Driven-Future-cba6b7c1b8514c33beb6314ae548c81d?pvs=21">Nidal K. points out in the article “Data Ownership Revolution with Web3: How to Take Back Control of Your Data and Monetize It”</a>, <em>“Web 2.0 platforms created walled gardens around user data.”</em> Web3 aims to break down these walls, giving users back their data ownership.</p><p>By leveraging blockchain technology and decentralization, users don’t just get to own their data; they get to dictate its use. It’s a shift from platform-centric models to user-centric ones. This means that in the web3 world, you won’t just be a user; you’ll be a decision-maker.</p><p>Consider current online services that operate on a centralized model. Your emails, cloud storage, and even social media posts reside on servers owned by a few corporations. Web3 proposes a model where such data could be stored on decentralized networks, giving users direct control over their information.</p><h4>Monetizing Data in Web3</h4><p>Web3 not only offers users control over their data but also opportunities to monetize this data. Platforms of the future might allow users to earn from their data, creating a more equitable digital landscape.</p><p>It’s not just about monetary benefits, however. With the proper mechanisms in place, users could earn better service quality, personalized experiences, or even access to premium content. Such a model could transform passive users into active stakeholders, reshaping the dynamics of the digital economy.</p><h4>Redefining Data in Web3</h4><p>Web3 promises a reimagined internet where users regain control and ownership of their data. This decentralized web ensures that users are not simply passive consumers but active participants earning from their data. As highlighted in the <a href="https://www.moderncontemporaryartworktrends.com/data-ownership-in-web-3-0/">“Data Ownership in Web 3.0” article by Claude Edwin Theriault</a>, this era champions the transition from <em>“data as a commodity”</em> to <em>“data as a utility.”</em></p><p>This transition would be immense in terms of how we interact on the internet. Consider the current state of the internet, where large corporations often have more insight into our personal preferences than we do. Fueled by our data, their algorithms dictate the content we see, the ads we’re served, and even the products we’re offered. Web3 seeks to disrupt this paradigm.</p><p>In this scenario, you’re not just a user but a stakeholder, where every piece of data you contribute is recognized, rewarded, and respected. This isn’t a utopian dream but rather the very ethos of web3. This increased transparency could lead to greater trust in online platforms. Moreover, with users at the helm, we could see a surge in community-driven content and platforms. If anything, a “web3” internet, as described above, would resemble the original hopes for the web much more closely than what we have today. The quote below is from <a href="https://web.archive.org/web/19970219205519/http://www.lysator.liu.se/etexts/the_internet.html">a February 1993 article in “The Magazine of Fantasy and Science Fiction” entitled simply “Internet.”</a></p><blockquote><strong>“Why do people want to be ‘on the Internet?’ One of the main reasons is simple freedom. The Internet is a rare example of a true, modern, functional anarchy. There is no ‘Internet Inc.’ There are no official censors, no bosses, no board of directors, no stockholders. In principle, any node can speak as a peer to any other node, as long as it obeys the rules of the TCP/IP protocols, which are strictly technical, not social or political.”</strong></blockquote><p>Most readers would agree that the current state of the Internet has drifted far from the optimistic vision laid out above and that the web3 vision aligns much more closely.</p><h4>The Role of Cryptography</h4><p>Cryptography, often behind the scenes, ensures our digital world’s security. With data becoming increasingly portable, its security and integrity are paramount. Techniques like encryption and digital signatures are crucial. They ensure data, whether moving or stationary, remains breach-resistant.</p><p>Consider the rising instances of data breaches in recent years. The need for robust security measures has never been more pressing. Cryptography acts as a defense against such threats, ensuring that our digital identities, transactions, and personal information remain secure. As we move towards a future with even more data mobility, the role of cryptography will only become more pivotal.</p><p>A cornerstone of web3’s promise is the true ownership of one’s data. This ownership is often cryptographically secured, with users holding private keys granting them access and control over their digital assets, be it cryptocurrencies or personal data. As the saying goes, <em>“With great power comes great responsibility,”</em> which rings true in web3.</p><p>This decentralized data ownership model places the onus of security squarely on the individual. While this empowerment is liberating, it’s also daunting. It means that the everyday user must be more tech-savvy and more security-conscious. They must understand the weight of holding their private keys and the implications of potential mismanagement.</p><p>Several web3 platforms already offer embeddable wallets and other abstractions that take key management out of users’ hands. However, these abstractions introduce a philosophical problem. If users no longer manage their private keys directly, do they genuinely own their data? By placing the responsibility of key management into the hands of third-party platforms or systems, we may reintroduce a form of centralized control. It might not be as overt as the current centralized data custodians of the web2 world, but it’s centralization nonetheless.</p><p>This shift could transform <em>“ownership”</em> into a more nebulous concept. Users might have access to their data, but the control embodied by the direct management of private keys might be diluted. It’s a delicate balance between usability and the essence of decentralized ownership. As the web3 ecosystem evolves, it’s a conversation that the community, developers, and users alike must engage in, ensuring that the core tenets of decentralization aren’t compromised in the pursuit of simplicity.</p><h3>Data Portability in an AI-Driven Future</h3><h4>Role of Data Portability in AI Advancements</h4><p>Artificial Intelligence (AI) sits at the cutting edge of technology. Yet, AI’s full potential can only be harnessed with access to rich, varied data. This is where data portability becomes indispensable. Data portability can enable users to transition to AI platforms that respect their rights.</p><p>In a future with true data portability, users will decide what services to share their data with and have visibility into how it is used. This data is very valuable to organizations building AI-backed solutions. This opens up an opportunity for users to monetize their data.</p><p>The union of AI and data portability signals a future where tailor-made experiences will surpass anything we’ve seen before. Picture AI-powered recommendation engines that integrate data from diverse platforms, offering truly bespoke suggestions, be it shopping, entertainment, or healthcare.</p><p>Imagine a day when your health monitor communicates seamlessly with your grocery list app. Based on your health data, the AI recommends specific foods and even integrates with local grocery stores to find the best deals. Or consider a scenario where your AI-driven virtual assistant, having access to your calendar, work tasks, personal preferences, and even mood, curates a perfect evening for you. These are not mere speculations but tangible futures enabled by AI and data portability.</p><h3>How We at Catena Labs Plan to Tackle Data Portability</h3><p>At Catena Labs, we’re unwavering in our vision for the web. Our ambition is a user-centric digital ecosystem liberated from centralized gatekeeper constraints. We’re pioneering innovations across domains, from identity and communication to AI and commerce.</p><p>Our journey is inspired by the understanding that in the digital realm, empowerment stems from agency. Agency over one’s data, choices, and digital interactions. This philosophy underpins every tool we design and every application we develop.</p><p>Our work with Duffle epitomizes our dedication to reshaping the digital realm. With features like rapid, encrypted messaging and personal AI chat using the XMTP protocol, Duffle forecasts a future where data isn’t just portable but genuinely empowering.</p><p>However, while we view Duffle as the best-in-class application for interacting with this data, the portable data and decentralized protocols behind the scenes make all the difference. This allows you to take your data wherever you please. You will never be locked into Duffle.</p><p>Data portability extends to the concept of group chats and communities as well. Users can create group chats or communities in Duffle and continue these conversations in any application supporting the underlying XMTP protocol. Any AI agents involved in group chats or communities are portable as well. Below is an example of communicating with Duffle AI from within Coinbase Wallet!</p><h3>Jeremy Allaire on Twitter: &quot;Excited for XMTP and Web3 wallets. See below my chat AI with a bot inside my Coinbase Wallet interacting with Duffle (@catena_labs) pic.twitter.com/zFNXLgbgX7 / Twitter&quot;</h3><p>Excited for XMTP and Web3 wallets. See below my chat AI with a bot inside my Coinbase Wallet interacting with Duffle (@catena_labs) pic.twitter.com/zFNXLgbgX7</p><p>This approach manifests our commitment to a more accessible, fairer, and user-centric digital world. A world where every byte of data, every online interaction, is rooted in respect, transparency, and empowerment.</p><p>The digital realm is vast and intricate, but with collective endeavors and a unified vision, we can craft a future where data portability is foundational, not an afterthought.</p><p><strong>References:</strong></p><ol><li><a href="https://hai.stanford.edu/better-ai-data-rights"><em>Better AI Data Rights</em></a><em> — Marshall Van Alstyne, Geoffrey Parker, Georgios Petropoulos and Bertin Martens, Stanford University Human-Centered Artificial Intelligence.</em></li><li><a href="https://www.moderncontemporaryartworktrends.com/data-ownership-in-web-3-0/"><em>Data ownership in Web 3.0</em></a><em> — Claude Edwin Theriault, </em><a href="http://ModernContemporaryArtworkTrends.com"><em>ModernContemporaryArtworkTrends.com</em></a><em>, April 2023.</em></li><li><a href="https://medium.com/coinmonks/data-ownership-revolution-with-web3-how-to-take-back-control-of-your-data-and-monetize-it-7a1c195cfd39"><em>Data Ownership Revolution with Web3: How to Take Back Control of Your Data and Monetize It</em></a><em> — Nidal K, Coinmonks blog, May 2023.</em></li><li><a href="https://www.iiprd.com/data-portability-and-ai/"><em>Data Portability and AI</em></a><em> — IIPRD, May 2023.</em></li><li><a href="https://medium.com/frctls/data-portability-and-identity-4336d996cbb9"><em>Data Portability and Identity</em></a><em> — Peter Grosskopf, Fractal ID Team blog, June 2021.</em></li><li><a href="https://www.brookings.edu/articles/data-portability-and-interoperability-a-primer-on-two-policy-tools-for-regulation-of-digitized-industries-2/"><em>Data portability and interoperability: A primer on two policy tools for regulation of digitized industries</em></a><em> — Sukhi Gulati-Gilbert and Robert Seamans, The Brookings Institution, May 2023.</em></li><li><a href="https://www.cambridge.org/core/books/artificial-intelligence-and-international-economic-law/data-portability-in-a-datadriven-world/F445EC4A9E9665A05E773A88E8840027"><em>Data Portability in a Data-Driven World</em></a><em> — Frederike Zufall and Raphael Zingg, Cambridge University Press, October 2021.</em></li><li><a href="https://plaid.com/blog/how-data-portability-maximizes-crypto-value/"><em>How data portability maximizes crypto’s value</em></a><em> — Ben White, Plaid blog, August 2022.</em></li><li><a href="https://www.weforum.org/agenda/2021/06/harness-ai-data-portability-financial-inclusion/"><em>How to harness AI and data portability for greater financial inclusion</em></a><em> — Laurent Le Moal and Amelia Ng, World Economic Forum, June 2021.</em></li><li><a href="https://a16zcrypto.com/posts/article/how-web3-data-portability-reduces-the-power-of-centralized-services/"><em>How web3 data portability reduces the power of centralized services</em></a><em> — Chris Dixon, a16zcrypto, January 2022.</em></li><li><a href="https://www.forbes.com/sites/forbestechcouncil/2022/03/31/in-web-30-data-ownership-and-monetization-must-belong-to-individuals/?sh=3157d033d6b7"><em>In Web 3.0, Data Ownership And Monetization Must Belong To Individuals</em></a><em> — Jeff Bell, Forbes, March 2022.</em></li><li><a href="https://www.entrepreneur.com/money-finance/3-ways-web-30-will-change-digital-ownership/432166"><em>3 Reasons Why Web3 Will Flip Digital Ownership On Its Head</em></a><em> — Ivan Liljeqvist, Entrepreneur Magazine, August 2022.</em></li></ol><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2950da08a53d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Shaping a Future of Digital Privacy with LLMs and Encrypted Messaging]]></title>
            <link>https://medium.com/@mattdionis/shaping-a-future-of-digital-privacy-with-llms-and-encrypted-messaging-a9b0f79decfb?source=rss-6387214b750d------2</link>
            <guid isPermaLink="false">https://medium.com/p/a9b0f79decfb</guid>
            <category><![CDATA[privacy]]></category>
            <category><![CDATA[data-privacy]]></category>
            <category><![CDATA[artificial-intelligence]]></category>
            <category><![CDATA[ai]]></category>
            <category><![CDATA[decentralization]]></category>
            <dc:creator><![CDATA[Matt Dionis]]></dc:creator>
            <pubDate>Fri, 04 Aug 2023 18:02:21 GMT</pubDate>
            <atom:updated>2023-08-04T18:02:21.898Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="Representation of decentralization &amp; data privacy produced by AI" src="https://cdn-images-1.medium.com/max/1024/1*pXlNeJL23i7D8wzWA8TImQ.png" /></figure><p>The current digital landscape presents a double-edged sword with regard to user data. On the one hand, the explosion of data has catalyzed technological advancements that make life more convenient and help keep us more connected. On the other hand, companies have capitalized on this massive influx of data, often at the cost of user privacy. Our digital footprints have become valuable assets, with companies commercializing and profiting from our most personal interactions. The proliferation of digital identities has also ushered in challenges around impersonation and false representation.</p><h3>When Data Privacy Goes Wrong: High-Profile Examples</h3><p>Data privacy breaches can have severe repercussions. Two high-profile examples appear below.</p><h3>Cambridge Analytica</h3><p>One of the most controversial cases of user data misuse involves the social media giant Meta. In 2018, it came to light that Cambridge Analytica, a political consulting firm, had obtained the personal details of millions of Facebook users without their permission and utilized it for political advertising objectives. This incident raised global concerns about Facebook’s data privacy practices and resulted in a hefty fine of $5 billion for the company.</p><h3>Equifax</h3><p>In 2017, major credit reporting agency Equifax disclosed a security breach that compromised the sensitive information of 147 million individuals. The stolen data contained Social Security numbers, birth dates, addresses, and even driver’s license numbers, all of which could be exploited for identity theft purposes. This case highlighted the vulnerability of centralized data storage systems and questioned the efficacy of existing data protection mechanisms.</p><p>The lack of privacy and respect for personal data has reached a tipping point in recent years, necessitating legislation like the <a href="https://gdpr.eu/">General Data Protection Regulation (GDPR)</a>. Yet, we should not have to rely solely on regulatory safeguards. As custodians of this digital landscape, we should prioritize user privacy instead of waiting for legislation to enforce it.</p><h3>Privacy in Duffle</h3><p>At <a href="https://catena.xyz/">Catena Labs</a>, we firmly believe that privacy is not just a feature but an essential cornerstone of AI-backed digital products. One of our product initiatives, <a href="https://catena.xyz/codename/duffle">Duffle</a>, embodies this principle.</p><p>Duffle enables people to utilize decentralized identities and portable profiles to engage in encrypted chats with groups and individuals — and also interact with private AI agents. It employs secure data-sharing mechanisms, privately-hosted Large Language Models (LLMs), and encrypted messaging protocols. It is about fostering a new era of digital interaction, one where your data and conversations are your own.</p><h3>Private Data: An Essential Ingredient for Personalized AI</h3><p>In today’s digital age, data is akin to gold. However, this data “gold” isn’t locked away in some safe; it’s often out in the open, accessible to anyone with the right tools and the willingness to exploit it. The data we generate as we navigate digital spaces, interact with platforms, and engage with AI, is frequently consumed by corporations and used to further their interests, often without our informed consent. In this scenario, our data — an extension of our identity, preferences, and behavior — should not just be treated as an asset; it should remain strictly private, forming the essential cornerstone of a truly personalized AI experience.</p><p>Drawing a parallel to human relationships, it becomes evident that trust is the bedrock upon which any impactful relationship is built. The cornerstone of trust, whether between friends, family members, or business associates, is confidentiality. The more trust you have in someone, the more personal information you are willing to share with them. The relationships we foster with AI should be no different.</p><p>Users will trust AI-backed tools when they know that their personal information cannot be misused or manipulated and that they have complete control over their private data. Understanding that our data remains confidential, is treated with respect, remains under our control, and is used solely to enhance our experiences is critical to fostering this trust. The assurance of this trust and control encourages individuals to willingly share more specific and personal information, thus paving the way for genuinely individualized and contextual AI experiences.</p><p>In Duffle, Catena Labs is championing the cause of private data. Users can share their personal data securely with their own personal and private AI agent, ensuring they reap the benefits of a tailored AI experience without risking their privacy. Imagine having an AI assistant who knows you very well and is constantly optimizing for your needs while maintaining a strict code of confidentiality.</p><h3>Privately-Hosted LLMs: Conversation Privacy at the Core</h3><p>While AI continues to make significant strides, a crucial challenge persists: ensuring conversation privacy. In traditional models, conversations with AI often contribute to training public models, potentially compromising user privacy. While contributing significantly to the AI’s learning and adaptability, this process could inadvertently compromise user privacy. It may expose private and sensitive content of conversations that a user may not want to be used beyond the specific interaction. To tackle this, we need a new approach — privately-hosted LLMs with encrypted personal embeddings and secure private plugins.</p><p>In Duffle, we aim to address privacy concerns through the use of privately-hosted LLMs. This measure ensures that the content of your interactions with the AI, and the conversations that you hold, remain confidential and do not contribute to training publicly accessible models. This privacy-first approach addresses potential privacy issues and comes with a dual benefit.</p><p>Our privately-hosted LLMs are designed to maintain user privacy and adapt to individual users’ needs and preferences. The models can learn from each conversation and interaction, providing personalized responses and improving the user experience without sharing personal data with public LLMs. We ensure that any data used in this way is not shared or used in any manner to which you, as the user, have not explicitly consented.</p><p>At Catena, we place conversation privacy at the core of our operations. With the power of privately-hosted LLMs, we ensure that our users can leverage the benefits of AI technology, enjoying highly personalized and efficient responses, all while their conversation privacy remains uncompromised.</p><h3>Private Communication: The Power of Encrypted Networks</h3><p>We live in an era where most of our communication is executed digitally. From personal messages to business transactions, we rely heavily on the digital world, underscoring the importance of secure and private digital interactions. Encryption is the stalwart guard that ensures our digital messages and data remain safe from unauthorized access or accidental leaks. It serves as a shield that protects the privacy of our conversations and the security of our data in a landscape where cyber threats are always present.</p><p>Duffle leverages the robust capabilities of encrypted networks to provide this crucial safeguard. Specifically, we leverage the <a href="https://xmtp.org/">eXtensible Message Transport Protocol (XMTP)</a>. This protocol is designed to facilitate secure, encrypted communication, a vital layer of protection that safeguards both the content and the context of interactions between users and their AI agents.</p><p>We harness the power of end-to-end encryption, ensuring only the intended recipient can decrypt and access the communication. Every bit of data is encrypted from the moment a message is sent to the moment it’s received. This encryption includes your interactions with your AI agent. This approach fortifies the privacy and security of your communications and guarantees the confidentiality of your data.</p><p>With Duffle’s implementation of XMTP and end-to-end encryption, privacy will not just be a theoretical concept or a luxury feature but the backbone of every interaction and transaction you undertake. It’s not just about making private, secure conversation channels with your AI possible — at Catena, we’re making it the new normal.</p><h3>The Power of Private AI Agents</h3><p>As we move towards a more AI-driven digital environment, the conversational nature of AI tools becomes increasingly vital. This is especially true as AI begins to permeate more aspects of our personal and professional lives. Private AI agents, like those utilized within Duffle, can redefine this interaction by providing a personalized touch.</p><p>AI, especially LLMs, have made significant strides in understanding human language and context. They can generate human-like text to engage, entertain, and educate. However, these conversations are often generic and lack personalization since the AI has no specific context or knowledge about the individual user.</p><p>That’s where private AI agents come in. Imagine having an AI assistant that knows your work habits, understands your interests, or remembers that obscure movie reference you made weeks ago. It’s not just about data; it’s about personalized, contextual data. It can provide tailored recommendations, reminders, and insights based on your unique needs and preferences.</p><p>Duffle’s approach combines the power of LLMs with the promise of data privacy. With personal, privately-hosted LLMs that you control, you have an AI assistant that can learn from your data over time without sharing or exploiting this information.</p><p>In an era where our digital and physical lives are intertwined, this personalized, privacy-first approach can dramatically enhance the user experience while safeguarding individual privacy. It can be a game-changer for individuals and organizations, opening up new ways of interacting with AI.</p><p>Embracing this privacy-centric approach is not just about avoiding past mistakes; it’s about paving the way for a more secure, personalized, and user-friendly digital future.</p><h3>The Road Ahead</h3><p>As we navigate this exciting digital journey, protecting user privacy and data is paramount. Duffle, with its focus on private data, privately-hosted LLMs, and encrypted communication, is a pioneering initiative in this direction. By providing users with a truly private, secure platform for interacting with AI, we are revolutionizing the user experience and laying the foundation for a privacy-first digital future.</p><p>Privacy isn’t just a feature. It is an integral aspect of your digital life. It is the future we at Catena Labs are diligently working towards. And it’s a future where your data is truly your own.</p><p>We invite you to join the journey! We’re humbled and thankful for the feedback of our earliest Dufflers, and we’re now thrilled to invite more individuals off our waitlist to explore Duffle’s alpha.</p><p>To request access to iOS or Android versions, visit the codename // Duffle site: <a href="https://duffle.chat">https://duffle.chat</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a9b0f79decfb" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Let’s #EmbraceTheStuck]]></title>
            <link>https://medium.com/@mattdionis/lets-embracethestuck-fe4b8115b799?source=rss-6387214b750d------2</link>
            <guid isPermaLink="false">https://medium.com/p/fe4b8115b799</guid>
            <category><![CDATA[covid19]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[career-advice]]></category>
            <category><![CDATA[careers]]></category>
            <category><![CDATA[motivation]]></category>
            <dc:creator><![CDATA[Matt Dionis]]></dc:creator>
            <pubDate>Sun, 29 Mar 2020 22:36:02 GMT</pubDate>
            <atom:updated>2020-03-29T22:36:05.188Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="An open book illuminated by a string of lights" src="https://cdn-images-1.medium.com/max/1024/1*77kVLXT5wReVAW-kQYcpaw.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@californong?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Nong Vang</a> on <a href="https://unsplash.com/s/photos/reading?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplay.ht%2Fembed%2F%3Farticle_url%3Dhttps%3A%2F%2Fmedium.com%2F_p%2Flets-embracethestuck-fe4b8115b799&amp;display_name=Play&amp;url=https%3A%2F%2Fplay.ht%2Farticles%2Ffe4b8115b799&amp;image=https%3A%2F%2F1%2AP9g_4ikKQvCk5LT8PPH0Qw.jpeg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=play" width="700" height="185" frameborder="0" scrolling="no"><a href="https://medium.com/media/f3963fdde73723ff551777ff41783cd6/href">https://medium.com/media/f3963fdde73723ff551777ff41783cd6/href</a></iframe><p>Over the past couple of weeks, a phrase that has its origins in modern military slang keeps entering my mind: “<a href="https://www.npr.org/2007/03/08/7458809/embrace-the-suck-and-more-military-speak">embrace the suck</a>.” This phrase was popularized by soldiers during the original Operation Iraqi Freedom and as <a href="https://www.latimes.com/archives/la-xpm-2007-jan-28-op-bay28-story.html">this Los Angeles Times story</a> notes, it loosely translates to,</p><blockquote>“Face it, soldier; I’ve been there. War ain’t easy. Now deal with the difficulty and let’s get on with the mission.”</blockquote><p>There’s an added wrinkle to what much of the world is currently enduring, isolation. We have been asked to <a href="https://www.hopkinsmedicine.org/health/conditions-and-diseases/coronavirus/coronavirus-social-distancing-and-self-quarantine">practice social distancing</a>, to <a href="https://time.com/5806477/what-is-shelter-in-place/">shelter-in-place</a>, to <a href="https://www.hhs.gov/answers/public-health-and-safety/what-is-the-difference-between-isolation-and-quarantine/index.html">self-quarantine</a>. With this in mind, we basically need to <strong>“embrace the stuck!”</strong></p><figure><img alt="Emoji faces wearing facemasks" src="https://cdn-images-1.medium.com/max/1024/1*mZjKF_t6qJY1dg_Z5hj4Dg.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@visuals?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">visuals</a> on <a href="https://unsplash.com/s/photos/coronavirus?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>We are stuck at home day after day. Most of us are working from home, many for the first time. Some of us are attempting to do so while chasing kids around; kids who are out of school indefinitely. This is a big change for all of us, but I will argue that there are opportunities in this period of uncertainty.</p><figure><img alt="Kids having a pillow fight; feathers flying" src="https://cdn-images-1.medium.com/max/1024/1*vC7MQbdJiIPQMrHOHedxbQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@allentaylorjr?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Allen Taylor</a> on <a href="https://unsplash.com/s/photos/kids?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>Those of us who are fortunate enough to be healthy and unaffected physically by the coronavirus should be thankful. Sure, it’s OK to be frustrated. Yes, you may feel burnt out from attempting to perform double-duty, working and chasing kids around. On the other end of the spectrum, you may have recently lost your job. That sucks. Plain and simple. But at the end of the day, I promise, there is opportunity here.</p><p>Over a decade ago, in late 2008, I moved from Los Angeles back to Massachusetts as the economy was collapsing. I had no job prospects and within a week went from living on Sunset Blvd to living in a two-bedroom apartment with my sister. I felt stressed, isolated, but never defeated. My girlfriend at the time, who would soon become my wife, suggested I look into actuarial science as I had always been a “math nerd.”🤓 Soon after, I purchased the necessary books and study guides and began working toward taking the first actuarial exam. Through self-study, I passed the first two actuarial exams and by early 2010 had secured a solid job at an insurance company. This indirectly led to my current career as a software engineer, a career I may have never found had I not taken initiative back in one of the toughest periods of my life.</p><p>Take advantage of this isolation period as much as you can. Put together a reading list and work through it consistently to learn a new skillset. Finally follow through on that goal to learn to code and enroll in an <a href="https://www.codecademy.com/">online program</a>.💻 Pick up that paintbrush again and start creating.🎨 Put pen to paper and begin writing that book you’ve always talked about wanting to write.📝 Whatever it is, take advantage of this very difficult period in history. Work toward coming out of this period with new or improved skill sets. That <strong>will</strong> set you apart in the future competitive job market.🚀</p><figure><img alt="A sign with the text, “never be afraid to reinvent yourself”" src="https://cdn-images-1.medium.com/max/1024/1*HzEkDo0Y2AtvyVcVqsogJw.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@creativegangsters?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Allie Smith</a> on <a href="https://unsplash.com/s/photos/inspiration?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>We are sadly losing many thousands of people to this virus. Honor them by not wasting a second of the time we are fortunate to still have.</p><p>#EmbraceTheStuck!!!</p><p><em>Note: I plan on donating any proceeds I may earn on this story through the Medium Partner Program to </em><a href="https://girlswhocode.com/"><strong><em>Girls Who Code</em></strong></a><strong><em>.</em></strong><em> I have been fortunate to work with some incredible women engineers but when I look around I realize this profession is still dominated by men. I would like to do my own small part to help change this!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=fe4b8115b799" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Never Too Late to Learn: My (meandering) path to a career in software engineering]]></title>
            <link>https://medium.com/extendnode/never-too-late-to-learn-my-meandering-path-to-a-career-in-software-engineering-308f81912cdb?source=rss-6387214b750d------2</link>
            <guid isPermaLink="false">https://medium.com/p/308f81912cdb</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[tech]]></category>
            <category><![CDATA[entrepreneurship]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[careers]]></category>
            <dc:creator><![CDATA[Matt Dionis]]></dc:creator>
            <pubDate>Thu, 22 Aug 2019 16:43:05 GMT</pubDate>
            <atom:updated>2019-08-28T14:52:07.971Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="A pamphlet entitled “Don’t Just Stand There” sits on a wooden desk" src="https://cdn-images-1.medium.com/max/1024/1*kOw2LVzG0MA-HqbgxNtwaw.jpeg" /><figcaption>Get motivated!</figcaption></figure><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplay.ht%2Fembed%2F%3Farticle_url%3Dhttps%3A%2F%2Fmedium.com%2F_p%2Fnever-too-late-to-learn-my-meandering-path-to-a-career-in-software-engineering-308f81912cdb&amp;url=https%3A%2F%2Fplay.ht%2Farticles%2F308f81912cdb&amp;image=https%3A%2F%2F1%2AP9g_4ikKQvCk5LT8PPH0Qw.jpeg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=play" width="700" height="185" frameborder="0" scrolling="no"><a href="https://medium.com/media/0160108184f27c389431f0895e176b9a/href">https://medium.com/media/0160108184f27c389431f0895e176b9a/href</a></iframe><p>If you’ve ever considered pursuing a career in software engineering but thought you were too old or that your education and career path up to this point weren’t a fit, think again! My path to a career in software engineering is detailed below and let’s just say it was not a straight line, but it was well worth it!</p><h3>The weather geek</h3><p>For as long as I can remember I have been fascinated by the weather. Some of my fondest memories as a child were peering out the window as a severe thunderstorm rolled in or waking up in the morning to a raging blizzard outside. My favorite number was, and still is, 56 due to the fact that The Weather Channel was 56 on our cable package.</p><figure><img alt="The Weather Channel logo" src="https://cdn-images-1.medium.com/max/200/1*FSuAO8WOeL-u_3e_xC_gGw.png" /><figcaption>Old school Weather Channel logo. Oh, the memories!</figcaption></figure><p>Throughout my teenage years, I was the local weather spotter for Boston’s ABC affiliate. I would call in local conditions and snowfall amounts during storms and would be mentioned on-air once in awhile. I <em>knew</em> my future career was going to be in meteorology and no one could tell me anything different.</p><p>I was a solid student throughout my childhood and decided to only apply to one school, Penn State University. Penn State has one of the best, if not <em>the</em> best, <a href="http://www.met.psu.edu/">meteorology programs</a> in the nation. I received my acceptance letter before Halloween of my senior year of high school. Everything was falling into place for this future meteorologist…or so I thought.</p><p><strong>Total lines of code written by age 18: 0</strong></p><p><strong><em>Skills gained which would eventually help my engineering career: embracing a passion (meteorology) and being a self-starter in learning more about a field</em></strong></p><h3>A national tragedy and a change of course</h3><p>Within the first month of college, my classmates and I were informed that there was a great chance <em>none</em> of us would graduate with a Meteorology degree. I remember all of us laughing out loud. We had all been weather geeks since we could walk. Noooo chance we would change majors.</p><p>By the beginning of my sophomore year of college, I started to get bored with my meteorology courses. I loved tornados, hurricanes, blizzards but these extreme weather events do not happen very often. I remember overhearing classmates arguing about whether that night’s low temperature would be 37º or 38º one day and all I was concerned with was where I was going to party that night. It was clear that I needed to make a change, but when you’ve been known as the “future meteorologist” since age five it can be <em>very</em> difficult to tell those you love that that dream is over.</p><p>I had my first Computer Science course scheduled for the fall of 2001 but <strong>after just one class</strong> I dropped it. I decided that computer science was just not for me and my time was better spent in a different class. Oh, silly 20-year-old me ;)</p><p>My sophomore year began in the fall of 2001 and on September 11 any childhood innocence I may have had left was gone. Meteorology suddenly felt even less important to me as I began to look for a major, and a future career, where I could have a greater impact.</p><p>Around this same time, I attended a free speaker series event on the University Park campus. Chuck D of Public Enemy fame was the speaker that evening. I still remember to this day when he looked out at the audience and urged us, students, not to <em>“waste our time at a great university pursuing someone else’s dream”</em>. That was the push I needed and the very next day I began filling out paperwork to change my major.</p><p>I moved to Washington D.C. after graduating from Penn State and within a year was working as a Data Analyst on an Immigration and Customs Enforcement (ICE) contract.</p><p><strong>Total lines of code written by age 22: 0</strong></p><p><strong><em>Skills gained which would eventually help my engineering career: time management, advanced mathematics, improved logical thinking</em></strong></p><h3>Jaded and restless</h3><p>I entered my career in Homeland Security with a vision that I would be “protecting the country from terrorists”. This is <em>not</em> what I experienced in reality. It quickly became apparent to me that my job was mostly busy work and that the contractor I was working for was much more interested in securing more Federal contracts while appearing to “fight terrorism” than actually fighting terrorism. In my 2.5 years on the job, I can honestly admit that my work contributed to zero terrorist apprehensions.</p><figure><img alt="A man posing for a photoshoot" src="https://cdn-images-1.medium.com/max/260/1*xYgfmH0d1wT-dk3N_IIVZw.jpeg" /><figcaption>Fitness modeling photoshoot circa 2007</figcaption></figure><p>I was pretty frustrated at this point but thankfully had the gym as an outlet. Every day after work I would spend a solid two hours lifting weights. I would then go home and prepare eggs, oatmeal, chicken, and sweet potatoes for the next day’s meals. This lifestyle eventually led to a couple of local photoshoots and the opportunity to work with a manager to further this side career. I did some work for Under Armour and Simpson Racing and quickly got the itch to move West to Hollywood to see what I could make out of this opportunity.</p><p><strong>Total lines of code written by age 25: 0</strong></p><p><strong><em>Skills gained which would eventually help my engineering career: even stronger self-starter skills, ability to focus on the task-at-hand and remove distractions</em></strong></p><h3>Hollywood dreams</h3><p>I quit my stable job with great benefits while my parents were vacationing overseas and broke the news to them over the phone the day they returned. I do <strong>not</strong> recommend this strategy for breaking news like this. It did not go over well, to say the least.</p><figure><img alt="The Hollywood sign with palm trees in the foreground" src="https://cdn-images-1.medium.com/max/1024/1*dNTnZHlJiniRpDpodKBPzQ.jpeg" /><figcaption>The backdrop to an interesting 15 months of my life</figcaption></figure><p>After arriving in LA, I found a job working as a graveyard shift Front Desk Agent at a <a href="https://www.morganshotelgroup.com/mondrian/mondrian-los-angeles">hotel on the Sunset Strip</a>. My plan was to work nights, hit the gym in the morning, and audition for acting roles in the afternoon. This plan turned out to be <em>very</em> naive. I auditioned for a grand total of zero roles as I had failed to take sleep into consideration. I never really got accustomed to the overnight shift and felt like a zombie most days.</p><p>I made the decision to move back to my hometown in late 2008 just as the economy was collapsing.</p><p><strong>Total lines of code written by age 26: 0</strong></p><p><strong><em>Skills gained which would eventually help my engineering career: the ability to fight through adversity, communication skills, “debugging” (in this case in support of solving hotel guest issues)</em></strong></p><h3>Return to the East Coast</h3><p>I moved back to the East Coast at the very end of 2008 when the economy had hit rock bottom. It took me almost a full year to find another job. In hindsight, I wish I had begun learning to code at this point but it never crossed my mind.</p><p>I worked as a Data Analyst on a temporary contract for a little over a year. I had no benefits: no healthcare, zero vacation days, no opportunity to advance. Thankfully, my wife encouraged me to pursue a career in <a href="https://en.wikipedia.org/wiki/Actuarial_science">actuarial science</a>. I had a solid math background and actuarial careers pay well so I started studying!</p><p><strong>Total lines of code written by age 29: 0</strong></p><p><strong><em>Skills gained which would eventually help my engineering career: analytical skills</em></strong></p><h3>Avoiding risk</h3><p>I passed the first two actuarial exams on my own which led to an opportunity to work at a <a href="https://www.hanover.com/">local insurance company</a>. This was a huge step up from my prior temp role. This position is where I began to dabble in some “programming” in a way. Most of my days were spent in massive Microsoft Excel files updating and improving macros. I found that I really enjoyed this work although it still felt fairly tedious.</p><figure><img alt="An example question from an actuarial exam" src="https://cdn-images-1.medium.com/max/1005/1*7aydUqLAZF5r4ev467HI3A.jpeg" /><figcaption>A sample problem from an actuarial exam. I do <strong>not</strong> miss those days!</figcaption></figure><p>I struggled mightily with the third actuarial exam and ended up transitioning off of the exam track and into an actuarial technician role. This role afforded me the opportunity to begin working with SQL Server. I took to this from day one and had a lot of fun learning SQL.</p><p><strong>Total lines of code written by age 32: 0 (unless you count Excel macros and SQL)</strong></p><p><strong><em>Skills gained which would eventually help my engineering career: “programming” Excel macros, SQL</em></strong></p><h3>Embracing risk</h3><p>Around this same time, one of my best friends from high school and I decided to work on a health and fitness startup. The basic idea was to connect the millions of health and fitness-related photos shared on social media (meals, supplements, workouts, etc.) to health and fitness companies. You can think of it as a healthy living rewards platform. We called it <a href="http://outliermagazine.co/matt-dionis-conquerfit-interview/">ConquerFit</a>.</p><figure><img alt="A screenshot of a prototype for a health and fitness app" src="https://cdn-images-1.medium.com/max/341/1*wZ5C2PJwowt5Ohvmpol7ZA.jpeg" /><figcaption>An early prototype of the ConquerFit app</figcaption></figure><p>We outsourced development of the ConquerFit app to a local dev team and they delivered exactly what we wanted for our MVP. We quickly realized, however, that our friends and family funding had been blown through and we had a lot of features that needed to be added to the app before it was ready for general public release.</p><p>I decided to teach myself to code in order to build the “v2” version of our app.</p><p>I dove in head first starting with <a href="https://www.codecademy.com/">Codecademy</a> which I found to be an excellent first resource. After working through all of the JavaScript, HTML, CSS, and SQL material on Codecademy, I moved on to <a href="https://teamtreehouse.com/">Treehouse</a>.</p><p>I felt confident at this point and began hacking on some small sample projects. I cannot stress enough how important it is to begin working on an actual project early on in your learning journey. Working through tutorials is one thing, building an app is quite another. You’ll quickly get familiar with <a href="https://git-scm.com/">git</a> and <a href="https://github.com/">GitHub</a>, <a href="https://www.npmjs.com/">npm</a>, <a href="https://developers.google.com/web/tools/chrome-devtools/">browser dev tools</a>, and much more.</p><p>The sample project I spent most of my time on was something I called “MobSeen”. This application focused on sports events and allowed users to view Instagram photos shared in and around sporting events in near real-time. In order to build this app, I needed to gain a deeper understanding of Node.JS, AngularJS and setting up and managing a database. This turned out to be a great learning experience!</p><figure><img alt="A screenshot of an app which shows photos from sporting events" src="https://cdn-images-1.medium.com/max/1024/1*Mv2hDNUeOvQutrbdtBG3Ug.png" /><figcaption>The MobSeen app showing photos at Super Bowl XLIX!</figcaption></figure><p>I <strong>loved</strong> the process of learning, building, stumbling, learning some more, and repeating over and over again. What I found that I did <strong>not</strong> love was running a startup and thinking about fundraising, marketing, accounting, etc. ConquerFit would fade away but my newfound passion for web development would propel my career forward.</p><p><strong>Total lines of code written by age 32: many 😁</strong></p><p><strong><em>Skills gained which would eventually help my engineering career: HTML, CSS, JavaScript, git, GitHub, npm, browser dev tools, debugging</em></strong></p><h3>Given a chance</h3><p>I was very hesitant to apply for software engineering jobs at first as I never quite felt “ready”. Thankfully, my wife urged me to go for it and I followed her advice. I was able to get on the <a href="https://hired.com/">Hired</a> platform in the spring of 2015. I originally was only interested in jobs in Central Massachusetts as I wanted to avoid a commute. My recruiter, however, convinced me to expand my search area to Boston and I am so thankful that I did. I interviewed with a half dozen companies before receiving and accepting an offer from <a href="https://www.circle.com">Circle</a>.</p><p>My first role in this field was as a Software Engineer on the internal tools team at Circle. I was, and continue to be, incredibly grateful to the team at Circle for giving me a chance. I had an awesome manager and was surrounded by an intelligent, hard-working and collaborative team from day one. I can’t say enough about how comfortable they made me feel and how much I learned over those first couple of weeks, months, and years in the industry.</p><p><strong>Total lines of PRODUCTION code written by age 34: many 😁</strong></p><h3>Giving back</h3><p>I have spent the last eighteen months in Tech Lead/Engineering Manager roles which have allowed me to further improve my communication, prioritization, planning and management skills. I am focused on giving back to more junior developers and career-changers at this point through blogging, speaking at conferences, building video courses, and mentorship.</p><p>Take it from me: you are <strong>not</strong> too old to start coding, and your seemingly unrelated career path to this point <strong>will</strong> help you to be a better engineer in the long run. Start learning, start building, and never stop asking questions! In fact, feel free to reach out to me <a href="https://twitter.com/MattDionis">@mattdionis</a> or <a href="mailto:mattdionis@gmail.com">mattdionis@gmail.com</a> with any and all questions.</p><h3>Resources that have helped me (and could help you)</h3><h4>Learning platforms</h4><ul><li><a href="https://www.codecademy.com/">Codecademy</a> (solid for beginners)</li><li><a href="https://teamtreehouse.com/">Treehouse</a> (great next step after Codecademy)</li><li><a href="https://www.pluralsight.com/">Pluralsight</a> (more advanced, deep dives into frameworks/libraries)</li><li><a href="https://egghead.io/">Egghead.io</a> (awesome JavaScript content)</li></ul><h4>Instructors/bloggers</h4><ul><li><a href="https://medium.com/@samerbuna">Samer Buna</a> (especially love his Node.JS material)</li><li><a href="https://overreacted.io/">Dan Abramov</a> (incredible deep dives into React)</li><li><a href="https://blog.apollographql.com/">The Apollo GraphQL blog</a> (great for beginner and experienced GraphQL devs alike)</li></ul><h4>Twitter follows</h4><ul><li><a href="https://twitter.com/sarah_edo">Sarah Drasner</a> (animations, VueJS, and so much more)</li><li><a href="https://twitter.com/sxywu">Shirley Wu</a> (data visualization awesomeness)</li><li><a href="https://twitter.com/NadiehBremer">Nadieh Bremer</a> (⬆️ ditto)</li><li><a href="https://twitter.com/swyx">Shawn Wang</a> (JAMstack!)</li><li><a href="https://twitter.com/John_Papa">John Papa</a> (Angular!)</li></ul><h4>Podcasts</h4><ul><li><a href="https://reactpodcast.simplecast.fm/">React Podcast</a></li><li><a href="https://devchat.tv/react-round-up/">React Round Up</a></li><li><a href="https://undefined.fm/">Undefined</a></li><li><a href="https://fullstack.health/">Fullstack Health</a></li></ul><p><strong><em>Good luck!!!</em></strong> 👨‍💻</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=308f81912cdb" width="1" height="1" alt=""><hr><p><a href="https://medium.com/extendnode/never-too-late-to-learn-my-meandering-path-to-a-career-in-software-engineering-308f81912cdb">Never Too Late to Learn: My (meandering) path to a career in software engineering</a> was originally published in <a href="https://medium.com/extendnode">ExtendNode’s Blogs for Entrepreneurs</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Dig in and Get the Most Out of CodeSandbox]]></title>
            <link>https://medium.com/@mattdionis/dig-in-and-get-the-most-out-of-codesandbox-7f9421c9f9ce?source=rss-6387214b750d------2</link>
            <guid isPermaLink="false">https://medium.com/p/7f9421c9f9ce</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[development]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[software-engineering]]></category>
            <dc:creator><![CDATA[Matt Dionis]]></dc:creator>
            <pubDate>Mon, 19 Aug 2019 16:10:54 GMT</pubDate>
            <atom:updated>2019-08-19T16:20:35.622Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ljd8m-UJHtFI-EmFaxgoOQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@markusspiske?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Markus Spiske</a> on <a href="https://unsplash.com/search/photos/sandbox?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplay.ht%2Fembed%2F%3Farticle_url%3Dhttps%3A%2F%2Fmedium.com%2F_p%2Fdig-in-and-get-the-most-out-of-codesandbox-7f9421c9f9ce&amp;url=https%3A%2F%2Fplay.ht%2Farticles%2F7f9421c9f9ce&amp;image=https%3A%2F%2F1%2AP9g_4ikKQvCk5LT8PPH0Qw.jpeg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=play" width="700" height="185" frameborder="0" scrolling="no"><a href="https://medium.com/media/5cd4fe20a3982c9d3f88665d19f4851c/href">https://medium.com/media/5cd4fe20a3982c9d3f88665d19f4851c/href</a></iframe><p><a href="https://codesandbox.io">CodeSandbox</a> is an awesome online code editor for spinning up and testing out new ideas quickly, sharing demo apps, collaborating, and even for getting larger projects started before moving them over to GitHub or another source control option.</p><p>Personally, <a href="https://codesandbox.io/u/Matt-Dionis/sandboxes">I have used CodeSandbox</a> to write both server-side (Node.js) and client-side (React) code. It’s my go-to choice for testing out new libraries (URQL), frameworks, and features (React Hooks). I’ve also used multiple CodeSandboxes like Legos and pieced them together. The best example of this is my <a href="https://codesandbox.io/s/fl2mq">Apollo Federated Gateway</a> which links to a <a href="https://codesandbox.io/s/gr881">Location Service</a> and a <a href="https://codesandbox.io/s/4ccr3">Weather Service</a>. I then call this Gateway from my <a href="https://codesandbox.io/s/wzpzr">Apollo/URQL side-by-side</a> React CodeSandbox. That’s four CodeSandboxes successfully working together! I like this approach because it allows anyone interested in learning about a separate piece of the stack to view, fork, and hack on just that isolated portion of code.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*QMYXZYQTn7QAcYodwaZh6Q.png" /><figcaption>Four CodeSandboxes which rely on each other</figcaption></figure><p>CodeSandbox has many more options and features than you might guess at first glance. In this post, we will dive into some of the more powerful features of this awesome tool!</p><h3>Embedding</h3><p>CodeSandboxes can be embedded in other sites so that users can view and play around with your sandbox. The quickest way to share a CodeSandbox project is to click on the “Share” button and choose one of the sharing options that appear in the lower right of the modal. However, there are about a dozen configuration options that you’ll want to become familiar with in order to customize your embeds.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Zmh2YITfZ0t0eAhalet3Bw.gif" /><figcaption>CodeSandbox embed modal with configuration options</figcaption></figure><h4>Options</h4><p><strong>Appearance</strong></p><p>There are about a half dozen appearance options that you can tweak.</p><p>The view option determines the default view of the embed and can be one of “editor”, “split”, or “preview”. If you do not explicitly set this option it defaults to “split” for large screens or “preview” for smaller screens. If you want to show off a very visual sandbox, then “preview” is probably the way to go. Otherwise, “editor” is probably the best option. With limited screen real estate in an embed, I have found “split” to not often be a great choice.</p><p>The autoresize option is Medium-specific and automatically resizes the embed to the content. This option is off (0) by default but can be turned on by passing 1 to autoresize instead.</p><p>The hidenavigation option allows you to hide the navigation bar above the sandbox preview which shows the URL. This option defaults to “off” (0) but I often set it to 1 as I don’t find the navigation bar necessary in an embed.</p><p>Next up is the expanddevtools option which determines whether the devtools console is open (1) or closed (2). This option defaults to closed which is typically what you would want.</p><p>The moduleview option evaluates the file which is currently open in the editor. This option defaults to false (0) but if you have a use case for this you can set it to 1 to turn it on.</p><p>The previewwindow option allows you to choose what appears in the preview window if view is set to “split” or “preview”. This option defaults to “browser” but you can also set it to “console”, to display the devtools console, or “tests”, to display your test results.</p><p>Finally, the fontsize option allows you to set the, you guessed it, font size in px. This option defaults to 14.</p><p><strong>Sandbox Options</strong></p><p>There are also a few sandbox options that you can configure to your liking.</p><p>First off, there’s the codemirror option which is set to false (0) by default which means that the Monaco editor will be used. If you want to reduce your embed size significantly, you can set this to 1 to use the CodeMirror editor instead. This can be a nice performance optimization for your embed if you’re OK with using CodeMirror.</p><p>The next option in this section is eslint which is false (0) by default. If you want to enable ESLint, you can simply set this option to 1, but be aware that this will increase your embed size significantly.</p><p>Finally, the module option determines which module to open by default. This defaults to your sandbox’s entry path, but you can set it to whichever module you would like. You can even show multiple modules as tabs by entering a comma-separated list.</p><p><strong>Other Options</strong></p><p>The initialpath option defaults to / but you may set it to any valid string to show a different path on load.</p><p>The editorsize option allows you to set the editor size as a percentage and defaults to 50.</p><p>The forcerefresh option forces a full refresh after every edit and defaults to false (0).</p><p>If you have the codemirror option set to 1, you can pass a comma-separated list of line numbers to the highlights option to highlight lines of code.</p><p>The runonclick option allows you to only load the preview when the user chooses to. This option is set to false (0) by default.</p><p>Finally, the verticallayout option allows you to choose whether to display the editor and preview vertically (1) or horizontally (0, default) when view is set to “split”.</p><h4>Example embeds</h4><p>Let’s briefly walk through a couple of examples of embeds using the options discussed above.</p><p>In this first embed, I am aiming to focus on the code and also ensure the embed is as performant as possible. I, therefore, choose the editor-only view (view=editor) and increase the font size to 20 (fontsize=20). I also set codemirror to 1 to ensure a lighter weight embed. The resulting embed appears below.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodesandbox.io%2Fembed%2Fapolloclient-for-state-management-fym98%3Fcodemirror%3D1%26fontsize%3D20%26hidenavigation%3D1%26module%3D%252Fsrc%252FApp.js%26view%3Deditor&amp;url=https%3A%2F%2Fcodesandbox.io%2Fs%2Fapolloclient-for-state-management-fym98%3Fcodemirror%3D1%26fontsize%3D20%26hidenavigation%3D1%26module%3D%252Fsrc%252FApp.js%26view%3Deditor&amp;image=https%3A%2F%2Fcodesandbox.io%2Fapi%2Fv1%2Fsandboxes%2Ffym98%2Fscreenshot.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codesandbox" width="1000" height="500" frameborder="0" scrolling="no"><a href="https://medium.com/media/915c7f2280369a8638661dba5761f8df/href">https://medium.com/media/915c7f2280369a8638661dba5761f8df/href</a></iframe><p>In this next embed, I aim to show as much code as possible while keeping it readable, side-by-side with the resulting UI. To accomplish this, I set module to the file that I’m concerned with, /src/components/SettingsComponent.jsx, and I set fontsize to 12 in order to fit more code on the screen. The default view is “Editor + Preview” although you’ll notice that on smaller screens this defaults to just show the preview. Users can click the split screen icon to show the code side-by-side with the preview. The resulting embed is shown below.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fcodesandbox.io%2Fembed%2Fapolloclient-for-state-management-fym98%3Ffontsize%3D12%26module%3D%252Fsrc%252Fcomponents%252FSettingsComponent.jsx&amp;url=https%3A%2F%2Fcodesandbox.io%2Fs%2Fapolloclient-for-state-management-fym98%3Ffontsize%3D12%26module%3D%252Fsrc%252Fcomponents%252FSettingsComponent.jsx&amp;image=https%3A%2F%2Fcodesandbox.io%2Fapi%2Fv1%2Fsandboxes%2Ffym98%2Fscreenshot.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=codesandbox" width="1000" height="500" frameborder="0" scrolling="no"><a href="https://medium.com/media/92aac60fcce786184356f87cd01da8f8/href">https://medium.com/media/92aac60fcce786184356f87cd01da8f8/href</a></iframe><p>Now that you know a bit more about embed options, make sure to tweak them to your liking the next time you embed a CodeSandbox project!</p><h3>Importing and Exporting projects</h3><p>CodeSandbox has some great tools both for importing existing projects into CodeSandbox and for exporting projects to GitHub.</p><h4>CodeSandbox CLI</h4><p>CodeSandbox has a <a href="https://github.com/codesandbox/codesandbox-importers/tree/master/packages/cli">CLI</a>! Confession time: I was not aware this existed until a few days ago. To install the CodeSandbox CLI globally, run:</p><pre>npm install -g codesandbox</pre><p>Once the CLI is installed, you can export a project to CodeSandbox by running codesandbox followed by the directory you want to export. For example, if you are currently in your project’s top-level directory, simply run codesandbox ./.</p><p>This is a very convenient feature if you want to quickly share a local project with a broader audience. But what if you find yourself in the opposite situation? You have a CodeSandbox project which you would like to get under source control in GitHub. There is a CodeSandbox feature to cover this situation as well!</p><h4>GitHub Integration</h4><p>The CodeSandbox GitHub integration allows you to import any public GitHub repository and also to export any CodeSandbox project to GitHub!</p><p><strong>Importing</strong></p><p>To import a GitHub repo into CodeSandbox simply grab the URL of the repo and paste it into the CodeSandbox “Import from GitHub” feature. After a few seconds, you’ll have a copy of your project in CodeSandbox!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5PMgQC0W9ky0a1NFanr1xg.gif" /><figcaption>Importing a GitHub project into CodeSandbox</figcaption></figure><p><strong>Exporting</strong></p><p>Exporting <strong><em>to</em></strong> GitHub is also possible. Simply click on the GitHub tab within your sandbox, enter the desired repo name, and click “Create Repository”!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6hV-0B_8m03MrLRZQ-yeaw.gif" /><figcaption>Exporting a CodeSandbox project to GitHub</figcaption></figure><h3>Live Collaboration</h3><p>CodeSandbox has a feature which makes it easy to collaborate on a sandbox with others in real-time! As they describe it, <em>“it’s like Google Docs, but for your code”</em>.</p><h4>How to “Go Live”</h4><p>To go “live”, you simply click on the Live tab and then click “Go Live” to generate a URL which others can use to join your live session. The CodeSandbox team prepared a great demo of this feature which you can view below.</p><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FDnnJ0sLn28s%3Ffeature%3Doembed&amp;url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DDnnJ0sLn28s&amp;image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FDnnJ0sLn28s%2Fhqdefault.jpg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=youtube" width="854" height="480" frameborder="0" scrolling="no"><a href="https://medium.com/media/aec0d8707a230320b6542dbee2c9341d/href">https://medium.com/media/aec0d8707a230320b6542dbee2c9341d/href</a></iframe><h4>Using “Classroom Mode”</h4><p>Classroom Mode allows you to decide who can edit the sandbox during a live session. This is helpful if you are teaching and want everyone to be able to work with the same sandbox but only yourself, or a limited number of people, to actually be able to edit the sandbox.</p><h3>Testing</h3><p>CodeSandbox has native integration with <a href="https://jestjs.io/">Jest Tests</a> for running tests! You simply need to create files which end with one of the following: .test.js, .spec.js, .test.js(x), or .spec.js(x).</p><h3>Deploying</h3><p>When you are ready to deploy a sandbox, you have two options: <a href="https://zeit.co/">Zeit</a> and <a href="https://www.netlify.com/">Netlify</a>.</p><p>To deploy using Zeit Now you will first need to create a Zeit account and log into it.</p><p>On the other hand, the Netlify integration allows you to deploy a sandbox even if you do not yet have a Netlify account. The following templates are available for Netlify deploys:</p><ul><li><a href="https://reactjs.org/">React</a></li><li><a href="https://vuejs.org/">Vue</a></li><li><a href="https://preactjs.com/">Preact</a></li><li><a href="https://nuxtjs.org/">Nuxt</a></li><li><a href="https://parceljs.org/">Parcel</a></li><li>Static</li><li><a href="https://cxjs.io/">CxJS</a></li><li><a href="https://react-styleguidist.js.org/">Styleguidist</a></li><li>Typescript Variants of React and Parcel</li><li><a href="https://www.gatsbyjs.org/">Gatsby</a></li></ul><h3>Takeaways</h3><p>I hope you now have a better understanding of just how flexible and powerful CodeSandbox can be. Now get to building!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7f9421c9f9ce" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Get Hooked: Hooks in React and Beyond]]></title>
            <link>https://medium.com/circle-engineering/get-hooked-hooks-in-react-and-beyond-aaacb228959a?source=rss-6387214b750d------2</link>
            <guid isPermaLink="false">https://medium.com/p/aaacb228959a</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[hooks]]></category>
            <dc:creator><![CDATA[Matt Dionis]]></dc:creator>
            <pubDate>Wed, 26 Jun 2019 19:04:30 GMT</pubDate>
            <atom:updated>2019-07-07T12:44:34.838Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/500/1*y5lVhqzvNBF62WTBA0Z1uQ.jpeg" /><figcaption>Hooks are like velcro. Easily add to/remove from components as needed.</figcaption></figure><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplay.ht%2Fembed%2F%3Farticle_url%3Dhttps%3A%2F%2Fmedium.com%2F_p%2Fget-hooked-hooks-in-react-and-beyond-aaacb228959a&amp;url=https%3A%2F%2Fplay.ht%2Farticles%2Faaacb228959a&amp;image=https%3A%2F%2F1%2AP9g_4ikKQvCk5LT8PPH0Qw.jpeg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=play" width="700" height="185" frameborder="0" scrolling="no"><a href="https://medium.com/media/5058a42b30ad8951964ddb114e1a45a3/href">https://medium.com/media/5058a42b30ad8951964ddb114e1a45a3/href</a></iframe><h3>Why are Hooks so exciting?</h3><p><a href="https://reactjs.org/docs/hooks-reference.html">React Hooks</a> were introduced in the late fall of 2018 and officially made available in a stable release in <a href="https://reactjs.org/blog/2019/02/06/react-v16.8.0.html">React 16.8</a>. I watched the <a href="https://youtu.be/dpw9EHDh2bM">React Conf talks</a> introducing React Hooks but must admit that I didn’t “get it” at first. Sure, I understood the basics of hooks but I couldn’t quite grasp the benefits. Luckily, there are a ton of resources out there discussing hooks so I dove in and devoured as much content as I could. This post is meant to clearly summarize my findings and explain why I’m now a huge fan of hooks. Let’s kick things off by discussing how hooks address some common React inefficiencies.</p><h4>Sharing stateful logic between components</h4><blockquote>“Hooks let us organize the logic inside a component into reusable isolated units” — Dan Abramov</blockquote><p>I really like the above quote from <a href="https://medium.com/u/a3a8af6addc1">Dan Abramov</a>. In the past, pre-hooks, the code in React components was often split up by lifecycle method rather than concern. Business logic was mixed together and difficult, if not impossible, to separate. Hooks allow us to organize, isolate, and reuse this logic. As my headline image makes clear, when I think of hooks I think of velcro. Just like velcro straps, hooks can easily be attached, detached, and moved around.</p><p>The below tweet from <a href="https://medium.com/u/e970465f2c1e">Sunil Pai</a> is also a nice way to visualize this idea.</p><h3>Sunil Pai on Twitter</h3><p>ok so - I took dan&#39;s classes/hooks code from react conf, blacked out the &#39;unnecessary&#39; bits, then colour coded bits by &#39;concern&#39;. so much nicer. the effect is amplified in more complex components, where concerns are split and mixed across lifecycle methods.</p><p>Let’s take a closer look at Sunil’s use of hooks in this example. We can clearly see the isolation of concerns in the above code. Theme, name, and width are separated out into their own logical units. However, if you are new to hooks, the above code may bring up more questions than answers. How can we get away with calling useState and useEffect multiple times in the same component? Why does the second call to useEffect return a function but the first does not? How can I ensure useEffect only runs on initial render or when a certain variable changes? By the end of this post, all of these questions and more will be answered.</p><blockquote>“They’re not a way to share state — but a way to share stateful logic.” — Dan Abramov</blockquote><p>To me, this is the most important concept to grasp. We now have a way to share stateful logic. This allows us to isolate and reuse this logic rather than repeating it all over the place.</p><h4>Managing state in components</h4><p>Prior to the introduction of hooks, we needed to spin up a class component if we needed to work with state. State was then managed through one object which could often grow to contain many stateful properties.</p><p>Continuing to work with the above example, this is how a typical pre-hooks stateful component would handle state:</p><pre>this.state = {<br>  name: &quot;Harry&quot;,<br>  surname: &quot;Potter&quot;,<br>  width: window.innerWidth<br>}</pre><pre>...</pre><pre>this.setState({ name });<br>this.setState({ surname });<br>this.setState({ width: window.innerWidth });</pre><p>You can see how separate concerns (name, width) are lumped together in the this.state object. You’ll also notice how we need to call this.setState any time we need to update a stateful property.</p><p>Now let’s take a look at this same component updated to make use of hooks:</p><pre>let [name, setName] = useState(&quot;Harry&quot;);<br>let [surname, setSurname] = useState(&quot;Potter&quot;);<br>useEffect(() =&gt; {<br>  document.title = name + &quot; &quot; + surname;<br>});</pre><pre>let [width, setWidth] = useState(window.innerWidth);<br>useEffect(() =&gt; {<br>  let handleResize = () =&gt; setWidth(window.innerWidth);<br>  window.addEventListener(&quot;resize&quot;, handleResize);<br>  return () =&gt; {<br>    window.removeEventListener(&quot;resize&quot;, handleResize);<br>  };<br>});</pre><p>You’ll notice a clear separation of concerns and explicit function names for updating each stateful property (setName, setSurname, setWidth) rather than multiple calls to this.setState. You’ll also notice that the lifecycle methods have disappeared. Let’s take a closer look at that change next.</p><h4>Lifecycle methods</h4><p>In the original code of the example we’ve been working with, three different lifecycle methods are used: componentDidMount, componentDidUpdate, and componentWillUnmount:</p><pre>componentDidMount() {<br>  window.addEventListener(&quot;resize&quot;, this.handleResize);<br>  document.title = this.state.name + &#39; &#39; + this.state.surname;<br>}<br>...<br>componentDidUpdate() {<br>  document.title = this.state.name + &#39; &#39; + this.state.surname;<br>}<br>...<br>componentWillUnmount() {<br>  window.removeEventListener(&quot;resize&quot;, this.handleResize);<br>}</pre><p>You’ll notice a couple less than ideal aspects of this code. Separate concerns are lumped together within componentDidMount: listening to the “resize” event and setting document.title. Furthermore, there is repeated code for setting document.title. Are these major issues? No, not at this stage. However, as an application grows you will inevitably have more concerns mixed together in lifecycle methods and more repeated code between these methods. We can do better!</p><p>Here is the code which replaces the above lifecycle methods when you’re working with hooks:</p><pre>useEffect(() =&gt; {<br>  document.title = name + &quot; &quot; + surname;<br>});</pre><pre>...</pre><pre>useEffect(() =&gt; {<br>  let handleResize = () =&gt; setWidth(window.innerWidth);<br>  window.addEventListener(&quot;resize&quot;, handleResize);<br>  return () =&gt; {<br>    window.removeEventListener(&quot;resize&quot;, handleResize);<br>  };<br>});</pre><p>The first call to useEffect covers the componentDidMount and componentDidUpdate calls from above. The second call to useEffect actually covers componentDidMount, componentDidUpdate, and componentWillUnmount. We will discuss details about how to use useEffect later in this post.</p><h4>Higher-order components and render props</h4><blockquote>“Unlike patterns like render props or higher-order components, Hooks don’t introduce unnecessary nesting into your component tree.” — Dan Abramov</blockquote><p>Higher-order components allow us to reuse component logic and are possible thanks to React’s compositional nature. The problem is that they lead to what some have called “wrapper hell”. If you’ve ever worked in Node.js this can be compared to “callback hell”. Below is a contrived example to visually highlight what “wrapper hell” means:</p><pre>const EnhancedTodoComponent = compose(<br>  withConfirm(),<br>  withErrorBoundary(),<br>  withAutoBinding()<br>)(TodoComponent);</pre><pre>export default EnhancedTodoComponent;</pre><p>Obviously, the above can get tedious but the real pain comes with debugging as you’ll often see output like this in React Dev Tools (and this is tame compared to some components which are wrapped in <strong>many</strong> more higher-order components):</p><pre>withConfirm(withErrorBoundary(withAutoBinding(ToDoComponent)))<br>withErrorBoundary(withAutoBinding(ToDoComponent))<br>withAutoBinding(ToDoComponent)<br>ToDoComponent</pre><p>We can often run into similar situations with the render props pattern. Here is an example of this pattern from the <a href="https://www.apollographql.com/docs/react/essentials/queries/">Apollo docs</a> in relation to the Query component:</p><pre>const Dogs = ({ onDogSelected }) =&gt; (<br>  &lt;Query query={GET_DOGS}&gt;<br>    {({ loading, error, data }) =&gt; {<br>      if (loading) return &quot;Loading...&quot;;<br>      if (error) return `Error! ${error.message}`;<br><br>      return (<br>        &lt;select name=&quot;dog&quot; onChange={onDogSelected}&gt;<br>          {data.dogs.map(dog =&gt; (<br>            &lt;option key={dog.id} value={dog.breed}&gt;<br>              {dog.breed}<br>            &lt;/option&gt;<br>          ))}<br>        &lt;/select&gt;<br>      );<br>    }}<br>  &lt;/Query&gt;<br>);</pre><p>While this example only includes one level of nesting, you can imagine the “wrapper hell” we will encounter in more complex components with many levels of nesting.</p><p>Using hooks in place of higher-order components and render props can definitely clean up your component tree and make debugging a bit easier.</p><h3>How are Hooks implemented (at a high level)?</h3><p>I often find myself asking “how” when learning new technical concepts. I don’t feel like I <em>truly</em> grasp a concept until I understand how it is implemented. I’m not necessarily looking for a line-by-line analysis of source code, but a high-level understanding of implementation can go a long way toward wrapping one’s head around a new concept.</p><p>There are two JavaScript features you will need to understand deeply if you want to grasp how hooks work: closures and arrays.</p><h4>Closures</h4><p>Shawn Wang (<a href="https://medium.com/u/547f259e265e">Swyx</a>) does an excellent job discussing closures and how they relate to hooks in <a href="https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-really-work/"><em>“Deep Dive: How do React hooks really work?”</em></a>. I highly encourage you to bookmark that link and read through Shawn’s post. Below is his <em>possible</em> implementation of the React useState hook through closures:</p><pre>const MyReact = (function() {<br>  let _val // hold our state in module scope<br>  return {<br>    render(Component) {<br>      const Comp = Component()<br>      Comp.render()<br>      return Comp<br>    },<br>    useState(initialValue) {<br>      _val = _val || initialValue // assign anew every run<br>      function setState(newVal) {<br>        _val = newVal<br>      }<br>      return [_val, setState]<br>    }<br>  }<br>})()</pre><pre>// all credit to Shawn Wang (<a href="https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-really-work/">https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-really-work/</a>)</pre><p>You can see that _val is declared outside of the scope of the component and closed over. This setup allows _val to successfully be updated by the useState method. This setup also ensures _val is “reset” on future renders.</p><h4>Arrays</h4><p>The first “rule of hooks” which we’ll discuss below basically states, <em>“only call hooks at the top level…to ensure that hooks are </em><strong><em>always called in a consistent order</em></strong><em>”</em><strong>. </strong>This should trigger thoughts of arrays as clearly the “index” of the hook matters a great deal. <a href="https://medium.com/u/f3a7b7b027fa">Rudi Yardley</a> does an excellent job discussing how hooks rely on arrays in <a href="https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e"><em>“React Hooks: Not magic, just arrays”</em></a> and I highly recommend giving it a read. At a high-level, the below code shows his “naive” implementation of useState:</p><pre>let state = [];<br>let setters = [];<br>let firstRun = true;<br>let cursor = 0;</pre><pre>function createSetter(cursor) {<br>  return function setterWithCursor(newVal) {<br>    state[cursor] = newVal;<br>  };<br>}</pre><pre>// This is the pseudocode for the useState helper<br>export function useState(initVal) {<br>  if (firstRun) {<br>    state.push(initVal);<br>    setters.push(createSetter(cursor));<br>    firstRun = false;<br>  }</pre><pre>  const setter = setters[cursor];<br>  const value = state[cursor];</pre><pre>  cursor++;<br>  return [value, setter];<br>}</pre><pre>// all credit to Rudi Yardley (<a href="https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e">https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e</a>)</pre><p>You can clearly see the use of multiple arrays in the above implementation: one for state and one for setters. Obviously, the order in which you declare hooks is very important. Messing with this order could result in mismatches between state values and setters and what you expect them to be.</p><h3>Why Follow the Rules?</h3><p>There are <a href="https://reactjs.org/docs/hooks-rules.html">two rules</a> that we must follow when using React hooks. Like my three-year-old daughter, my first question when presented with new rules is “why”. So let’s discuss…</p><h4>Only call hooks at the top level</h4><p>Hooks should only be called at the top-level of your React function components. This means you should not be calling hooks inside conditionals, loops, or nested functions. Following this rule ensures that hooks are always called in a consistent order. React relies upon hooks being called in this consistent order.</p><p>Let’s take a look at a basic example showing how a conditional check could break usage of hooks. First, a valid use of hooks:</p><pre>const [firstName, setFirstName] = useState(&#39;Matt&#39;);</pre><pre>const [location, setLocation] = useState(&#39;Los Angeles&#39;);</pre><p>No conditionals, loops, or nested functions wrapping useState. We’re in good shape! 👍</p><p>However…</p><pre>if (!defaultName) {<br>  const [firstName, setFirstName] = useState(&#39;Matt&#39;);<br>}</pre><pre>const [location, setLocation] = useState(&#39;Los Angeles&#39;);</pre><p>This violates the first rule of hooks. If defaultName always resolves to false then we’d be “safe”, but there’s no guarantee of that. In cases where defaultName is truthy the useState(&#39;Los Angeles&#39;) hook will come first and functionality will be busted. 👎</p><p>If we want to run an effect conditionally, we can put that condition inside our Hook like so:</p><pre>const [firstName, setFirstName] = useState(() =&gt; {<br>  return defaultName || &#39;Matt&#39;;<br>});</pre><pre>const [location, setLocation] = useState(&#39;Los Angeles&#39;);</pre><p>This is obviously a contrived example, but the point is that you can move your conditional logic inside the hook.</p><h4>Only call hooks from React functions</h4><p>Hooks should only be called within React function components or inside custom hooks. Do not call hooks inside regular JavaScript functions. As the React docs state, <em>“by following this rule, you ensure that all stateful logic in a component is clearly visible from its source code”</em>.</p><h4>ESLint plugin</h4><p>Following rules can be hard but thankfully there is an ESLint plugin available which enforces the two above rules, <a href="https://www.npmjs.com/package/eslint-plugin-react-hooks">eslint-plugin-react-hooks</a>.</p><p>If you don’t already have ESLint installed and configured in your project, I highly recommend doing so. After this, simply run:</p><pre>npm install eslint-plugin-react-hooks --save-dev</pre><p>or</p><pre>yarn add eslint-plugin-react-hooks -D</pre><p>Then add the following to your ESLint config:</p><pre>{<br>  &quot;plugins&quot;: [<br>    // ...<br>    &quot;react-hooks&quot;<br>  ],<br>  &quot;rules&quot;: {<br>    // ...<br>    &quot;react-hooks/rules-of-hooks&quot;: &quot;error&quot;, // Checks rules of Hooks<br>    &quot;react-hooks/exhaustive-deps&quot;: &quot;warn&quot; // Checks effect dependencies<br>  }<br>}</pre><p><em>Note: </em><em>eslint-plugin-react-hooks has been included in </em><a href="https://github.com/facebook/create-react-app"><em>create-react-app</em></a><em> since </em><a href="https://github.com/facebook/create-react-app/releases/tag/v3.0.0"><em>v3.0.0</em></a><em>! 🎉</em></p><p>The useSomething naming convention is how the linter plugin is able to find bugs in the code using Hooks. You should <strong>always</strong> name your hooks starting with use....</p><h3>Built-in React Hooks</h3><h4>useState</h4><p>In the past, our only choice when working with state was to spin up a class component and use this.setState to update state. The useState hook allows us to manage state in function components. Basic usage looks like the following:</p><pre>[count, setCount] = useState(0);</pre><p>We use array destructuring ([count, setCount]) to return a pair from our useState invocation. count will be initialized to 0 as that is the value we passed to useState. The update function, setCount in this case, is similar to this.setState in a class, except it <em>does not merge the old and new state together</em>.</p><p>If the initial state is the result of an expensive computation, you may provide a function instead, which will be executed only on the initial render. That scenario would look like this (taken from the <a href="https://reactjs.org/docs/hooks-reference.html#lazy-initial-state">React docs</a>):</p><pre>const [state, setState] = useState(() =&gt; {<br>  const initialState = someExpensiveComputation(props);<br>  return initialState;<br>});</pre><p>Furthermore, if you would like to take the previous state into account when computing the new state, you can pass a function to the setState method and this method will receive the previous state as an argument:</p><pre>&lt;button onClick={() =&gt; setCount(prevCount =&gt; prevCount + 1)}&gt;+&lt;/button&gt;</pre><p>React assumes that if you call useState many times, you do it in the same order during every render.</p><p><a href="https://reactjs.org/docs/hooks-reference.html#usestate">useState</a> is a solid solution if you only have a few state properties to manage. useReducer is the better choice once you have many state properties. We will discuss this next.</p><h4>useReducer</h4><p>useReducer is an alternative to useState and is preferable when you have a lot of state to work with. The signature of useReducer looks like this:</p><pre>const [state, dispatch] = useReducer(reducer, initialArg, init);</pre><p>There are two ways to seed useReducer with an initial state. The simplest approach is to pass the initial state as the second argument like so:</p><pre>const [state, dispatch] = useReducer(<br>  reducer,<br>  {count: initialCount}<br>);</pre><p>The other option is to pass an init function as the third argument like this:</p><pre>function init(initialCount) {<br>  return {count: initialCount};<br>}</pre><pre>const [state, dispatch] = useReducer(reducer, initialCount, init);</pre><p>This approach is handy if you want to extract the logic for calculating the initial state outside the reducer. This also makes it easier to implement a “reset” feature.</p><p>Below is a very basic example of useReducer being used to set and update the state of a NumberManipulator component:</p><pre><em>const</em> initialState = { num: 2 };</pre><pre><em>function</em> reducer(<em>state</em>, <em>action</em>) {<br>  switch (action.type) {<br>    case &#39;double&#39;:<br>      return { num: state.num * 2 };<br>    case &#39;half&#39;:<br>      return { num: state.num / 2 };<br>    case &#39;square&#39;:<br>      return { num: state.num * state.num };<br>    default:<br>      throw new Error();<br>  }<br>}</pre><pre><em>function</em> NumberManipulator() {<br>  <em>const</em> [state, dispatch] = useReducer(reducer, initialState);<br>  return (<br>    &lt;&gt;<br>      Number: {state.num}<br>      &lt;button onClick={() <em>=&gt;</em> dispatch({type: &#39;double&#39;})}&gt;double&lt;/button&gt;<br>      &lt;button onClick={() <em>=&gt;</em> dispatch({type: &#39;half&#39;})}&gt;half&lt;/button&gt;<br>      &lt;button onClick={() <em>=&gt;</em> dispatch({type: &#39;square&#39;})}&gt;square&lt;/button&gt;<br>    &lt;/&gt;<br>  );<br>}</pre><p>If you return the same value from useReducer as the current state, React will bail out without rendering the children or firing effects. This is a nice performance optimization feature (note: for much more on optimizing performance with React Hooks, check out <a href="https://itnext.io/optimizing-react-code-with-hooks-3eaaf5978351">this post</a> by <a href="https://medium.com/u/899d40f807b0">Subhan Naeem</a>).</p><h4>useEffect</h4><p>useEffect can be thought of as a replacement for lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmount, etc.).</p><p>The most basic use of useEffect looks like this:</p><pre>useEffect(() =&gt; {<br>  document.title = &#39;Welcome to &#39; + props.name;<br>});</pre><p>Super simple, right? Actually, there is a lot more to useEffect than it appears at first glance.</p><p>The above code will work, but it will also fire on every single render. We probably don’t want this to be the case. We would prefer that this effect only runs when props.name changes. We can accomplish this by passing an optional second argument to useEffect. This second argument is an array of dependencies and the effect will now only fire when one of the dependencies in this array changes. Let’s update our effect to only fire when props.name changes:</p><pre>useEffect(() =&gt; {<br>  document.title = &#39;Welcome to &#39; + props.name;<br>}, [props.name]);</pre><p>Great! Now, what if we only wanted our effect to fire on the initial render. Maybe we are confident that props.name will never change and we want to ensure our effect only fires once. To accomplish this, we also lean on the optional second argument. In this case, we pass an empty array. This tells useEffect that there are no dependencies and this effect only needs to be called once:</p><pre>useEffect(() =&gt; {<br>  document.title = &#39;Welcome to &#39; + props.name;<br>}, []);</pre><p>While most effects do not require cleanup, some, such as subscriptions, do. So how do we handle cleanup? Do we need to rely on a lifecycle method, componentWillUnmount, after all? No! You can return a function from the function you passed to useEffect and handle any cleanup logic there. This may sound confusing, but this example from the <a href="https://reactjs.org/docs/hooks-reference.html#cleaning-up-an-effect">React docs</a> should help:</p><pre>useEffect(() =&gt; {<br>  const subscription = props.source.subscribe();<br>  return () =&gt; {<br>    // Clean up the subscription<br>    subscription.unsubscribe();<br>  };<br>});</pre><p>This approach can also be used for effects which include event listeners.</p><h4>Additional built-in React hooks</h4><p>There are about a half dozen additional built-in hooks which we will not dive into here but you can learn about on your own through these links to the official React docs:</p><ul><li><a href="https://reactjs.org/docs/hooks-reference.html#usememo">useMemo</a></li><li><a href="https://reactjs.org/docs/hooks-reference.html#usecontext">useContext</a></li><li><a href="https://reactjs.org/docs/hooks-reference.html#usecallback">useCallback</a></li><li><a href="https://reactjs.org/docs/hooks-reference.html#useref">useRef</a></li><li><a href="https://reactjs.org/docs/hooks-reference.html#useimperativehandle">useImperativeHandle</a></li><li><a href="https://reactjs.org/docs/hooks-reference.html#uselayouteffect">useLayoutEffect</a></li><li><a href="https://reactjs.org/docs/hooks-reference.html#usedebugvalue">useDebugValue</a></li></ul><h3>Hooks in the wild</h3><p>I have found that the best way to get comfortable with hooks is to use custom hooks available in libraries I already depend upon. I can then, for example, understand how a hook replaces functionality I previously depended upon through a higher-order component or render prop.</p><h4>Apollo GraphQL hooks</h4><p>I ❤️ working with <a href="https://medium.com/u/9360eb7d79eb">Apollo</a>, so the first custom hooks I utilized were useQuery and useMutation from <a href="https://www.npmjs.com/package/@apollo/react-hooks">@apollo/react-hooks</a>. Here is an example CodeSandbox:</p><p><a href="https://codesandbox.io/s/apollo-graphql-reacthooks-example-gbuus">Apollo GraphQL React-hooks example - CodeSandbox</a></p><p>Here’s the use of useQuery in isolation:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/902/1*_9F6BdCvWOcIukpApWwZZA.png" /></figure><p>I pass a GraphQL query to useQuery and it returns an object with a loading property and a data property. I use loading to display a basic loading indicator. Once data is available, I iterate over data.teams to render my component!</p><p>Here is an example showing the use of useMutation:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hoiqwSYZ9pIdp-HkbB33-g.png" /></figure><p>I pass a GraphQL mutation to useMutation as the first argument. Within the second argument, I pass optional variables. In this case, I need to pass id for this mutation to work. I also added an optional update function which updates the cache on a successful mutation. Prior to hooks, Apollo followed the render props pattern. I had a very easy time translating my legacy use of render props with these custom hooks. Plus, my code is now easier to read and maintain, in my opinion.</p><h4>URQL hooks</h4><p>I also find that looking at the source code behind custom hooks greatly helps me understand how to go about implementing my own custom hooks. I recently began looking through the custom hooks within <a href="https://formidable.com/open-source/urql/">the URQL library</a> from <a href="https://medium.com/u/543b34f6e9c6">Formidable</a>. Below you can see how URQL utilizes the built-in useRef and useMemo hooks to build their useRequest custom hook:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OOnKcvsoQREOvPr0o_rPng.png" /></figure><p>I encourage you to read through <a href="https://github.com/FormidableLabs/urql/tree/master/src/hooks">the URQL hooks source code</a> to gain a deeper understanding of implementing custom hooks!</p><h3>Hooks outside of React</h3><p>While hooks were originally introduced for React, there is no reason they cannot be implemented for other frameworks and also in vanilla JS, and indeed they already have been!</p><h4>VueJS hooks</h4><p>I’m not going to get into the current controversy in the VueJS community, but I will point out that there is an <a href="https://github.com/yyx990803/vue-hooks">experimental library for using React-style hooks in Vue</a>. This repo was spun up by <a href="https://medium.com/u/4f198f5f1f12">Evan You</a> himself.</p><p>There is also an excellent post by <a href="https://medium.com/u/c2509fce86ff">Sarah Drasner</a> which discusses why hooks may be beneficial for Vue, <a href="https://css-tricks.com/what-hooks-mean-for-vue/"><em>“What Hooks Mean for Vue”</em></a><em>!</em></p><h4>TNG-Hooks</h4><p>Hooks can also be used in vanilla JavaScript without a framework like React or Vue thanks to the <a href="https://github.com/getify/TNG-Hooks">TNG-Hooks library</a> created by <a href="https://medium.com/u/5dccb9bb4625">Kyle</a> Simpson. In order to effectively use hooks, we need functions which are both stateful <strong>and</strong> effectful, similar to React function components. Within TNG-Hooks, these functions are referred to as Articulated Functions and are generated by wrapping functions in the TNG hooks-context like so:</p><pre>[renderUsername, onClickUsername] = TNG(renderUsername, onClickUsername);</pre><p>The first example from the TNG-Hooks README should make you feel comfortable right away:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NfkT8KbO0h9L8gAtFZq1gg.png" /></figure><p>Other than wrapping functions in TNG, this all looks <strong>very</strong> familiar after going over React hooks. useState works how you would expect it to!</p><h3>Adoption Strategy</h3><p>To enable Hooks, all of your React packages must be ≥ 16.8.0. Remember that hooks can only be added to function components or used within other custom hooks. While we’re in the early days, the goal is for hooks to cover all use cases for classes as soon as possible, according to the React team. You can incrementally begin adding hooks to your existing apps. You may also begin replacing uses of higher-order components and render props with hooks, although full-scale app rewrites are neither necessary nor encouraged as the introduction of hooks will not “break” legacy solutions. Finally, install <a href="https://www.npmjs.com/package/eslint-plugin-react-hooks">eslint-plugin-react-hooks</a> to ensure you are consistently following the rules of hooks!</p><h3>Takeaways</h3><p>I hope you learned something from this (long) post and feel at least a bit more confident about working with hooks. Please reach out to me with any feedback as I’m sure there are things I have overlooked or could have explained better. Thank you!</p><p>Interested in GraphQL or looking for a lightweight state management solution? Check out <a href="https://engineering.circle.com/https-medium-com-mattdionis-move-over-redux-apollo-client-as-a-state-management-solution-1f9325f96cdd">“Move Over Redux”</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aaacb228959a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/circle-engineering/get-hooked-hooks-in-react-and-beyond-aaacb228959a">Get Hooked: Hooks in React and Beyond</a> was originally published in <a href="https://medium.com/circle-engineering">Circle Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Giving Back: Medium Partner Program + membership gifting]]></title>
            <link>https://medium.com/adventures-in-consumer-technology/giving-back-medium-partner-program-membership-gifting-70c008337779?source=rss-6387214b750d------2</link>
            <guid isPermaLink="false">https://medium.com/p/70c008337779</guid>
            <category><![CDATA[tech]]></category>
            <category><![CDATA[motivation]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[writing]]></category>
            <category><![CDATA[medium]]></category>
            <dc:creator><![CDATA[Matt Dionis]]></dc:creator>
            <pubDate>Wed, 12 Jun 2019 20:23:45 GMT</pubDate>
            <atom:updated>2019-06-27T23:01:34.320Z</atom:updated>
            <content:encoded><![CDATA[<h3>Giving Back: Medium’s Partner Program</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SGo0iCQfbRnd4ZLcsTjybw.jpeg" /></figure><p>I recently joined the <a href="https://medium.com/creators">Medium Partner Program</a> and soon after I stumbled upon the “<a href="https://medium.com/gift-checkout">Gift a membership</a>” feature in Medium. I immediately recognized a potential opportunity to give back to Medium readers. For $50, an annual Medium membership can be gifted to a reader.</p><p>As a point of reference, a <a href="https://engineering.circle.com/https-medium-com-mattdionis-move-over-redux-apollo-client-as-a-state-management-solution-1f9325f96cdd">recent post of mine</a> which had decent readership earned $34.25 in its first week in the Partner Program. One week’s worth of earnings from this single post can almost fund an annual membership for a reader. My personal plan going forward is to produce more consistent, compelling content on Medium both to hopefully inspire and educate others and to fund annual membership gifts.</p><p>My goal is to gift one annual membership each week going forward. This is exciting but what would make it exponentially more impactful is if other writers (most with far greater audiences than I) joined this initiative. Together we could gift hundreds of annual memberships every single week! Medium continues earning revenue, writers broaden their audience, and readers who otherwise could not afford this membership can finally have one.</p><p>One question may be, why not just offer your content for free? I actually do offer mine for free on <a href="https://dionis.dev/">my personal blog</a> but that site has <strong>far</strong> fewer potential readers than Medium and virtually zero discoverability features. Furthermore, writers put time, energy, and emotion into their posts and I feel like compensation is earned. It is certainly not free money.</p><p>Please tag your favorite writers so that we can quickly make this vision a reality. I would love to build up enough momentum that Medium takes notice and joins forces with us to formalize this program and reach as many readers as possible!<br>Thank you!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=70c008337779" width="1" height="1" alt=""><hr><p><a href="https://medium.com/adventures-in-consumer-technology/giving-back-medium-partner-program-membership-gifting-70c008337779">Giving Back: Medium Partner Program + membership gifting</a> was originally published in <a href="https://medium.com/adventures-in-consumer-technology">Adventures in Consumer Technology</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Move Over Redux]]></title>
            <link>https://medium.com/circle-engineering/https-medium-com-mattdionis-move-over-redux-apollo-client-as-a-state-management-solution-1f9325f96cdd?source=rss-6387214b750d------2</link>
            <guid isPermaLink="false">https://medium.com/p/1f9325f96cdd</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[software-engineering]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[graphql]]></category>
            <dc:creator><![CDATA[Matt Dionis]]></dc:creator>
            <pubDate>Fri, 24 May 2019 16:31:29 GMT</pubDate>
            <atom:updated>2019-06-16T19:16:48.252Z</atom:updated>
            <content:encoded><![CDATA[<h3>Move Over Redux: Apollo-Client as a State Management Solution</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NMzhN3iG7iQgWvu3NQfMzw.jpeg" /><figcaption>Use Apollo to launch GraphQL in your project!</figcaption></figure><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplay.ht%2Fembed%2F%3Farticle_url%3Dhttps%3A%2F%2Fmedium.com%2F_p%2Fhttps-medium-com-mattdionis-move-over-redux-apollo-client-as-a-state-management-solution-1f9325f96cdd&amp;url=https%3A%2F%2Fplay.ht%2Farticles%2F1f9325f96cdd&amp;image=https%3A%2F%2F1%2AP9g_4ikKQvCk5LT8PPH0Qw.jpeg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=play" width="700" height="185" frameborder="0" scrolling="no"><a href="https://medium.com/media/741fa9464dd5fed042ad2deec92b67d3/href">https://medium.com/media/741fa9464dd5fed042ad2deec92b67d3/href</a></iframe><h3>Background</h3><p>On the Internal Tools team at <a href="https://www.circle.com">Circle</a>, we recently modernized a legacy PHP app by introducing React components. Just a handful of months after this initiative began we have close to one-hundred React components in this app! 😲</p><p>We recently reached a point where we found ourselves reaching for a state management solution. Note that it took many months and dozens of components before we reached this point. State management is often a tool that teams reach for well before they need it. While integrating a state management solution into an application no doubt comes with many benefits it also introduces complexity so don’t reach for it until you truly need it.</p><p>Speaking of complexity, one complaint about the typical “go-to” state management solution, <a href="https://redux.js.org/">Redux</a>, is that it requires too much boilerplate and can be difficult to hit-the-ground-running with. In this post, we will look at a more lightweight solution which comes with the added benefit of providing some basic GraphQL experience for those who choose to use it.</p><p>On the Circle 🛠 team, we know that our future stack includes GraphQL. In fact, in the ideal scenario, we would have a company-wide data graph at some point and access and mutate data consistently through GraphQL. However, in the short-term, we were simply looking for a low-friction way to introduce GraphQL to a piece of the stack and allow developers to wrap their heads around this technology in a low-stress way. GraphQL as a client-side state management solution using libraries such as <a href="https://github.com/apollographql/apollo-client">apollo-client</a> felt like the perfect way to get started. Let’s take a look at the high-level implementation of a proof-of-concept for this approach!</p><h3>Configuring the client</h3><p>First, there are a number of packages we’ll need to pull in:</p><pre>yarn add @apollo/react-hooks apollo-cache-inmemory apollo-client graphql graphql-tag react react-dom</pre><p>Below you’ll find index.js on the client in its entirety. We’ll walk through the client-side schema specific pieces next:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f8ca0083b898f68457cbc5f268c82b1d/href">https://medium.com/media/f8ca0083b898f68457cbc5f268c82b1d/href</a></iframe><p>First, we define typeDefs and resolvers.</p><p>The AppBarColorSetting type will have required id, name, and setting fields. This will allow us to fetch and mutate the app bar’s color through GraphQL queries and mutations!</p><pre>type AppBarColorSetting {<br>  id: Int!<br>  name: String!<br>  setting: String!<br>}</pre><p>Next up, we define the Query type so that we can fetch the appBarColorSetting:</p><pre>type Query {<br>  appBarColorSetting: AppBarColorSetting!<br>}</pre><p>Finally, you guessed it, we need to define the Mutation type so that we can update appBarColorSetting:</p><pre>type Mutation {<br>  updateAppBarColorSetting(setting: String!): AppBarColorSetting!<br>}</pre><p>Finally, we set up our client. Often, you will find yourself instantiating ApolloClient with alink property. However, since we have added a cache and resolvers, we do not need to add a link. We do, however, add a couple of properties that may look unfamiliar. As of apollo-client 2.6, you can set an assumeImmutableResults property to true to let apollo-client know that you are confident you are not modifying cache result objects. This can, potentially, unlock substantial performance improvements. To enforce immutability, you can also add the freezeResults property to inMemoryCache and set it to true. Mutating frozen objects will now throw a helpful exception in strict mode in non-production environments. To learn more, read the <a href="https://blog.apollographql.com/whats-new-in-apollo-client-2-6-b3acf28ecad1">“What’s new in Apollo Client 2.6”</a> post from <a href="https://medium.com/u/540bbf1a0d2b">Ben Newman</a>.</p><pre>const client = new ApolloClient({<br>  cache: new InMemoryCache({<br>    freezeResults: true<br>  }),<br>  typeDefs,<br>  resolvers,<br>  assumeImmutableResults: true<br>});</pre><p>That’s it! Now, simply pass this client to ApolloProvider and we’ll be ready to write our query and mutation! 🚀</p><pre>const TogglesApp = () =&gt; (<br>  &lt;ApolloProvider client={client}&gt;<br>    &lt;App /&gt;<br>  &lt;/ApolloProvider&gt;<br>);</pre><h3>Querying client-side data</h3><p>We’re now going to query our client cache using GraphQL. Note that in this proof-of-concept, we simply define the initial state of our userSettings in a JSON blob:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/41ebea5dffdeb1922cc797ecaacbe443/href">https://medium.com/media/41ebea5dffdeb1922cc797ecaacbe443/href</a></iframe><p><em>Note the need to define the type with the </em><em>__typename property.</em></p><p>We then define our query in its own .js file. You could choose to define this in the same file the query is called from or even in a .graphql file though.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d6364f6f1e30221c60bd88a4752e3057/href">https://medium.com/media/d6364f6f1e30221c60bd88a4752e3057/href</a></iframe><p>The most important thing to notice about this query is the use of the @client directive. We need to add this to both the appBarColorSetting query as well as each of the id, name and setting fields as they are all client-specific. Let’s take a look at how we call this query next:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/abf8c3d8177dbc34b35fbd7197b0765f/href">https://medium.com/media/abf8c3d8177dbc34b35fbd7197b0765f/href</a></iframe><p><em>Note: we are using </em><a href="https://material-ui.com/"><em>Material-UI</em></a><em> in this app, but obviously the UI framework choice is up to you. 🤷‍♂️</em></p><p>Some bonus material: we are using the beta version of <a href="https://www.npmjs.com/package/@apollo/react-hooks">apollo/react-hooks</a> here!</p><pre>const { loading, data } = useQuery(APP_BAR_COLOR_SETTING_QUERY);</pre><p>We show a basic loading indicator and then render the app bar with data.appBarColorSetting.setting passed into the color attribute. If you are using the Apollo Client Developer Tools, you’ll be able to clearly see this data sitting in the cache.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*lfXIeGVZrB7mBHL0sVt6_w.png" /></figure><h3>Mutating client-side data and updating the cache</h3><p>You may have noticed this block of code in our App component. This simply alternates the value of setting based on its current value and passes it to our SettingsComponent. We will take a look at this component and how it triggers a GraphQL mutation next.</p><pre>&lt;SettingsComponent<br>  setting={<br>    data.appBarColorSetting.setting === &quot;primary&quot; ? &quot;secondary&quot; : &quot;primary&quot;<br>  }<br>/&gt;</pre><p>First, let’s take a peek at our mutation:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/96f3665149d9da32134c4f85a91efe20/href">https://medium.com/media/96f3665149d9da32134c4f85a91efe20/href</a></iframe><p>Again, notice the use of the @client directive for our client-side updateAppBarColorSetting mutation. This mutation is very simple: pass in a required setting string and update the setting.</p><p>Below you will find all the code within our SettingsComponent which utilizes this mutation:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a23c4ad17cb7fe1ac9137b031334123d/href">https://medium.com/media/a23c4ad17cb7fe1ac9137b031334123d/href</a></iframe><p>The interesting piece of this code that we want to focus on is the following:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c206db2ae31aa10ebe843e4c84b43730/href">https://medium.com/media/c206db2ae31aa10ebe843e4c84b43730/href</a></iframe><p>Here, we make use of the apollo/react-hooks useMutation hook, pass it our mutation and variables, then update the cache within the update method. We first read the current results for the APP_BAR_COLOR_SETTING_QUERY from the cache then update appBarColorSetting.setting to the setting passed to this component as a prop, then write the updated appBarColorSetting back to APP_BAR_COLOR_SETTING_QUERY. Notice that we do <strong>not</strong> update the data object directly, but instead make a clone of it and update setting within the clone, then write the cloned data object back to the cache. This triggers our app bar to update with the new color! We are now utilizing apollo-client as a client-side state management solution! 🚀</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/675/1*ruhx_t_ZbBWWDRiViplImg.gif" /></figure><h3>Takeaways</h3><p>If you’d like to dig into the code further, the <a href="https://codesandbox.io/s/eloquent-johnson-fym98">CodeSandbox can be found here</a>. This is admittedly a very contrived example but it shows how easy it can be to <a href="https://www.apollographql.com/docs/react/essentials/local-state">leverage apollo-client as a state management solution</a>. This can be an excellent way to introduce GraphQL and the Apollo suite of libraries and tools to a team who has little to no GraphQL experience. Expanding use of GraphQL is simple once this basic infrastructure is in place.</p><p>I would love to hear thoughts and feedback from everyone and I hope you learned something useful through this post!</p><p>If you found this post helpful, please 👏 for it to fund free Medium memberships for other readers! To learn more about this initiative, check out: <a href="https://medium.com/@mattdionis/giving-back-medium-partner-program-membership-gifting-70c008337779">“Giving Back: Medium Partner Program + membership gifting”</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1f9325f96cdd" width="1" height="1" alt=""><hr><p><a href="https://medium.com/circle-engineering/https-medium-com-mattdionis-move-over-redux-apollo-client-as-a-state-management-solution-1f9325f96cdd">Move Over Redux</a> was originally published in <a href="https://medium.com/circle-engineering">Circle Engineering</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Want to grasp the benefits of GraphQL? Picture your ideal restaurant menu.]]></title>
            <link>https://medium.com/@mattdionis/want-to-grasp-the-benefits-of-graphql-picture-your-ideal-restaurant-menu-7aeb0e59b738?source=rss-6387214b750d------2</link>
            <guid isPermaLink="false">https://medium.com/p/7aeb0e59b738</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[apollo]]></category>
            <category><![CDATA[api]]></category>
            <category><![CDATA[graphql]]></category>
            <category><![CDATA[javascript]]></category>
            <dc:creator><![CDATA[Matt Dionis]]></dc:creator>
            <pubDate>Mon, 30 Oct 2017 15:01:39 GMT</pubDate>
            <atom:updated>2019-06-16T19:18:05.139Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*N4uOGPQW12aOZ1A2zQpRYg.jpeg" /></figure><iframe src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fplay.ht%2Fembed%2F%3Farticle_url%3Dhttps%3A%2F%2Fmedium.com%2F_p%2Fwant-to-grasp-the-benefits-of-graphql-picture-your-ideal-restaurant-menu-7aeb0e59b738&amp;url=https%3A%2F%2Fplay.ht%2Farticles%2F7aeb0e59b738&amp;image=https%3A%2F%2F1%2AP9g_4ikKQvCk5LT8PPH0Qw.jpeg&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=play" width="700" height="185" frameborder="0" scrolling="no"><a href="https://medium.com/media/14cd9d16fed895a57644ae7463ad8a46/href">https://medium.com/media/14cd9d16fed895a57644ae7463ad8a46/href</a></iframe><p>Let’s set the scene: It’s a fall Friday evening and you have just been seated at a restaurant you have been excited to try, <em>The Underfetching Farmhouse</em>. The waiter brings over the menu and you immediately notice that it seems, well…<em>sparse</em>. In the middle of this sheet of white paper are four words: appetizers, entrees, drinks, dessert. Not wanting to embarrass yourself you decide to just “go with the flow”. Hey, maybe this is a new “hip and edgy” way to order. Play it cool. The waiter returns a few minutes later and you state that you are interested in appetizers, entrees, and drinks. The waiter nods in approval and heads off in a hurry. He returns with an appetizers menu then scoots off again. A minute later he is back again with a list of entrees. He runs back to his station yet again and then quickly returns with a drink menu. While progress has certainly been made, you are still rather underwhelmed with what has been provided to you. You now know what appetizers, entrees, and drinks are available, but that’s it. No descriptions, no prices. Turns out the waiter will have to make another roundtrip for the description of each menu item you are interested in and yet another for the price. <em>Underfetching</em> indeed! You’ve had enough and decide to leave and try another spot down the street.</p><p>You arrive at the second restaurant of the evening, <em>The Organic Overfetch</em>, ready to quickly order as you are now starving. When your waiter greets you, you explain your recent experience and the waiter giggles as he promises you will not run into the same frustration at this establishment. He leaves for what feels like an eternity and when he returns he places what appears to be a medium-sized novel on the table. You slowly open this book and realize it is the menu. There are categories, menu items, descriptions, ingredients, prices, nutritional information, images, chef biographies. Try as you may, you become lost in this menu and have a very difficult time finding the information you are interested in. In your frustration you storm out of this business as well.</p><p>As you reach the sidewalk you glance across the street and notice a new restaurant that you have been hearing a lot of chatter about. The <em>GraphQL Cafe</em> is beckoning and you decide to give it a try. You are quickly seated and the waiter asks you what information you would like on your menu. This seems like an odd question, but you play along. “I would like to see the name, description, and price for each of your appetizers, entrees, and drinks”, you say. Within seconds your waiter returns with a small menu matching exactly what you requested. You order and settle in for a relaxing dinner thinking, “this is the way it <em>should</em> be.”</p><p>If you’ve worked with REST APIs, you can surely relate to this poor diner’s experience at <em>The Underfetching Farmhouse </em>and<em> The Organic Overfetch. </em>As developers, we are constantly trying to balance how much data we return from our API endpoints. Do you provide just enough and then make the client call additional endpoints to get more details? Do you provide everything the client could possibly need in one giant data blob? Thankfully there is now another option. GraphQL solves both the underfetching and overfetching problems by allowing clients to ask for exactly what they need from the server. Want to see the name, description, and price for entrees? Just call your single /graphql endpoint with this simple, descriptive query:</p><pre>query getMenu(category: String!) {<br>  menu(category: “entrees”) {<br>    name<br>    description<br>    price<br>  }<br>}</pre><p>There are many more benefits and tons of exciting possibilities that GraphQL makes possible! This post is simply meant to point out two of the major issues that GraphQL solves and hopefully get you excited about digging deeper. To learn more about the technical “nitty-gritty” check out the <a href="http://facebook.github.io/graphql/October2016/">GraphQL spec</a>.🤓 For some awesome step-by-step tutorials about all things GraphQL, both server-side and client-side, check out <a href="https://www.howtographql.com/">HowToGraphQL</a>. You may want to get started with GraphQL through a backend development framework. If so, check out <a href="https://www.graph.cool/">Graphcool</a>.😎 For an incredible suite of tools to help you optimize the apps you build with GraphQL, there is no better option than <a href="http://dev.apollodata.com/">Apollo</a>!🚀 Also, feel free to reach out to me on <a href="https://twitter.com/MattDionis">Twitter</a>. I am always excited to talk all things GraphQL!😍</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7aeb0e59b738" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[VueJS unit tests as a learning tool: v-text versus v-html]]></title>
            <link>https://medium.com/vuefinder/vuejs-unit-tests-as-a-learning-tool-v-text-versus-v-html-12b1ae64c09c?source=rss-6387214b750d------2</link>
            <guid isPermaLink="false">https://medium.com/p/12b1ae64c09c</guid>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[vuejs]]></category>
            <category><![CDATA[vue]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Matt Dionis]]></dc:creator>
            <pubDate>Sat, 05 Aug 2017 14:15:33 GMT</pubDate>
            <atom:updated>2017-08-05T14:53:43.803Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fXBo56b0tanSCNHo4O2eWw.jpeg" /><figcaption>Working with `v-text` &amp;`v-html`. Photo by <a href="https://unsplash.com/photos/5Ntkpxqt54Y?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Sai Kiran Anagani</a> on <a href="https://unsplash.com/?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p><em>This is the fourth post in a series which dives into unit tests within the </em><a href="https://github.com/vuejs/vue"><em>VueJS code base</em></a><em> in order to gain a deeper understanding of how elements within the Vue ecosystem work. I recommend checking out the </em><a href="https://medium.com/vuefinder/vuejs-unit-tests-as-a-learning-tool-v-show-f29d3986bced"><em>first post on v-show</em></a><em>, </em><a href="https://medium.com/vuefinder/vuejs-unit-tests-as-a-learning-tool-v-if-ad66f1c363ff"><em>second post on v-if</em></a><em>, and </em><a href="https://medium.com/@mattdionis/vuejs-unit-tests-as-a-learning-tool-v-for-2805e60bbff"><em>third post on v-for</em></a><em> before diving into this article.</em></p><p><em>Beyond alerting one to regressions in a code base, well-written unit tests read like simple sentences and help those working on a project to understand what individual features do. Unit tests can also serve as great templates for documentation if they are written well as they should describe what a feature does and how it reacts to different inputs.</em></p><p><em>The </em><a href="https://vuejs.org/v2/api/"><em>VueJS documentation</em></a><em> is excellent, but recently I decided to dig even deeper and begin exploring the source code behind Vue! The first piece of the code base I visited was the </em><a href="https://github.com/vuejs/vue/tree/dev/test"><em>tests directory</em></a><em>. Most of you have surely heard of </em><a href="https://medium.com/javascript-scene/tdd-the-rite-way-53c9b46f45e3"><em>Test Driven Development (TDD)</em></a><em>. Well, in this series I would like to introduce you to Test Driven Learning (TDL). The idea is to begin reading through the unit tests of the framework or library you are using early in order to gain a deeper understanding of how individual features work. TDL also has a beneficial side-effect in that it will reinforce the benefits of writing unit tests in your own projects and reveal solid testing patterns.</em></p><h4>‘v-text’ versus ‘v-html’ unit tests</h4><p>In this third post in the series we will take a look at the v-text and v-html directives. The v-text unit tests can be found <a href="https://github.com/vuejs/vue/blob/dev/test/unit/features/directives/text.spec.js">here</a> and the v-html unit tests <a href="https://github.com/vuejs/vue/blob/dev/test/unit/features/directives/html.spec.js">here</a>, but we will be walking through them piece-by-piece below.</p><p>First up, v-text! The first test is very basic and simply tests that the string bound to the a data property is rendered as the element’s innerHTML. If you feel like this seems familiar it is because v-text works just like {{}} interpolation. &lt;div v-text=”a”&gt;&lt;/div&gt; renders the same output as &lt;div&gt;{{a}}&lt;/div&gt;.</p><p>The next test is a bit more interesting as it reveals what happens when you pass HTML markup to v-text. It appears that v-text encodes HTML entities such as &lt; and &gt;.</p><p>The final block of tests shows how v-text behaves with several different value types. Booleans, arrays, objects, strings, numbers, and even spaces will be rendered as their string equivalents: “false”, “[]”, “{}”, “abc”, “123”, “ “, respectively. null and undefined are rendered as empty strings.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d3a63ee80133922dbe5a2600ceeebc5d/href">https://medium.com/media/d3a63ee80133922dbe5a2600ceeebc5d/href</a></iframe><p>Let’s say we’re working on a project and find that we need to render HTML markup. We cannot rely on v-text as we have learned that it will encode this markup. Where do we turn? Another directive, aptly named v-html!</p><p>The first test below should look familiar as it is the exact same as the first test for v-text. This shows us that passing a basic string to v-html will render it the same as v-text or interpolation would.</p><p>The second test is more interesting and differs from v-text in an important way. When passed HTML entities, v-html will render them as plain HTML rather than encoding them. Note that the &lt; symbol within the span is encoded properly as expected.</p><p>The next couple tests reveal other ways this directive can be used. HTML entities can be passed inline as well as inline in the DOM. The final block of tests is identical to the final block of tests for v-text and shows how different value types will be rendered.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/30297c29a9b792d4e906608644ecac59/href">https://medium.com/media/30297c29a9b792d4e906608644ecac59/href</a></iframe><h4>‘v-text’ and ‘v-html’ docs</h4><p>The <a href="https://vuejs.org/v2/api/#v-text">v-text</a> and <a href="https://vuejs.org/v2/api/#v-html">v-html</a> API docs sections should make complete sense to us now that we have studied the unit tests:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NU-cLGBVzJM0ZMFKN5zlHw.png" /></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gaGjDR1HWulj0WLHIu8vrw.png" /></figure><p>As I mentioned earlier, the VueJS docs are excellent, but I would argue that reading through the unit tests behind v-text and v-html taught us all that the docs reveal and more in just a couple minutes of reading! Also, as I mentioned, reading through the tests taught us how unit tests should be written and how thorough they should be. Writing similar tests for features within your own apps should become a priority for you and your team!</p><h4>Next up</h4><p>In the next post, to be published soon, we will take a deep dive into the v-class unit tests!</p><h4>Previous posts</h4><ul><li><a href="https://medium.com/vuefinder/vuejs-unit-tests-as-a-learning-tool-v-show-f29d3986bced">v-show</a></li><li><a href="https://medium.com/vuefinder/vuejs-unit-tests-as-a-learning-tool-v-if-ad66f1c363ff">v-if</a></li><li><a href="https://medium.com/@mattdionis/vuejs-unit-tests-as-a-learning-tool-v-for-2805e60bbff">v-for</a></li></ul><p><strong>If you enjoyed this post please hit the little</strong> 💚 <strong>below to let me know you’d like more of this material! Thanks!</strong> 🤓</p><p><em>Interested in building the future of money at </em><a href="https://www.circle.com"><em>Circle</em></a><em>? We’re </em><a href="https://jobs.lever.co/circle?lever-via=HvpG9MgLuI"><em>hiring</em></a><em>!</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=12b1ae64c09c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/vuefinder/vuejs-unit-tests-as-a-learning-tool-v-text-versus-v-html-12b1ae64c09c">VueJS unit tests as a learning tool: v-text versus v-html</a> was originally published in <a href="https://medium.com/vuefinder">Vuefinder</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>