<?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"><channel><title><![CDATA[Black Girl Bytes]]></title><description><![CDATA[I'm a Developer Advocate at GitHub. I'm passionate about community, code, and education! Reach out to me on [Twitter](https://twitter.com/blackgirlbytes) ❤️]]></description><link>https://blackgirlbytes.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1630710061987/Lyn1m7cs-.png</url><title>Black Girl Bytes</title><link>https://blackgirlbytes.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 12 May 2026 09:23:39 GMT</lastBuildDate><atom:link href="https://blackgirlbytes.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Your AI Agent isn't an Engineer]]></title><description><![CDATA[Raise your hand if you've been personally victimized by the question: 'Will AI replace software engineers?' It's a common debate that drives developers to extremes—either avoiding AI entirely or frantically signing up for every AI course available.

...]]></description><link>https://blackgirlbytes.dev/your-ai-agent-isnt-an-engineer</link><guid isPermaLink="true">https://blackgirlbytes.dev/your-ai-agent-isnt-an-engineer</guid><category><![CDATA[AI]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[agents]]></category><category><![CDATA[agentic AI]]></category><category><![CDATA[openai]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Mon, 17 Feb 2025 05:14:52 GMT</pubDate><content:encoded><![CDATA[<p>Raise your hand if you've been personally victimized by the question: 'Will AI replace software engineers?' It's a common debate that drives developers to extremes—either avoiding AI entirely or frantically signing up for every AI course available.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vxan70t5wtzh7b90zpfs.jpeg" alt="Mean Girls" /></p>
<h2 id="heading-why-this-conversation-matters">Why This Conversation Matters</h2>
<p>However, it's not a hypothetical or frivolous concern. Companies <em>are</em> making hiring decisions based on AI productivity. <a target="_blank" href="https://www.salesforceben.com/salesforce-will-hire-no-more-software-engineers-in-2025-says-marc-benioff/">Salesforce's CEO recently announced</a> plans to reduce hiring software and support engineers after seeing a 30% productivity boost from AI.</p>
<p>As a Developer Advocate in AI, my public response has always been to upskill and adapt to the changing economy. After all, you wouldn't want to be the person insisting on driving a horse and buggy while everyone else has moved on to cars.</p>
<p>I believe that AI <strong><em>is</em></strong> a helpful tool. I've used it to understand new technologies and quickly prototype ideas.</p>
<p>But internally, I've wrestled with a different question: Why do we keep framing AI primarily as a replacement for human beings?</p>
<h2 id="heading-how-ai-marketing-shaped-this-perception">How AI Marketing Shaped This Perception</h2>
<p>My spicy take is that our industry helped shape this narrative. We inadvertently leaned into a lazy marketing strategy prioritizing quick wins over sustainable adoption. It's easier to tell VCs and executives that your AI tool replaces developers than to demonstrate how it augments developer capabilities.</p>
<h3 id="heading-anthropomorphism-is-not-all-bad">Anthropomorphism Is Not All Bad</h3>
<p>Anthropomorphism is the practice of assigning human traits to non-human entities. It isn't inherently problematic. In fact, it's a common practice in tech. Thoughtful anthropomorphism makes digital experiences more intuitive and helps users embrace new interfaces. For example:</p>
<ul>
<li><p>E-books mirror traditional reading experiences by simulating page-turning animations, even though there's no physical page to turn.</p>
</li>
<li><p>Electric cars (as <a target="_blank" href="https://bsky.app/profile/threepointone.bsky.social/post/3lbepxmdwek23">Sunil Pai pointed out to me</a>) play pre-recorded engine sounds when they start, providing a familiar affordance for drivers.</p>
</li>
</ul>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3sq0na03klvr9ag57z4o.png" alt="Sunil Pais bluesky post about electric cars and prerecorded engines" /></p>
<p>In these cases, users don't actually believe their e-book contains paper or that their electric car has a combustion engine.</p>
<p>But, AI presents a unique challenge. Its complexity and "black box" nature make it harder for users to grasp its true capabilities and limitations. To bridge this knowledge gap, companies lean heavily into human-like descriptions:</p>
<h4 id="heading-claude-is-a-friend">Claude is a "friend."</h4>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/awydtnqmap1ksu35hw59.jpeg" alt="Billboard that says Claude is a friend" /></p>
<h4 id="heading-devin-is-an-ai-software-engineer">Devin is an "AI Software Engineer."</h4>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/murz9pox05w30p94u63e.png" alt="Blog post about Devin as an AI software engineer" /></p>
<h4 id="heading-chatgpt-is-reasoning">ChatGPT is "reasoning."</h4>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/524ip1yl0gjt4tpfiq5a.png" alt="a screenshot of chatgpt that said reasoned for a few seconds" /></p>
<p>While these descriptions make AI feel more familiar, the drawback is that they can also mislead users to believe that AI can think, reason, and work independently like humans.</p>
<h2 id="heading-the-problem-with-marketing-ai-as-a-human">The Problem with Marketing AI as a Human</h2>
<p>Anthropomorphic AI marketing is sometimes a form of self-sabotage because:</p>
<h3 id="heading-it-alienates-developers">It Alienates Developers</h3>
<ul>
<li><p>When AI is marketed as an "engineer" or "developer, " decision-makers view it as a one-to-one substitute for human talent.</p>
</li>
<li><p>This is counterproductive because developers are some of the most valuable users of AI tools. They are the users who know how to use AI and contribute to the ecosystem effectively. According to the <a target="_blank" href="https://survey.stackoverflow.co/2024/ai#1-ai-tools-in-the-development-process">2024 Stack Overflow Developer Survey</a>, 76% of developers currently use or plan to incorporate AI into their workflows. However, our industry's marketing suggests that using AI and contributing to the ecosystem will eventually put AI in a place to take their jobs. So why would they want to further the movement?</p>
</li>
</ul>
<h3 id="heading-it-sets-unrealistic-expectations">It Sets Unrealistic Expectations</h3>
<ul>
<li><p>If an AI tool is marketed as "just like a human," users will expect it to perform at human levels.</p>
</li>
<li><p>AI is a non-sentient tool that processes historical data patterns, is prone to hallucinating, misses important context, and provides non-deterministic output.</p>
</li>
<li><p>When developers realize it's not as good as the marketing implied, the company and product risk losing credibility. Developers are notorious for valuing authenticity. Over-exaggeration or misrepresentation in marketing only drives developers away.</p>
</li>
</ul>
<p>But don't take my word for it. A Wired article titled <a target="_blank" href="https://www.wired.com/story/video-game-industry-artificial-intelligence-developers/">Developers Are Getting Fed Up With Their Bosses' AI Initiatives</a> shares findings from the <a target="_blank" href="https://reg.gdconf.com/state-of-game-industry-2025">2025 Game Developer Conference Survey</a>. While 52% of companies now use generative AI in their games, 30% of surveyed developers expressed negative sentiment.</p>
<p>One survey participant shared their reflections: "I have a PhD in AI, worked to develop some of the algorithms used by generative AI. I deeply regret how naively I offered up my contributions."</p>
<p>Another participant stated, "We should use generative AI to help people be faster at their jobs, not lose them."</p>
<h3 id="heading-it-misses-the-real-value-proposition">It Misses the Real Value Proposition</h3>
<p>The real value of AI developer tools includes automating boring tasks, faster prototyping, and quicker debugging, which leaves more time for creative problem-solving.</p>
<h2 id="heading-the-year-of-the-agent">The "Year of the Agent"</h2>
<p>And now, AI enthusiasts have dubbed 2025 as the Year of the Agent. In short, <a target="_blank" href="https://aws.amazon.com/what-is/ai-agents/">AI agents</a> are tools that can autonomously take action on our behalf, like executing shell commands, creating calendar events, and building applications. But as we move from LLMs that suggestion code to us to more autonomous agents, anthropomorphic marketing is only increasing.</p>
<h2 id="heading-framework-for-effectively-marketing-ai-agents-to-developers">Framework for Effectively Marketing AI Agents to Developers</h2>
<p>Here's how to market AI developer tools in a way that both builds trust and differentiates your Agent in an oversaturated market:</p>
<h3 id="heading-understand-how-it-works">Understand How It Works</h3>
<p>If you work in Developer Relations, Sales, Marketing, or as an executive promoting an AI agent, you're probably representing a product you didn't build. This means you may not fully understand how the tool works, its true capabilities, or its limitations. Developers have a knack for spotting misrepresentation or inauthentic marketing.</p>
<p>You can mitigate this challenge by:</p>
<ul>
<li><p>Becoming customer zero</p>
<ul>
<li>Use the product extensively before it reaches the public</li>
</ul>
</li>
<li><p>Investing time in learning the following fundamentals:</p>
<ul>
<li><p>LLMs and their capabilities</p>
</li>
<li><p>Key differences between Copilots and Agents</p>
</li>
<li><p>Core AI Agent operations and your product's unique approach</p>
</li>
<li><p>Token handling and context management</p>
</li>
<li><p>Tool calling mechanisms</p>
</li>
<li><p>System limitations</p>
</li>
<li><p>Points requiring human intervention</p>
</li>
<li><p>Your product's agentic loop. For example, some agents use the following loop:</p>
<ul>
<li><p>Accept user request</p>
</li>
<li><p>Share requests and available tools with an LLM</p>
</li>
<li><p>Receive LLM's execution plan</p>
</li>
<li><p>Execute the plan and tool calls</p>
</li>
<li><p>Verify results with the LLM</p>
</li>
<li><p>Revise and re-execute if needed</p>
</li>
<li><p>Deliver final results to the user and wait for the user's request</p>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>I used these two resources to help me understand AI agents:</p>
<ul>
<li><p><a target="_blank" href="https://www.kaggle.com/whitepaper-agents">Google's White Paper</a></p>
</li>
<li><p><a target="_blank" href="https://www.anthropic.com/research/building-effective-agents">Anthropic's White Paper</a></p>
</li>
</ul>
<h3 id="heading-thoughtful-naming">Thoughtful Naming</h3>
<p>It might be difficult to eliminate anthropomorphism entirely, especially since it is useful. My advice is to use it sparingly. Skip titles like "AI Engineer" or "AI Teammate." Choose names that set clear expectations, like Copilot, Agent, or Assistant. GitHub's use of "Copilot" and "AI Pair Programming Assistant" exemplifies this balance because it suggests collaboration while keeping humans in control.</p>
<h3 id="heading-augmentation-gt-replacement">Augmentation &gt; Replacement</h3>
<p>Let's understand who developers are. They're not rockstar/ninja/10x developers. Those stereotypes are so 2014.</p>
<p>Developers juggle multiple roles – they're parents, open source maintainers, bootcamp instructors, and more. AI agents shine brightest when they complement these diverse responsibilities, taking on parallel tasks while developers focus on high-impact work. Instead of marketing your tools as whole substitutes for developers, position them as tools part of a developer's toolkit.</p>
<p>I expand more on this thought in my blog post titled, "<a target="_blank" href="https://dev.to/blackgirlbytes/the-average-developer-is-a-multitasker-a-case-for-agents-832">The Average Developer is a Multitasker: A Case for Agents</a>."</p>
<h3 id="heading-transparency">Transparency</h3>
<p>If possible, go open source. If not, find ways to explain the architecture through whitepapers and conference talks. This approach will help your users understand that it's not magic so they can determine how to use the product and get the best performance from it.</p>
<p>Many times, when there's a lack of transparency, developers will theorize how they think it works and create their own narrative, which can backfire on your product. I remember this happened in the early days of GitHub Copilot. I would hop into Twitter Spaces, where people would share how they thought it worked, but they were wrong and spreading misinformation.</p>
<h3 id="heading-developer-control">Developer Control</h3>
<p>You can build trust with developers by putting them in control of their workflow. Here are some of my suggestions:</p>
<ul>
<li><p>Similar to how developers choose IDE settings, allow developers to choose their preferred LLM models and customize the Agent's behavior and verbosity.</p>
</li>
<li><p>Show what actions the Agent will take before executing them and provide detailed logs for debugging.</p>
</li>
<li><p>Provide APIs and hooks so the Agent fits into existing workflows.</p>
</li>
</ul>
<p><a target="_blank" href="http://block.github.io/goose">codename goose</a> is my favorite example of this, although I'm biased because it's an agent my company made. It's open source. Goose, as it's fondly called, lets developers choose their LLM model and extensions via <a target="_blank" href="https://www.anthropic.com/news/model-context-protocol">Model Context Protocol</a>. Developers can also choose to interact with the Agent via the CLI or GUI.</p>
<h3 id="heading-show-dont-tell">Show, Don't Tell</h3>
<p>Instead of making false promises, demonstrate your AI agent's value through concrete examples. Create short, engaging video demos, GIFs, or blog posts showing the Agent in action:</p>
<ul>
<li><p>Creating and running test suites</p>
</li>
<li><p>Converting code between languages</p>
</li>
<li><p>Transforming wireframes into interactive UIs</p>
</li>
<li><p>Generating API documentation from code comments</p>
</li>
<li><p>Automating environment setup</p>
</li>
<li><p>Reviewing pull requests</p>
</li>
</ul>
<p>Don't be afraid to demo live and make it fun so it can be memorable! When I worked at GitHub, I used to demo GitHub Copilot at conferences. I would prompt GitHub Copilot to post a tweet that said, "I wrote this tweet with Copilot." It was a short and simple demo that was memorable for attendees and sparked curiosity from those who weren't there.</p>
<p><strong>Note</strong>: Demoing generative AI tools live is scary because the output is non-deterministic. If your live demo fails, that's even better because you can use it as a teaching moment. Show how you work around issues and where human expertise adds value. This authenticity builds more trust than a perfectly polished demo ever could.</p>
<h3 id="heading-documentation">Documentation</h3>
<p>Documentation often determines whether developers adopt your tool. Strong documentation for your Agent could include:</p>
<ul>
<li><p>Installation guides</p>
</li>
<li><p>Accurate technical specifications of model training and limitations</p>
</li>
<li><p>Comprehensive feature guides</p>
</li>
<li><p>Step-by-step tutorials</p>
</li>
<li><p>Prompt playbooks</p>
</li>
<li><p>Clear explanations of data usage and privacy</p>
</li>
</ul>
<h3 id="heading-open-collaboration">Open Collaboration</h3>
<p>Build product credibility by fostering an ecosystem where developers can learn from each other, and you can learn from them. You can do this by:</p>
<ul>
<li><p>Using platforms like GitHub Discussions and Discord to create spaces for feedback and support</p>
</li>
<li><p>Encouraging knowledge sharing by letting developers exchange prompts, best practices, and integrations</p>
</li>
<li><p>Recognizing community contributions, like open source extensions or insightful bug reports</p>
</li>
<li><p>Maintaining a transparent feedback loop to show that you value developer input</p>
</li>
</ul>
<p>A great example is <a target="_blank" href="http://Cursor.directory">Cursor.directory</a> - a platform by and for the community where developers share <code>.cursorrules</code> prompts.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Our presentation of AI shapes how the world perceives and uses it. Let's move beyond the tired question of whether AI will replace developers and focus on how it can augment developer capabilities.</p>
<p>Share your thoughts below!</p>
]]></content:encoded></item><item><title><![CDATA[What Text Area Popovers Taught Me About Browser APIs]]></title><description><![CDATA[I recently went down several rabbit holes about building WYSIWYG editors and popovers. While on maternity leave, I finally have time to deeply explore random technical problems without deadlines - a rare opportunity.
Thus far, I've focused on contrib...]]></description><link>https://blackgirlbytes.dev/what-text-area-popovers-taught-me-about-browser-apis</link><guid isPermaLink="true">https://blackgirlbytes.dev/what-text-area-popovers-taught-me-about-browser-apis</guid><category><![CDATA[Web Development]]></category><category><![CDATA[Browsers]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Open Source]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Wed, 29 Jan 2025 06:08:34 GMT</pubDate><content:encoded><![CDATA[<p>I recently went down several rabbit holes about building WYSIWYG editors and popovers. While on maternity leave, I finally have time to deeply explore random technical problems without deadlines - a rare opportunity.</p>
<p>Thus far, I've focused on contributing to an open source AI agent called <a target="_blank" href="https://block.github.io/goose">codename goose</a> built with a Rust backend and Electron-based chat interface. I submitted a <a target="_blank" href="https://github.com/block/goose/pull/542">pull request</a> to add a WYSIWYG editor to its chat interface, opting to build a custom solution instead of using existing packages. The maintainers appreciated this approach since editor dependencies bloat bundle size, but raised concerns about the toolbar consuming too much visual space. They suggested implementing a popover toolbar instead.</p>
<p>I wrongly assumed creating a floating toolbar would be simple. I aimed to:</p>
<ul>
<li><p>Show a popover toolbar when text is selected</p>
</li>
<li><p>Position it precisely above the selection</p>
</li>
<li><p>Handle word-wrapped text spanning multiple lines</p>
</li>
<li><p>Maintain accurate positioning during scroll</p>
</li>
</ul>
<p>Handling popovers in a text area element turned out to be more complex than expected. In this blog post, I’ll share what I learned.</p>
<h2 id="heading-text-areas-arent-your-average-dom-elements">Text areas aren’t your average DOM elements.</h2>
<p>Unlike typical HTML elements where we can manipulate contents, measure positions, and add new elements, text areas only expose raw text content and basic selection APIs. Browsers control their rendering behind the scenes.</p>
<p>I asked Claude to generate an analogy for further illustration:</p>
<ul>
<li><p><strong>Regular HTML elements</strong> are like having a house where you can move the furniture around, add new items, measure distances between things, etc.</p>
</li>
<li><p><strong>Text areas</strong> are more like looking through a window into a room you can't enter. You can see what's inside and make some basic changes (like adding/removing text), but you can't reach in and manipulate things directly. The browser handles all the internal workings using native OS text editing capabilities.</p>
</li>
</ul>
<h2 id="heading-popovers-outside-of-text-areas">Popovers outside of text areas</h2>
<h3 id="heading-the-popover-api">The Popover API</h3>
<p>All modern browsers include a built-in Popover API for creating popup elements. Here's an example:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codesandbox.io/embed/knpf7w">https://codesandbox.io/embed/knpf7w</a></div>
<p> </p>
<h4 id="heading-limitations">Limitations</h4>
<p>While this API is cross-browser compatible and straightforward to implement, it comes with several limitations:</p>
<ul>
<li><p>It only works with button elements since the required <code>popovertarget</code> attribute is only available on buttons</p>
</li>
<li><p>You have to use CSS to position the popover relative to its target element</p>
</li>
<li><p>And, my biggest limitation is that it doesn’t work within text areas.</p>
</li>
</ul>
<p>Shout out to Mark Techson for introducing me to the Popover API via Una Kravets’ conference talk called <a target="_blank" href="https://youtu.be/-0qa-UqTh_Q?si=IiwhJiXJbi_u4n-n&amp;t=642">Less Cruft, More Power: Leverage the Power of the Web Platform</a>.</p>
<h3 id="heading-the-selection-api">The Selection API</h3>
<p>I wanted my popover to appear wherever the user selected text. This required me to:</p>
<ul>
<li><p>Know the position of the selected text</p>
</li>
<li><p>Listen for events that happened when text was selected and deselected</p>
</li>
</ul>
<p>I came across Colby Fayock’s blog post called <a target="_blank" href="https://spacejelly.dev/posts/how-to-share-selected-text-in-react-with-the-selection-api">How to Share Selected Text in React with the Selection API</a>. While Colby's focus was on text sharing functionality, his post introduced me to the Selection API - which could help me position my popover relative to selected text.</p>
<p>The Selection API lives in <code>window.getSelection()</code>. When you call this method, it returns a Selection object that tells you about the text a user has selected on the page.</p>
<h4 id="heading-getrangeat0">getRangeAt(0)</h4>
<p>From this Selection object, you can call <code>getRangeAt(0)</code> to find out exactly where the selection begins and ends. It gives you two numbers:</p>
<ul>
<li><p><code>startOffset</code> - where the selection begins</p>
</li>
<li><p><code>endOffset</code> - where the selection ends</p>
</li>
</ul>
<p>In a selection, each character has an index. For the text "Hello, World! Welcome.", the indexes look like this:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codesandbox.io/embed/vj49mj">https://codesandbox.io/embed/vj49mj</a></div>
<p> </p>
<p>If you select the word "World", then <code>startOffset</code> is 7 (where "W" begins) and <code>endOffset</code> is 12 (right after "d").</p>
<p><strong>Side note:</strong> I learned that the parameter 0 in getRangeAt(0) tells the browser which selection you want information about. When you select text, each selection gets stored at different indexes in an array. Most browsers only let you select one piece of text at a time, so you'll only have one item at index 0. But browsers like Firefox let you hold Ctrl to select multiple pieces of text. If you try to access indexes greater than 0 in browsers that don't support multiple selections, you'll get an error.</p>
<h4 id="heading-getboundingclientrect">getBoundingClientRect()</h4>
<p><code>getRangeAt(0)</code> gives you access to <code>getBoundingClientRect()</code>.</p>
<p><code>getBoundingClientRect()</code> returns a box of measurements around your selected text. It tells you the top, right, bottom, and left positions of this box, plus its width and height.</p>
<p>With these measurements, I could place my popover right above any text the user selects, like this:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codesandbox.io/embed/mhxtkr">https://codesandbox.io/embed/mhxtkr</a></div>
<p> </p>
<p>While this approach worked for most HTML elements, text area elements provide limited access to the Selection API, so I needed an alternative approach.</p>
<h3 id="heading-the-mirrored-div">The Mirrored Div</h3>
<p>Through rubber ducking with Claude, I learned about the mirrored div approach, a workaround for determining selection coordinates in a text area.</p>
<p>Here's how it works: create an invisible div that overlays the text area, containing the exact same content and styling. When a user selects text, they're actually interacting with this invisible div rather than the text area underneath it. This gives you access to the full Selection API while maintaining what looks and feels like a standard text area to the user.</p>
<p>I found validation for this technique in Jhey Thompkins' blog post "<a target="_blank" href="https://jh3y.medium.com/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a">HOW TO: Where's the text cursor?</a>", which introduced me to the <code>getComputedStyle()</code> method. This API returns the computed CSS styles of HTML elements, letting developers match the text area's appearance in the overlay div with precision.</p>
<p>But just like with a real mirror, things aren't always what they seem. Similar to the warning on car mirrors that "objects may be closer than they appear," our mirrored div can distort reality in subtle ways:</p>
<ul>
<li><p>Text can wrap at different points between the div and text area</p>
</li>
<li><p>Browsers handle spacing and font rendering differently, causing text positions to shift unexpectedly</p>
</li>
</ul>
<p>{% codesandbox wtsqcv %}</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codesandbox.io/embed/wtsqcv">https://codesandbox.io/embed/wtsqcv</a></div>
<p> </p>
<h2 id="heading-why-not-use-an-npm-package">Why not use an NPM package?</h2>
<p>I’ve tried a few packages, and I found that most of these packages work well with regular DOM elements. However, they struggle with text areas due to the same fundamental limitations I stated earlier - limited access to the text area's internal rendering and positioning.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>While browsers have come a long way in supporting rich text interactions, working with text areas remains surprisingly complex. I had fun learning about these browser APIs, but I still haven't found a solution that fits my use case. Maybe future APIs will make tasks like selection-based popovers more straightforward.</p>
<p>If you've tackled text area customization in a way I haven’t explored, I'd love to hear about your approaches.</p>
]]></content:encoded></item><item><title><![CDATA[A Beginner-Friendly Illustrated Guide to Verifiable Credentials]]></title><description><![CDATA[This blog post uses storytelling to introduce beginners to Verifiable Credentials, followed by a tutorial on creating them in JavaScript and Kotlin.
In Our Last Issue...
In our previous issue, we met Dawson Webhart, a junior frontend software enginee...]]></description><link>https://blackgirlbytes.dev/a-beginner-friendly-illustrated-guide-to-verifiable-credentials</link><guid isPermaLink="true">https://blackgirlbytes.dev/a-beginner-friendly-illustrated-guide-to-verifiable-credentials</guid><category><![CDATA[cryptographic identity verification]]></category><category><![CDATA[web5]]></category><category><![CDATA[verifiable credentials]]></category><category><![CDATA[identity-management]]></category><category><![CDATA[Identity]]></category><category><![CDATA[ssi]]></category><category><![CDATA[decentralization]]></category><category><![CDATA[Cryptography]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Kotlin]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Wed, 06 Mar 2024 08:45:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1709714637261/f51f690d-c47a-4f61-ac3d-bc04075514f0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This blog post uses storytelling to introduce beginners to Verifiable Credentials, followed by a tutorial on creating them in JavaScript and Kotlin.</em></p>
<h2 id="heading-in-our-last-issue">In Our Last Issue...</h2>
<p>In our <a target="_blank" href="https://dev.to/tbdevs/whats-the-point-of-web5-2kjb">previous issue</a>, we met Dawson Webhart, a junior frontend software engineer at a fashion tech company. We learned that Dawson's company wants to adopt Web5, a new technology that ensures users can control their privacy and data portability. Nadia, Dawson's bestie at work and in real life, hopes they lead the company's shift to Web5. Dawson also faced a personal setback when her favorite social media app took Dawson's username without her consent. These challenges piqued Dawson's interest in Web5, driving her to seek control over her digital presence.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o4k2mfgkymfeasnkcym5.jpeg" alt="Dawson reading her phones push notification" /></p>
<p><em>Artist credit: scribblndibbl</em></p>
<h2 id="heading-meet-dawsons-boyfriend">Meet Dawson's boyfriend</h2>
<p>When she gets home from work, Dawson pops a bag of popcorn and sits by the kitchen island, recapping her day with her boyfriend, Justin. As opposed to Dawson’s carefree and forgetful nature, Justin is prepared and meticulous, traits instilled by his immigrant parents. A physical trainer by profession, Justin's interest in the latest technological trends makes him the ideal sounding board for Dawson’s adventures.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e7lyy2cau9uzrjki45kt.png" alt="Dawson eating from a bowl of popcorn" /></p>
<p><em>Artist credit: scribblndibbl</em></p>
<p>“Dude, I can’t believe Francis Francino stole my handle. I’m never using that app again,” Dawson spills about her day, disbelief and frustration coloring her tone.</p>
<p>Justin nods empathetically, "It’s crazy how much of our data we don’t actually own on the internet, like your username situation. JungleGym games, the video game company, announced they're removing our access to certain games that no longer have tech support. It's ridiculous. If I had a physical copy, they couldn't just take it back. Makes me wish we could carry our digital purchases across different platforms."</p>
<p>Dawson lights up, "That's exactly what Nadia was saying about Web5—taking your data wherever you go. That’s why I’m thinking of really diving into it."</p>
<p>Justin shifts gears with a playful nudge, "Word, I support it. I also support you packing your bags for our weekend friend trip to Orlando. Our flight is tonight. Don't forget."</p>
<p>Caught off guard and trying to hide her forgetfulness, Dawson rushes upstairs to pack. “Psh, I did not forget! I just wanted to tell you about my day.”</p>
<p>She hastily packs, muttering under her breath about the number of outfits and shoes needed for a 2-day trip. And of course, she can’t forget her laptop.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ba107exq02y0cvp2aom4.png" alt="a half packed suitcase" /></p>
<p><em>Artist credit: scribblndibbl</em></p>
<h2 id="heading-a-new-way-to-travel">A New Way to Travel</h2>
<p>As they drive to the airport, Dawson runs through a checklist with Justin to ensure they haven't forgotten anything.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q4hmz3e33fve75wzxh6w.png" alt="Justin driving to the airport with Dawson in the passenger seat" /></p>
<p><em>Artist credit: scribblndibbl</em></p>
<p>"Suitcase, carry-on, keys, debit card, and ID?" she inquires, ticking off each item.</p>
<p>"I left my ID at home. It's all on my phone now, remember? Nadia filled us in on Digital Travel Credentials. They are the next big thing in identity verification," Justin explains.</p>
<p>When they stop at a red light, Justin briefly pulls out his phone to show Dawson his Digital Travel Credentials.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/scgyjcgkqic2kedpj7ml.png" alt="A hand holding a phone that shows a phone wallet with a digital travel credential inside" /></p>
<p><em>Artist credit: scribblndibbl</em></p>
<p>“All I have to do is show this to the TSA and they will let me through,” he explains. Dawson shrugs. She was unimpressed and preferred the traditional method – her physical passport.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1zcfesapcr3n8ls9lels.png" alt="Dawson and friends in security line" /></p>
<p><em>Artist credit: scribblndibbl</em></p>
<p>Dawson and Justin meet up with their friends, including Nadia and Nadia’s partner, at the airport. Everyone but Dawson swiftly passes through the Digital Travel Credentials (DTC) lane by showing their Verifiable Credential and tapping their phones on a card reader.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dloysovdpy51i448tu21.png" alt="phone tapping on card reader" /></p>
<p><em>Artist credit: scribblndibbl</em></p>
<p>“Sorry, girl. You should’ve gotten your digital credentials like I mentioned in the group chat,” Nadia remarks as Dawson heads to the standard line.</p>
<p>Dawson sighs. The standard line is SO long, but then she remembers her CLEAR subscription, a speedier alternative. <em>Her friends aren't the only smart ones</em>, she chuckles to herself.</p>
<p>In the CLEAR queue, Dawson's turn comes quickly. She scans her eyes and smirks, appreciating the smooth process—no extra downloads or purchases necessary, contrary to her friends' approach. Then, a CLEAR employee halts her progress.</p>
<p>“Ma’am, you've been selected for random ID verification.”</p>
<p>Dawson rummages through her bag for her passport. Handing it over, the employee casually notes, “Oh, we share the same birthday! And you’re from the beautiful island of—”</p>
<p>“Yeah..can we just —,“ Dawson strains a smile, but she was cringing on the inside. She wanted to keep up with her friends, and she was disturbed by the unnecessary sharing of her personal details.</p>
<h2 id="heading-the-growing-popularity-of-verifiable-credentials">The Growing Popularity of Verifiable Credentials</h2>
<p>Dawson reunites with her friends at the gate, venting about the invasive CLEAR employee. "You should report that," Nadia advises. "Next trip, get a Digital Travel Credential. The TSA didn't need to see my birth date or anything."</p>
<p>Nadia's enthusiasm grows as she elaborates on her motivation. "I pushed for everyone to try Digital Travel Credentials because I wanted to test them myself. They're a type of Verifiable Credential. Web5, the technology we're adopting at work, has a Software Development Kit to create credentials. Also, Verifiable Credentials are increasing in popularity. Companies like <a target="_blank" href="https://www.microsoft.com/en-us/security/business/identity-access/microsoft-entra-verified-id">Microsoft</a>, <a target="_blank" href="https://verifiablecredentials.dev/">Auth0 by Okta</a>, and <a target="_blank" href="https://blogs.workday.com/our-vision-to-digitize-credentials-in-the-new-world-of-work/">Workday</a> are all experimenting with Verifiable Credentials."</p>
<h2 id="heading-the-experiment">The Experiment</h2>
<p>On the plane, Dawson immediately opens her laptop and connects to the in-flight wifi to learn about Verifiable Credentials.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cbdm3jpxdco5cgpvuwd2.png" alt="Dawson typing on a peach laptop" /></p>
<p><em>Artist credit: scribblndibbl</em></p>
<h2 id="heading-what-are-verifiable-credentials">What are Verifiable Credentials?</h2>
<p><a target="_blank" href="https://developer.tbd.website/docs/web5/learn/verifiable-credentials">Verifiable Credentials (VCs)</a> are digital proofs that confirm certain facts about individuals, organizations, or entities. They can look like digital badges. VCs are stored securely in your smartphone's wallet app—similar to a debit card in Apple Wallet or a gym membership in Google Wallet. At their core, VCs are protected by cryptography, specifically through a JSON Web Token (JWT), ensuring their authenticity and integrity.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hdkp08d6c0b0rige420y.jpeg" alt="Auth0 Lab Verifiable Proof of Concept Designs" /></p>
<p><em>Image credit: Auth0 Lab's Verifiable Credential Proof of Concept Designs</em></p>
<h3 id="heading-flexible-use-cases-of-verifiable-credentials">Flexible Use Cases of Verifiable Credentials</h3>
<p>Let's say you need to prove you're of legal drinking age without revealing excess personal data. Instead of showing your full ID, you could present a VC to a vendor. The vendor recognizes the credential as proof of age and provides you with alcohol in exchange.</p>
<p>Similarly, Dawson's friends used Digital Travel Credentials to prove they were eligible to board their flight.</p>
<p><strong>VCs can represent virtually <em>any</em> claim or certification, including but not limited to:</strong></p>
<ul>
<li><p>Educational achievements</p>
</li>
<li><p>Employment history</p>
</li>
<li><p>Membership in clubs or organizations</p>
</li>
<li><p>Authenticity and accuracy of content</p>
</li>
<li><p>Online identity verification</p>
</li>
<li><p>Trustworthiness as a seller or business partner</p>
</li>
<li><p>Financial standing, including creditworthiness or proof of income, useful for loan applications. See: <a target="_blank" href="https://formfree.com/passport/">FormFree</a>, a company using <a target="_blank" href="https://developer.tbd.website/blog/shifting-loan-power-to-borrowers">Web5's Verifiable Credentials</a> to empower borrower's during the loan process.</p>
</li>
</ul>
<h3 id="heading-key-roles-in-the-verifiable-credential-process">Key Roles in the Verifiable Credential Process</h3>
<p>There are typically three to four key players through the Verifiable Credential exchange process:</p>
<ol>
<li><p><strong>Issuer</strong>: is a trusted organization, entity, or individual who created the verifiable credential and signed the credential stating the information is true.</p>
</li>
<li><p><strong>Subject</strong>: This is the organization, entity, or individual who the Verifiable Credential is about. They will store the verifiable credential in their phone's wallet and present it to the verifier.</p>
</li>
<li><p><strong>Verifier</strong>: This is the entity requesting proof. This entity evaluates the VC's validity and the issuer's credibility before granting access or services.</p>
</li>
<li><p><strong>Holder</strong>: Sometimes, a designated entity holds and presents the VC on the subject's behalf. Although, many times, the subject and the holder are the same.</p>
</li>
</ol>
<h3 id="heading-the-flow">The Flow</h3>
<ol>
<li><p>The issuer creates a VC with claims about the subject.</p>
</li>
<li><p>The issuer cryptographically signs the credential stating that the claims about the subject are true.</p>
</li>
<li><p>The subject stores the VC in their phone’s wallet.</p>
</li>
<li><p>The subject (or holder) presents their Verifiable Credential to a verifier.</p>
</li>
<li><p>The verifier runs a series of checks to determine if the VC is real and valid. They also determine if the issuer is real and trustworthy.</p>
</li>
</ol>
<h3 id="heading-what-does-cryptographically-signed-mean">What Does 'Cryptographically Signed' Mean?</h3>
<p>I think of cryptography as using code to create a digital lock that protects information. When we say something is "cryptographically signed," it indicates that an item has been marked with a unique digital fingerprint. This is similar to back in the day when a king would seal a decree with a ring.</p>
<p>An algorithm generates the signature, ensuring it's unique to the document and the person who signed it. The digital fingerprint is composed of a <strong>private key</strong> and a <strong>public key</strong>. While your private key is kept a secret, your public key is shared with others to verify that the signature was made with your private key and the document hasn't been tampered with.</p>
<p>Together, these keys perform a dual function: they confirm the authenticity of the document and its signer AND maintain the integrity of the document by detecting any alterations post-signature.</p>
<h2 id="heading-tutorial-create-a-vc-in-javascript">Tutorial: Create a VC in JavaScript</h2>
<p>Dawson wants to try creating a Legal Drinking Age Verifiable credential to help her apply the concepts she learned.</p>
<h3 id="heading-package-dependencies">Package dependencies</h3>
<p>Dawson starts by installing and importing the packages needed to create a Verifiable Credential with Web5.</p>
<p>She runs the following command:</p>
<pre><code class="lang-bash">npm install @web5/credentials @web5/dids
</code></pre>
<p>She creates a file called <code>verifiable-creds.js</code> and imports the packages in that file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { DidDht } <span class="hljs-keyword">from</span> <span class="hljs-string">'@web5/dids'</span>;
<span class="hljs-keyword">import</span> { VerifiableCredential, PresentationExchange } <span class="hljs-keyword">from</span> <span class="hljs-string">'@web5/credentials'</span>;
</code></pre>
<h3 id="heading-creating-the-issuer-and-the-subject">Creating the issuer and the subject</h3>
<p>Each participant in the Verifiable Credential process is linked to a Decentralized Identifier (DID), a W3C-standard alphanumeric string that serves as a unique identifier for individuals, organizations, or entities.</p>
<p>Dawson thinks the Department of Motor Vehicles or the Passport Office could be potential Legal Drinking Age Credential issuers. For learning purposes, she creates a DID to simulate an issuer similar to the Department of Motor Vehicles, naming it "Fake Department of Motor Vehicles" or "FakeDMV."</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> fakeDmvIssuerDid = <span class="hljs-keyword">await</span> DidDht.create();
</code></pre>
<p>Subsequently, Dawson generates her own DID to act as the subject of the credential.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> dawsonDid = <span class="hljs-keyword">await</span> DidDht.create();
</code></pre>
<h3 id="heading-inspect-the-did">Inspect the DID</h3>
<p>Dawson examines her DID's details:</p>
<pre><code class="lang-js"><span class="hljs-built_in">console</span>.log(dawsonDid)
</code></pre>
<p>She observes the DID document, particularly the DID string and public key:</p>
<pre><code class="lang-js"><span class="hljs-built_in">console</span>.log(<span class="hljs-string">`this is the DID string <span class="hljs-subst">${dawsonDid.uri}</span>`</span>)
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">`this is the DID’s public key information <span class="hljs-subst">${dawsonDid.<span class="hljs-built_in">document</span>.verificationMethod}</span>`</span>)
</code></pre>
<h3 id="heading-creating-the-credential">Creating the credential</h3>
<pre><code class="lang-js"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LegalDrinkingAgeCredential</span> </span>{
    <span class="hljs-keyword">constructor</span>(name, dateOfBirth, isOfLegalDrinkingAge, city, country) {
        <span class="hljs-built_in">this</span>.name = name;
        <span class="hljs-built_in">this</span>.dateOfBirth = dateOfBirth;
        <span class="hljs-built_in">this</span>.isOfLegalDrinkingAge = isOfLegalDrinkingAge;
        <span class="hljs-built_in">this</span>.city = city;
        <span class="hljs-built_in">this</span>.country = country;
    }
}

<span class="hljs-keyword">const</span> vc = <span class="hljs-keyword">await</span> VerifiableCredential.create({
    <span class="hljs-attr">type</span>: <span class="hljs-string">'LegalDrinkingAgeCredential'</span>,
    <span class="hljs-attr">issuer</span>: fakeDmvIssuerDid.uri,
    <span class="hljs-attr">subject</span>: fakeDmvIssuerDid.uri,
    <span class="hljs-attr">data</span>: <span class="hljs-keyword">new</span> LegalDrinkingAgeCredential(<span class="hljs-string">'Your Name'</span>, <span class="hljs-string">'Your Date of Birth'</span>, <span class="hljs-literal">true</span>, <span class="hljs-string">'Your City'</span>, <span class="hljs-string">'Your Country'</span>) 
});
</code></pre>
<h3 id="heading-signing-the-credential">Signing the credential</h3>
<p>The "Fake DMV" signs the credential with their DID:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> signedVC = <span class="hljs-keyword">await</span> vc.sign({ <span class="hljs-attr">did</span>: fakeDmvIssuerDid });
</code></pre>
<h3 id="heading-inspect-the-signed-vc">Inspect the Signed VC</h3>
<p>Dawson prints out the signed verifiable credential, and she finds that the verifiable credential is now an odd alphanumeric string.</p>
<pre><code class="lang-plaintext">eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpkaHQ6MWZmd25mNHduZW94cng5M2ZzYTF4NHA3eDg3Y210ZHJicWtkMXcxeTF4bmNtN2FrcWRleSMwIn0.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiTGVnYWxEcmlua2luZ0FnZUNyZWRlbnRpYWwiXSwiaWQiOiJ1cm46dXVpZDo5ZGZhYjcyMS0xY2IwLTRmNDYtOTgxZi05YjhjZDZkY2E1NzUiLCJpc3N1ZXIiOiJkaWQ6ZGh0OjFmZnduZjR3bmVveHJ4OTNmc2ExeDRwN3g4N2NtdGRyYnFrZDF3MXkxeG5jbTdha3FkZXkiLCJpc3N1YW5jZURhdGUiOiIyMDI0LTAzLTA2VDA0OjExOjA2WiIsImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmRodDoxZmZ3bmY0d25lb3hyeDkzZnNhMXg0cDd4ODdjbXRkcmJxa2QxdzF5MXhuY203YWtxZGV5IiwibmFtZSI6IllvdXIgTmFtZSIsImRhdGVPZkJpcnRoIjoiWW91ciBEYXRlIG9mIEJpcnRoIiwiaXNPZkxlZ2FsRHJpbmtpbmdBZ2UiOnRydWUsImNpdHkiOiJZb3VyIENpdHkiLCJjb3VudHJ5IjoiWW91ciBDb3VudHJ5In19LCJpc3MiOiJkaWQ6ZGh0OjFmZnduZjR3bmVveHJ4OTNmc2ExeDRwN3g4N2NtdGRyYnFrZDF3MXkxeG5jbTdha3FkZXkiLCJzdWIiOiJkaWQ6ZGh0OjFmZnduZjR3bmVveHJ4OTNmc2ExeDRwN3g4N2NtdGRyYnFrZDF3MXkxeG5jbTdha3FkZXkifQ.4_wXY3bWZvnvxqUIVsYkqHvrXQmmyYG9FTV7Zydq893yArGaZYCjia81KGFk4EQ241uaKP9i9dwaoeI_fcpJCg
</code></pre>
<p>She learns that signing her Verifiable Credential encoded it as a JSON Web Token (JWT), so that no one can modify the Verifiable Credential.</p>
<p>When she pastes the value of the JWT in a tool like Auth0’s <a target="_blank" href="http://jwt.io">jwt.io</a>, she can see the decoded value of the Verifiable Credential, including claims and decentralized identifiers.</p>
<h3 id="heading-showing-your-credentials-to-a-verifier">Showing your credentials to a verifier</h3>
<p>When you go to a verifier, you will share your Verifiable Credential with them. This is often done in a computerized way where maybe you scan a QR code or click a link.</p>
<p>The verifier can check to verify that the Verifiable Credential is real by running the code below:</p>
<pre><code class="lang-js"><span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">await</span> VerifiableCredential.verify({ <span class="hljs-attr">vcJwt</span>: signedVC });
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'\nVC Verification successful!\n'</span>);
} <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'\nVC Verification failed: '</span> + err.message + <span class="hljs-string">'\n'</span>);
}
</code></pre>
<p>Now, you can start the Presentation Exchange process. This is where your phone’s wallet and the Verifier’s application communicate.</p>
<p>The verifier has a Presentation Definition. The Presentation Definition sets the specific criteria that the verifier is looking for through the Verifiable Credential.</p>
<p>Dawson defines the criteria the verifier is looking for in the Presentation Definition:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> presentationDefinition = {
    <span class="hljs-attr">id</span>: <span class="hljs-string">"presDefId123"</span>,
    <span class="hljs-attr">name</span>: <span class="hljs-string">"Legal Drinking Age Presentation Definition"</span>,
    <span class="hljs-attr">purpose</span>: <span class="hljs-string">"for verifying legal drinking age"</span>,
    <span class="hljs-attr">input_descriptors</span>: [
        {
            <span class="hljs-attr">id</span>: <span class="hljs-string">"legalDrinkingAge"</span>,
            <span class="hljs-attr">purpose</span>: <span class="hljs-string">"Are you of legal drinking age??"</span>,
            <span class="hljs-attr">constraints</span>: {
                <span class="hljs-attr">fields</span>: [
                    {
                        <span class="hljs-attr">path</span>: [<span class="hljs-string">"$.credentialSubject.isOfLegalDrinkingAge"</span>],
                    },
                ],
            },
        },
    ],
};
</code></pre>
<p>This setup allows for a verification process that checks the credential against the verifier's requirements.</p>
<pre><code class="lang-js"><span class="hljs-keyword">try</span> {
    PresentationExchange.satisfiesPresentationDefinition({
        <span class="hljs-attr">vcJwts</span>: signedVC,
        <span class="hljs-attr">presentationDefinition</span>: presentationDefinition
   });
} <span class="hljs-keyword">catch</span> (err) {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Presentation Definition not satisfied: '</span> + err.message + <span class="hljs-string">'\n'</span>);
}
</code></pre>
<h2 id="heading-tutorial-create-a-vc-in-kotlin">Tutorial: Create a VC in Kotlin</h2>
<p>Dawson wants to try creating a Legal Drinking Age Verifiable credential to help her apply the concepts she learned.</p>
<h3 id="heading-package-dependencies-1">Package dependencies</h3>
<p>Dawson starts by installing and importing the packages needed to create a Verifiable Credential with Web5.</p>
<p>She adds the following code to her pom.xml file:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">repositories</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">repository</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>mavenCentral<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">url</span>&gt;</span>https://repo1.maven.org/maven2/<span class="hljs-tag">&lt;/<span class="hljs-name">url</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">repository</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">repository</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">id</span>&gt;</span>danubetech-maven-public<span class="hljs-tag">&lt;/<span class="hljs-name">id</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">url</span>&gt;</span>https://repo.danubetech.com/repository/maven-public/<span class="hljs-tag">&lt;/<span class="hljs-name">url</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">repository</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">repositories</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>xyz.block<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>web5-credentials<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.11<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>xyz.block<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>web5-dids<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.0.11<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span>
</code></pre>
<p>She creates a file called <code>VerifiableCreds.kt</code> and imports the packages in that file:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">import</span> web5.sdk.crypto.InMemoryKeyManager
<span class="hljs-keyword">import</span> web5.sdk.dids.methods.key.DidDht
<span class="hljs-keyword">import</span> web5.sdk.dids.DidResolvers
<span class="hljs-keyword">import</span> web5.sdk.credentials.VerifiableCredential
<span class="hljs-keyword">import</span> web5.sdk.credentials.PresentationExchange
<span class="hljs-keyword">import</span> web5.sdk.credentials.model.*
</code></pre>
<h3 id="heading-creating-the-issuer-and-the-subject-1">Creating the issuer and the subject</h3>
<p>Each participant in the Verifiable Credential process is linked to a Decentralized Identifier (DID), a W3C-standard alphanumeric string that serves as a unique identifier for individuals, organizations, or entities.</p>
<p>For the legal drinking age credential, Dawson thinks the following organizations could be potential issuers such as the Department of Motor Vehicles or the Passport Office. For learning purposes, she creates a DID to simulate an issuer similar to the Department of Motor Vehicles, naming it "Fake Department of Motor Vehicles" or "FakeDMV".</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> fakeDmvIssuerDid = DidDht.create(InMemoryKeyManager())
</code></pre>
<p>Subsequently, Dawson generates her own DID to act as the subject of the credential.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> dawsonDid = DidDht.create(InMemoryKeyManager())
</code></pre>
<h3 id="heading-inspect-the-did-1">Inspect the DID</h3>
<p>Dawson examines her DID's details:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> resolvedDid = DidResolvers.resolve(dawsonDid.uri)
println(resolvedDid)
</code></pre>
<p>She observes the DID document, particularly the DID string and public key:</p>
<pre><code class="lang-kotlin">println(<span class="hljs-string">"this is the DID string <span class="hljs-subst">${dawsonDid.uri}</span>"</span>)
println(<span class="hljs-string">"this is the DID’s public key information <span class="hljs-subst">${dawsonDid.didDocument?.verificationMethods}</span>"</span>)
</code></pre>
<h3 id="heading-creating-the-credential-1">Creating the credential</h3>
<pre><code class="lang-kotlin"><span class="hljs-keyword">data</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LegalDrinkingCredential</span></span>(
    <span class="hljs-keyword">val</span> name: String,
    <span class="hljs-keyword">val</span> dateOfBirth: String,
    <span class="hljs-keyword">val</span> isOfLegalDrinkingAge: <span class="hljs-built_in">Boolean</span>,
    <span class="hljs-keyword">val</span> city: String,
    <span class="hljs-keyword">val</span> country: String
)

<span class="hljs-keyword">val</span> vc = VerifiableCredential.create(
    type = <span class="hljs-string">"LegalDrinkingCredential"</span>,
    issuer = fakeDmvIssuerDid.uri,
    subject = dawsonDid.uri,
    <span class="hljs-keyword">data</span> = LegalDrinkingCredential( 
        name = <span class="hljs-string">"Dawson Webhart"</span>,
        dateOfBirth = <span class="hljs-string">"Your Date of Birth"</span>,
        isOfLegalDrinkingAge = <span class="hljs-literal">true</span>
        city = <span class="hljs-string">"Your City"</span>,
        country = <span class="hljs-string">"Your Country"</span>
    )
)
</code></pre>
<h3 id="heading-signing-the-credential-1">Signing the credential</h3>
<p>The "Fake DMV" signs the credential with their DID:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> signedVC = vc.sign(fakeDmvIssuerDid)
</code></pre>
<h3 id="heading-inspect-the-signed-vc-1">Inspect the Signed VC</h3>
<p>Dawson prints out the signed verifiable credential, and she finds that the verifiable credential is now an odd alphanumeric string.</p>
<pre><code class="lang-plaintext">eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpkaHQ6MWZmd25mNHduZW94cng5M2ZzYTF4NHA3eDg3Y210ZHJicWtkMXcxeTF4bmNtN2FrcWRleSMwIn0.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJ0eXBlIjpbIlZlcmlmaWFibGVDcmVkZW50aWFsIiwiTGVnYWxEcmlua2luZ0FnZUNyZWRlbnRpYWwiXSwiaWQiOiJ1cm46dXVpZDo5ZGZhYjcyMS0xY2IwLTRmNDYtOTgxZi05YjhjZDZkY2E1NzUiLCJpc3N1ZXIiOiJkaWQ6ZGh0OjFmZnduZjR3bmVveHJ4OTNmc2ExeDRwN3g4N2NtdGRyYnFrZDF3MXkxeG5jbTdha3FkZXkiLCJpc3N1YW5jZURhdGUiOiIyMDI0LTAzLTA2VDA0OjExOjA2WiIsImNyZWRlbnRpYWxTdWJqZWN0Ijp7ImlkIjoiZGlkOmRodDoxZmZ3bmY0d25lb3hyeDkzZnNhMXg0cDd4ODdjbXRkcmJxa2QxdzF5MXhuY203YWtxZGV5IiwibmFtZSI6IllvdXIgTmFtZSIsImRhdGVPZkJpcnRoIjoiWW91ciBEYXRlIG9mIEJpcnRoIiwiaXNPZkxlZ2FsRHJpbmtpbmdBZ2UiOnRydWUsImNpdHkiOiJZb3VyIENpdHkiLCJjb3VudHJ5IjoiWW91ciBDb3VudHJ5In19LCJpc3MiOiJkaWQ6ZGh0OjFmZnduZjR3bmVveHJ4OTNmc2ExeDRwN3g4N2NtdGRyYnFrZDF3MXkxeG5jbTdha3FkZXkiLCJzdWIiOiJkaWQ6ZGh0OjFmZnduZjR3bmVveHJ4OTNmc2ExeDRwN3g4N2NtdGRyYnFrZDF3MXkxeG5jbTdha3FkZXkifQ.4_wXY3bWZvnvxqUIVsYkqHvrXQmmyYG9FTV7Zydq893yArGaZYCjia81KGFk4EQ241uaKP9i9dwaoeI_fcpJCg
</code></pre>
<p>She learns that signing her Verifiable Credential encoded it as a JSON Web Token (JWT), so that no one can modify the Verifiable Credential.</p>
<p>When she pastes the value of the JWT in a tool like Auth0’s <a target="_blank" href="http://jwt.io">jwt.io</a>, she can see the decoded value of the Verifiable Credential including claims and decentralized identifiers.</p>
<h3 id="heading-showing-your-credentials-to-a-verifier-1">Showing your credentials to a verifier</h3>
<p>When you go to a verifier, you will share your Verifiable Credential with them. This is often done in a computerized way where maybe you scan a QR code or click a link.</p>
<p>The verifier can check to verify that the Verifiable Credential is real by running the code below:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">try</span> {
    VerifiableCredential.verify(signedVC)
} <span class="hljs-keyword">catch</span> (err: Exception) {
    println(<span class="hljs-string">"VC Verification failed:"</span> + err.message)
}
</code></pre>
<p>Now, you can start the Presentation Exchange process. This is where your phone’s wallet and the Verifier’s application communicate.</p>
<p>The verifier has a Presentation Definition. The Presentation Definition sets the specific criteria that the verifier is looking for through the Verifiable Credential.</p>
<p>Dawson defines the criteria the verifier is looking for in the Presentation Definition:</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">val</span> presentationDefinition = PresentationDefinitionV2(
        id = <span class="hljs-string">"presDefId123"</span>,
        name = <span class="hljs-string">"Legal Drinking Age Presentation Definition"</span>,
        purpose = <span class="hljs-string">"for verifying legal drinking age"</span>,
        inputDescriptors = listOf(
            InputDescriptorV2(
                id = <span class="hljs-string">"legalDrinkingAge"</span>,
                purpose = <span class="hljs-string">"Are you of legal drinking age?"</span>,
                constraints = ConstraintsV2(
                    fields = listOf(
                        FieldV2(
                            path = listOf(<span class="hljs-string">"$.vc.credentialSubject.isOfLegalDrinkingAge"</span>)
                        )
                    )
                )
            )
        )
    )
</code></pre>
<p>This setup allows for a verification process that checks the credential against the verifier's requirements.</p>
<pre><code class="lang-kotlin"><span class="hljs-keyword">try</span> {
    PresentationExchange.satisfiesPresentationDefinition(
        vcJwts = signedVC,
        presentationDefinition = presentationDefinition
    )
} <span class="hljs-keyword">catch</span> (e: Exception) {
     println(<span class="hljs-string">"VC does not satisfy Presentation Definition: "</span> + err.message)
}
</code></pre>
<p>Dawson taps a half-asleep Justin as they land in Orlando, "The planes landing, and I just made my first Verifiable Credentials in JavaScript and Kotlin," she says with a grin.</p>
<p><em>Please note: The information in this tutorial may become outdated as we update our SDKs towards the 1.0 release.</em></p>
<h2 id="heading-build-your-own-vcs-and-follow-tbds-progress-as-we-build-web5">Build your own VCs and follow TBD's progress as we build Web5</h2>
<ul>
<li><p><a target="_blank" href="https://developer.tbd.website">Documentation</a></p>
</li>
<li><p><a target="_blank" href="https://discord.com/invite/tbd">Discord</a></p>
</li>
<li><p><a target="_blank" href="http://Dev.to">Dev.to</a></p>
</li>
<li><p><a target="_blank" href="https://www.twitch.tv/tbdevs">Twitch</a></p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/@TBD54566975">YouTube</a></p>
</li>
<li><p><a target="_blank" href="https://github.com/TBD54566975">GitHub</a></p>
</li>
</ul>
<h2 id="heading-artist-credit">Artist Credit</h2>
<p>I did not do any of the art. My talented little sister drew all the art. Check out her work at: <a target="_blank" href="https://linktr.ee/scribblndibbl">https://linktr.ee/scribblndibbl</a></p>
]]></content:encoded></item><item><title><![CDATA[Shifting Loan Power to Borrowers]]></title><description><![CDATA["Our current credit system says, 'Saddle yourself, so we can give you more to saddle.'" Eric Lapin, President of FormFree, stated during a recent TBD live stream. His comment sheds light on a fundamental paradox of the U.S. credit system: it often re...]]></description><link>https://blackgirlbytes.dev/shifting-loan-power-to-borrowers</link><guid isPermaLink="true">https://blackgirlbytes.dev/shifting-loan-power-to-borrowers</guid><category><![CDATA[web5]]></category><category><![CDATA[AI]]></category><category><![CDATA[data]]></category><category><![CDATA[decentralization]]></category><category><![CDATA[loan]]></category><category><![CDATA[verifiable credentials]]></category><category><![CDATA[Decentralised Identity]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Wed, 31 Jan 2024 13:48:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1706708637564/16f4a60d-021a-4fd5-9876-f78ecaa3ef09.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>"Our current credit system says, 'Saddle yourself, so we can give you more to saddle.'"</em> Eric Lapin, President of <a target="_blank" href="https://www.formfree.com/">FormFree</a>, stated during a recent <a target="_blank" href="https://youtu.be/TZkK8a64E7I?si=2qhaIF22uGbD7lbJ">TBD live stream</a>. His comment sheds light on a fundamental paradox of the U.S. credit system: it often requires you to accumulate debt as a prerequisite for obtaining loans, leading to more debt. This systemic issue is underscored by <a target="_blank" href="https://www.newyorkfed.org/microeconomics/sce/credit-access#/experiences-credit-demand1">recent data from the Federal Reserve Bank of New York</a>, which reveals that 1 in 5 applicants for mortgages, car loans, or other types of loans were rejected — the highest rate in five years. This trend disproportionately impacts Black and Latino applicants. Guided by their slogan, 'Democratizing lending for all people without bias,' FormFree developed a platform built with Web5 and AI to address these issues.</p>
<h2 id="heading-residual-income-knowledge-index-riki">Residual Income Knowledge Index (RIKI)</h2>
<p>The Fair Isaac Corporation score, better known as a FICO score, is a three-digit score that helps lenders in the U.S. evaluate the likelihood of a borrower repaying a loan. A higher score indicates greater reliability. However, achieving a high FICO score — or any credit score — largely depends on accruing and gradually repaying debt. This may come as a disadvantage for various groups of people who may not have a credit score, including veterans, formerly incarcerated individuals, immigrants, young adults, and folks who prefer cash transactions.</p>
<p>To provide a more holistic view of a person's creditworthiness, FormFree developed a new system called <a target="_blank" href="https://www.formfree.com/news-and-insights/formfree-releases-residual-income-knowledge-index/">Residual Income Knowledge Index™ (RIKI™)</a>. Instead, RIKI analyzes monthly income and spending. Integrating this method into our existing credit system provides greater opportunities for home ownership, car purchases, and other essential loans.</p>
<h2 id="heading-its-like-tinder-for-banks">"It's like Tinder for banks!"</h2>
<p>During the live stream, FormFree Software Engineer, Jon West, showcased their <a target="_blank" href="https://passport.formfree.com/">Passport</a> product. The demo highlighted Passport's ability to match borrowers with lenders. This feature inspired an audience member to comment, 'It's like Tinder for banks!'"</p>
<p>Here's how it works:</p>
<ul>
<li><p>Borrowers securely connect to their bank account.</p>
</li>
<li><p>FormFree analyzes the account records and creates an anonymized credit profile for the borrower.</p>
</li>
<li><p>Lenders review these anonymized profiles and decide which borrowers to extend offers to.</p>
</li>
<li><p>Borrowers can now review offers from lenders and choose their preferred option.</p>
</li>
<li><p>All necessary borrower data is shared with the lender once a match is made.</p>
</li>
</ul>
<p>Typically, borrowers endure aggressively pitched products from dozens of lending institutions. FormFree shifts control to users for more tailored loan consideration.</p>
<h2 id="heading-how-formfree-uses-web5">How FormFree Uses Web5</h2>
<p>FormFree uses the following Web5 technologies:</p>
<ul>
<li><p><a target="_blank" href="https://developer.tbd.website/docs/web5/learn/decentralized-identifiers">Decentralized Identifiers (DID)</a> - After sign up, the application associates a user's account with a DID.</p>
</li>
<li><p><a target="_blank" href="https://developer.tbd.website/docs/web5/learn/verifiable-credentials">Verifiable Credentials (VC)</a> - A borrower's credit profile is secured as a Verifiable Credential enabling the borrower's information to stay anonymous and tamper-proof.</p>
</li>
</ul>
<h2 id="heading-coming-soon-tblend-and-credential-selector">Coming Soon - tbLend and Credential Selector</h2>
<p>As part of our <a target="_blank" href="https://developer.tbd.website/community/incubation-projects/">incubation program</a>, organizations such as <a target="_blank" href="https://www.formfree.com/">FormFree</a>, <a target="_blank" href="https://sophtron.com/index">Sophtron</a>, and <a target="_blank" href="https://www.mx.com/">MX</a> are working in partnership to build Web5 protocols that will help their products evolve.</p>
<ul>
<li><p><a target="_blank" href="https://github.com/TBD54566975/incubation-tblend#web5service">tbLend</a> - A Web5 protocol that connects the lender and borrower to exchange money securely.</p>
</li>
<li><p><a target="_blank" href="https://github.com/TBD54566975/incubation-verifiable-credential-selector">Credential Selector</a> - A Web5 protocol that enables developers to embed the Verifiable Credentials (VCs) into their application and allows users to select and retrieve VCs.</p>
</li>
</ul>
<h2 id="heading-rewatch-the-full-episode">Rewatch the full episode</h2>
<p>Learn more about what FormFree is building and watch the full live stream <a target="_blank" href="https://youtu.be/TZkK8a64E7I?si=2qhaIF22uGbD7lbJ">here</a>.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/TZkK8a64E7I?si=wKZIIh_4BqF0Rmst">https://youtu.be/TZkK8a64E7I?si=wKZIIh_4BqF0Rmst</a></div>
<p> </p>
<p><em>This post highlights key moments from our collaborative live stream with leaders and builders at FormFree. Join our weekly live streams every Friday at 12pm ET/9 am PT. We're learning how innovators and community members are advancing the Self-Sovereign Identity and Global Payments industry. Tune in next time via</em> <a target="_blank" href="https://twitch.tv/tbdevs"><em>Twitch</em></a> <em>or in our community</em> <a target="_blank" href="https://discord.com/invite/tbd"><em>Discord</em></a><em>.</em></p>
]]></content:encoded></item><item><title><![CDATA[Developer Relations is an all-company effort]]></title><description><![CDATA[Technology adoption doesn't happen with one software engineer coding in solitude. Even though big companies like Meta and Microsoft boast of their humble beginnings in a dorm room or a garage, product adoption requires good marketing. Many software e...]]></description><link>https://blackgirlbytes.dev/developer-relations-is-an-all-company-effort</link><guid isPermaLink="true">https://blackgirlbytes.dev/developer-relations-is-an-all-company-effort</guid><category><![CDATA[DevRel]]></category><category><![CDATA[developer relations]]></category><category><![CDATA[leadership]]></category><category><![CDATA[marketing]]></category><category><![CDATA[Developer Advocate]]></category><category><![CDATA[Product Management]]></category><category><![CDATA[Career]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Tue, 12 Dec 2023 14:15:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1702390414025/8010533d-08e8-4a01-9083-59ac9dea2b20.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Technology adoption doesn't happen with one software engineer coding in solitude. Even though big companies like Meta and Microsoft boast of their humble beginnings in a dorm room or a garage, product adoption requires good marketing. Many software engineers view marketing skeptically, seeing it as a sleazy way to convert potential customers into consumers. They often strive to develop a product so good that it doesn't need marketing. Reality check: Even if your product has the best user experience or solves the world's biggest problems, no one will ever use it if they don't know that it exists. Last year, I wrote an <a target="_blank" href="https://opensource.com/article/22/6/attract-contributors-open-source-project">article</a> highlighting authentic marketing strategies — an ethical and non-cringy approach to generate genuine interest in your projects.</p>
<p>Between 2019 and 2021, devtool startups recognized they needed more than elite coding skills for their product to succeed in a competitive market. They needed strategies to boost product awareness, education, and adoption among developer communities to sustain investor funding. Since developers, as consumers, are naturally skeptical, traditional marketing wasn't sufficient.</p>
<p>The solution involved hiring DevRel professionals, employees who can combine a deep understanding of technology and the developer mindset with exceptional communication skills and the creativity needed to engage effectively with tech communities. As a result, this led to a surge in hiring Developer Relations professionals. However, in 2022 and 2023, another shift occurred; a large influx of DevRel professionals left the industry. Some departures followed company layoffs, as businesses didn't see immediate return on their DevRel investments. Simultaneously, disillusioned individuals left voluntarily, often sharing their frustrations with unrealistic company expectations through YouTube and blogs.</p>
<h2 id="heading-devrel-dissatisfaction">DevRel Dissatisfaction</h2>
<p><a target="_blank" href="https://spinscale.de/posts/2023-11-28-goodbye-devrel.html">Goodbye DevRel for now</a> by Alexander Reelsen</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=_p0LYU_mA_0">https://www.youtube.com/watch?v=_p0LYU_mA_0</a></div>
<p> </p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/uy5sB_QtOPs?si=wmbE4hvd1Yw4JWqk">https://youtu.be/uy5sB_QtOPs?si=wmbE4hvd1Yw4JWqk</a></div>
<p> </p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/x319l8BtCW8?si=13GvR7AWcBJmkoGz">https://youtu.be/x319l8BtCW8?si=13GvR7AWcBJmkoGz</a></div>
<p> </p>
<p>Snarky sidenote: I often believe companies replaced DevRel departments by adding 2023's favorite buzzword to their marketing slogan: "AI."</p>
<p>When I first became a Developer Advocate, a role within the field Developer Relations, I grew weary of the numerous blog posts asking, "What is DevRel?" These posts were initially helpful as I explored the field, but after I gained experience, defining DevRel felt repetitive. I thought it was so surface level, and I craved deeper discussions around:</p>
<ul>
<li><p>Increasing community engagement</p>
</li>
<li><p>Modifying your DevRel strategy for various regions</p>
</li>
<li><p>Building relationships across your company</p>
</li>
<li><p>The art of public speaking</p>
</li>
</ul>
<p>After two years and three months in this profession, I now understand the ongoing need to define DevRel in blog posts. Employers' dissatisfaction with DevRel's effectiveness stems from a lack of understanding what DevRel really is. This misunderstanding adversely affects our performance. Developer Relations is a medium to long-term investment. We are not "swiss army knives" that can lead all your product, marketing, engineering, and support efforts. Most importantly, to achieve true success, Developer Relations requires the involvement of the entire company. In this blog post, I'll discuss why company-wide involvement is essential for DevRel success and how to achieve it.</p>
<h2 id="heading-my-credibility">My Credibility</h2>
<p>While I appreciate the respect from those familiar with my work, I occasionally encounter comments questioning my competence and credibility.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/otisbtt10xs0235flib4.png" alt="Ultimate is too much when the author is that young 🤔 I hope there are at least some good advice in it, and that junior developers won't be misled too much by believing blindly the title🤞" /></p>
<p><em>Example of skepticism ^</em></p>
<p>This skepticism might stem from my tendency to underplay my achievements, coupled with societal biases, as I am a young black woman. I welcome constructive debate and thought-provoking questions in the comments, but not dismissive remarks. To address this, I will highlight why my insights are valuable:</p>
<ul>
<li><p>Alongside two other people, I took an early stage nonprofit from a vision to something tangible by developing and running 10-week online coding courses for women of color and nonbinary people of color. Over four years, I taught over 60 individuals, many of whom are now software engineers.</p>
</li>
<li><p>I made a huge impact as a Developer Advocate at GitHub by significantly contributing to projects like GitHub Copilot. My impact on GitHub Copilot was so great that when I joined a new company, I found a list of resources for learning how to effectively use GitHub Copilot, and they were written by me.</p>
</li>
<li><p>I am currently a Staff Developer Advocate at a fast-paced startup operating within Block.</p>
</li>
<li><p>I've held previous roles as a Software Engineer at early-stage companies, as hire number 7 and 20 respectively.</p>
</li>
<li><p>My educational background includes both a coding bootcamp and a computer science degree from Boston University.</p>
</li>
<li><p>Before I learned to code, I was a help desk technician and a phlebotomist.</p>
</li>
</ul>
<p>My point is that my varied experiences across different roles and organizational sizes equip me with a holistic perspective. I understand the challenges and nuances of working in DevRel at both large corporations and smaller startups. I also know what it's like to work outside of DevRel.</p>
<h2 id="heading-defining-developer-relations">Defining Developer Relations</h2>
<p>Developer Relations, nicknamed DevRel for short, is a field made up of multiple roles including Developer Experience Engineers, Developer Advocates, Community Managers, Technical Writers, Developer Marketers, and moreThe primary objective of a DevRel team is to facilitate communication between technologists and the business. Although many enter the field with altruistic motives, the underlying mission is to expand the customer base in a scalable, one-to-many approach.</p>
<p>I'm a Developer Advocate, so I will focus more on that particular role. When engaging with the company, Developer Advocates represent the developer community. Alternatively, when engaging with the developer community, Developer Advocates represent the company. Developer Advocates raise awareness about the company's products within the developer community and provide the community's feedback to enhance the developer experience within the company.</p>
<ul>
<li><p>Creating awareness can take various forms, such as discussing the company's developer tools on podcasts, giving conference talks, and writing blog posts.</p>
</li>
<li><p>Engaging with the developer community involves direct interactions, like one-on-one conversations in forums, audio spaces, or at conferences.</p>
</li>
<li><p>Improving the developer experience often involves relaying feedback to engineering or product teams, maintaining documentation, creating user-friendly sample applications, and developing open source SDKs that complement the company's product.</p>
</li>
</ul>
<p>Ultimately, these strategies foster trust and education of the product. The developer community wants to use the company's developer tooling and understands how to use it well resulting in increased revenue. One of the most rewarding parts of this strategy is that it inspires community members to participate in DevRel activities, too! Often, community members are so engaged by DevRel's approach that they voluntarily start creating content or speaking at conferences. This enthusiasm can create a ripple effect, further boosting adoption within your company's developer community. However, seeing that increase in users and revenue can take a long time, ranging from months to years.</p>
<h2 id="heading-a-common-mistake-in-developer-relations-teams">A Common Mistake in Developer Relations Teams</h2>
<p>I admit that Developer Relations teams are not perfect, especially not me.</p>
<p>Developer Relations demands a careful balance between external activities and internal activities. Internal work, like community engagement and content creation, builds awareness and amplifies the company's presence. However, some DevRel teams focus too heavily on internal work, and then they struggle to make them product more known. Conversely, teams mainly focused on external efforts might neglect keeping documentation and example apps up to date.</p>
<p>You can have good docs, but no one reads them, or you can have unintuitive APIs, and folks walk away with a bad impression of the product.</p>
<p>I wrote a blog post outlining tasks you can do to make an impact internally and externally.</p>
<h2 id="heading-the-mismatched-expectations-of-devrel">The Mismatched Expectations of DevRel</h2>
<p>On the outside looking in, Developer Relations seems like a glamorous field promising tech celebrity. Behind the social media posts featuring people traveling the world to deliver conference talks and hanging out on social media, many developer advocates are grappling with the challenges of balancing rest, networking, and their core workload. A year into my first DevRel role, I detailed the job's demanding aspects in a <a target="_blank" href="https://dev.to/blackgirlbytes/the-hard-parts-of-developer-advocacy-for-me-530h">blog post</a>.</p>
<p>It can be both exciting and overwhelming to have your day-to-day work look like:</p>
<ul>
<li><p>Hopping off of a Twitch stream</p>
</li>
<li><p>Jumping on to a plane</p>
</li>
<li><p>Refining your conference talk on the plane and practicing your code demo</p>
</li>
<li><p>Publishing resources for the most recent release in your hotel room.</p>
</li>
<li><p>Delivering your conference talk the next day</p>
</li>
<li><p>Fielding questions from the audience</p>
</li>
<li><p>Going to dinner with other developers</p>
</li>
<li><p>Heading to your hotel room to answer questions from the community</p>
</li>
<li><p>Managing your social media interactions</p>
</li>
<li><p>Writing a trip report as you travel back home</p>
</li>
</ul>
<p>This hectic schedule can be frustrating, especially when faced with upper management's questions about metrics and the tangible impact of these efforts.</p>
<p>Many argue that DevRel job descriptions, like those for Developer Advocates, are overly broad and lack standardization, reflecting the diverse nature of DevRel across companies. While this viewpoint is valid, I see the flexibility as a positive aspect. Developer Relations encompasses a lot of cross-functional work. We might have to work with Marketing, Product, and Engineering. We might have to produce videos, write blog posts, and write code. I don't think that's unreasonable. Many DevRel professionals, including myself, enjoy the cross functional chaos. The apparent lack of standardization stems from the varying needs of different companies;</p>
<p>Developer Advocates often act as gap fillers, addressing specific weaknesses within the company. For example, some companies might be doing really well on the developer marketing side, so they need DevRel's coding skills to improve the developer experience. Or vice versa, some companies might have enough engineers to create a great product with a smooth developer experience, but they're struggling to engage with the community. Therefore, the level of ambiguity within Developer Relations roles seems fair to me.</p>
<p>Sidenote: Daniel M. Phiri wrote an interesting <a target="_blank" href="https://madalitso.me/notes/gaps-in-your-developer-journey/">article</a> on gap filling as a developer and as a developer advocate.</p>
<p>Another side note: Jason Lengstorf also has a great video on identifying gaps to fill in a company as a Developer Advocate.</p>
<p>{% youtube 3X-EUEOg638 %}</p>
<p>The real issue lies in the unrealistic expectations placed on DevRel teams, such as expecting the teams to:</p>
<ul>
<li><p>Juggle too many tasks at once rather than focusing on specific objectives at different times, especially in smaller teams. Larger teams have bandwidth to delegate distinct areas like video production, blogging, or SDK maintenance.</p>
</li>
<li><p>Deliver quick results in areas like community growth, reputation building, and technology adoption. Such processes naturally take time. People don't instantly embrace new technologies after hearing about them. They require an engaging onboarding experience, positive interactions with the team, accessible documentation, and fun building processes. Establishing a smooth onboarding process might take several months, and improving documentation could take up to a year.</p>
</li>
<li><p>Operating in isolation without support from other teams. While DevRel supports other teams within the company, reciprocal support isn't always there. For DevRel to truly succeed, other departments must invest time and resources in helping DevRel achieve its objectives.</p>
</li>
</ul>
<h2 id="heading-creating-a-devrel-culture">Creating a DevRel Culture</h2>
<p>Making DevRel an all-company endeavor can look like:</p>
<ul>
<li><p><strong>Early Engagement in DevRel Activities</strong>: Even at an early stage, try performing DevRel activities BEFORE hiring a DevRel team. This firsthand experience builds empathy, respect for the role, and a clearer understanding of the specific gaps that a DevRel team would need to fill. It could also save you some money.</p>
</li>
<li><p><strong>Inclusive Strategy and Product Discussions:</strong> Involve DevRel in meetings regarding strategy, product development, and engineering. DevRel should be informed and participate in the process if there are changes to the code or new company initiatives.</p>
</li>
<li><p><strong>Encourage non-DevRel staff to contribute to DevRel initiatives:</strong> While DevRel leads content creation and public speaking, other employees should also be involved. For instance, an engineer sharing their perspective on tool development can boost the company's repertoire.</p>
</li>
<li><p><strong>Practice working in public:</strong> This is especially important and easy if your company has an open source product. The community needs to know the roadmap and how you're thinking about building the product so that they can make valuable contributions. Working privately and expecting DevRel to publicize internal developments can lead to communication gaps. Open source thrives on mutual learning, often requiring more than code commits.</p>
</li>
<li><p><strong>Keep open lines of communication:</strong> Maybe you're not on the DevRel, but you heard some feedback at a conference or when talking with a community member. Share that feedback with the engineering team and the DevRel team. Regular feedback sessions can help bring community insights into company processes.</p>
</li>
<li><p><strong>Transfer knowledge from engineering to DevRel</strong> - Engineers know how the product <strong><em>should</em></strong> work because they built it. Transferring knowledge empowers DevRel to create more relatable and engaging content, documentation, and use cases for the community.</p>
</li>
<li><p><strong>Integrate DevRel Principles in the Company Mission:</strong> Embedding DevRel and open source principles into the company's mission aligns everyone's efforts with fostering a collaborative and open developer community.</p>
</li>
</ul>
<h2 id="heading-is-this-realistic">Is this Realistic?</h2>
<p>You might read this and wonder if such a comprehensive approach to supporting DevRel is too idealistic, especially given companies' time constraints.</p>
<p>My snarky response: If that's your immediate reaction, then perhaps you're not fully invested in the success of your product.</p>
<p>But let's go with a less snarky take: The most successful companies with admirable DevRel teams have other departments fully backing them up. They invested early in DevRel activities, even before establishing formal DevRel teams.</p>
<p>Take GitHub as an example, a company where I previously worked and which, in my view, excels in DevRel. GitHub was effectively practicing DevRel long before it had a formal team. One of the first blog posts on the GitHub blog was called <a target="_blank" href="https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git">How to undo (almost) anything</a>. This was written by Joshua Wehner, a software engineer and trainer at GitHub. In 2017, Mike Stowe wrote an article called <a target="_blank" href="https://influitive.com/blog/brief-history-developer-relations-programs-developer-communities/">A Brief History Of Developer Relations Programs: How DevRel Evolved Into Developer Communities</a>.</p>
<p>In the article, Mike highlights GitHub's involvement in the developer community, "the most successful—and underrated—developer relations program belongs to a company known as GitHub, a company that hasn't invested in their program the same way as Twilio or Sendgrid has, but still boasts the largest and most active developer community…focused on grassroots approaches over extensive event strategies. That's not to say that they didn't go to events. GitHub was famous for sending their myriad of creative Lisa/Octocat stickers to conferences around the world. But that wasn't core to their strategy. Their strategy was built around community, highlighting individuals' contributions, and providing a resource developers could rely on to continue growing in their careers."</p>
<p>Mike also recognizes companies like StackOverflow and Twilio for their effective DevRel execution.</p>
<p>Another admirable example is <a target="_blank" href="https://astro.build/">Astro</a>, a JavaScript metaframework. This is a startup founded in 2019 with less than 12 employees. They don't have a DevRel team (from my knowledge), yet they're popular in the JavaScript community because they:</p>
<ul>
<li><p>chronicled their progress via blogs BEFORE they hit version 1.0</p>
</li>
<li><p>actively live stream and join other streams</p>
</li>
<li><p>invested in stellar documentation</p>
</li>
<li><p>made engaging and easy to follow sample applications</p>
</li>
<li><p>speak at conferences</p>
</li>
<li><p>made it easy to take existing JavaScript framework knowledge and apply it to the Astro framework. Ex: if you are a Next.js dev or a Svelte dev, it's easy to pick up Astro.</p>
</li>
</ul>
<p>From the outside looking in, each employee at Astro is heavily involved in the developer community. Additionally, there are so many developers and developer advocates with influence that create courses and write blog posts about Astro, which helps to spread awareness.</p>
<p>I understand that small startups and their teams might not have the capacity to invest in DevRel activities if they're not on the DevRel team. I remember working as a Software Engineer just trying to complete my tickets. I would be overwhelmed if I also had to write blog posts. However, things changed when I joined Botany as their seventh hire. My manager cleverly carved out time within the sprint for engineers to write blog posts recapping what we learned throughout the sprint. This was done to help us retain knowledge and become more effective engineers. However, companies can take this idea and repurpose it to support DevRel initiatives. If this strategy is adopted by upper management, and they allocate the necessary resources, then non-DevRel staff can feel empowered to participate in DevRel activities without feeling overburdened.</p>
<p>Developer Relations is not just a team department or an isolated function. It's a philosophy that the entire organization needs to adopt. While it feels gross to say this, the company's developer community is the most valuable asset, so why not invest?</p>
<p>Feel free to leave a comment with deeper insights because although I do have experience, I don't have the same experiences as you all. The comments section is a space for us to learn and grow. I may only get a chance to respond to some, but I will read every comment.</p>
<p>Thanks for reading!</p>
]]></content:encoded></item><item><title><![CDATA[How to Query Records by Protocol Path]]></title><description><![CDATA[Starting a new job is thrilling because I get to learn new things. At my new job, I'm learning about Web5 and decentralization. So, I'm writing this blog post to share my insights about protocols and querying records.
When I built my first Web5 appli...]]></description><link>https://blackgirlbytes.dev/how-to-query-records-by-protocol-path</link><guid isPermaLink="true">https://blackgirlbytes.dev/how-to-query-records-by-protocol-path</guid><category><![CDATA[web5]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[decentralization]]></category><category><![CDATA[coding]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Wed, 25 Oct 2023 02:16:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1698199859600/17792354-604b-42f7-b998-42711cfb8bad.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Starting a new job is thrilling because I get to learn new things. At my new job, I'm learning about Web5 and decentralization. So, I'm writing this blog post to share my insights about protocols and querying records.</p>
<p>When I built my first Web5 application in July, I explored how to store data in a <a target="_blank" href="https://developer.tbd.website/docs/web5/learn/decentralized-web-nodes">Decentralized Web Node (DWN)</a>—a personal data store in the Web5 ecosystem. I can write, edit, delete, and read data, also known as records, to my DWN.</p>
<p>To interact with data in my DWN, I need a <a target="_blank" href="https://developer.tbd.website/docs/web5/learn/decentralized-identifiers">Decentralized Identifier (DID)</a>. DIDs are unique IDs in the digital world. DIDs also act as keys to accessing and manipulating data in a DWN. I think of it like a password to access a database.</p>
<p>Although these were fairly new concepts, I drew parallels to help me understand. In my mind, I compared a DWN to a database and a DID to credentials that help users access a database.</p>
<p>However, there were some technical guidelines that initially confused me. For example – by default, I cannot write data to someone else's DWN unless I have been granted permission to do so. I wasn't sure how to grant permission for a user to write to my DWN. Similarly, I wasn't sure how another user could give me permission to write or read data on their DWN.</p>
<p>Apparently, the solution is to use a <a target="_blank" href="https://developer.tbd.website/docs/web5/learn/protocols">protocol</a>! A protocol, structured as a JSON document, outlines the data structure, defines data types, and establishes rules for data access and interaction within a DWN. In other words, protocols enable users to control who can read or write specific types of data to your DWN.</p>
<h2 id="heading-defining-a-protocol">Defining a protocol</h2>
<p>I wrote a protocol definition for a chat application:</p>
<pre><code class="lang-js"> <span class="hljs-keyword">const</span> chatProtocolDefinition = {
      <span class="hljs-attr">protocol</span>: <span class="hljs-string">"https://blackgirlbytes.dev/ChatProtocol"</span>,
      <span class="hljs-attr">published</span>: <span class="hljs-literal">true</span>,
      <span class="hljs-attr">types</span>: {
        <span class="hljs-attr">message</span>: {
          <span class="hljs-attr">schema</span>: <span class="hljs-string">"https://schema.org/Message"</span>,
          <span class="hljs-attr">dataFormats</span>: [<span class="hljs-string">"application/json"</span>],
        },
        <span class="hljs-attr">audio</span>: {
          <span class="hljs-attr">schema</span>: <span class="hljs-string">"https://schema.org/AudioObject"</span>,
          <span class="hljs-attr">dataFormats</span>: [<span class="hljs-string">"audio/mp3"</span>],
        },
        <span class="hljs-attr">video</span>: {
          <span class="hljs-attr">schema</span>: <span class="hljs-string">"https://schema.org/VideoObject"</span>,
          <span class="hljs-attr">dataFormats</span>: [<span class="hljs-string">"video/mp4"</span>],
        },
        <span class="hljs-attr">image</span>: {
          <span class="hljs-attr">schema</span>: <span class="hljs-string">"https://schema.org/ImageObject"</span>,
          <span class="hljs-attr">dataFormats</span>: [<span class="hljs-string">"image/png"</span>],
        },
        <span class="hljs-attr">gif</span>: {
          <span class="hljs-attr">schema</span>: <span class="hljs-string">"https://schema.org/ImageObject"</span>,
          <span class="hljs-attr">dataFormats</span>: [<span class="hljs-string">"image/gif"</span>],
        },
      },
      <span class="hljs-attr">structure</span>: {
        <span class="hljs-attr">message</span>: {
          <span class="hljs-attr">$actions</span>: [
            { <span class="hljs-attr">who</span>: <span class="hljs-string">"anyone"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"write"</span> },    
            { <span class="hljs-attr">who</span>: <span class="hljs-string">"author"</span>, <span class="hljs-attr">of</span>: <span class="hljs-string">"message"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"read"</span> },    
            { <span class="hljs-attr">who</span>: <span class="hljs-string">"recipient"</span>, <span class="hljs-attr">of</span>: <span class="hljs-string">"message"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"read"</span> },
          ],
          <span class="hljs-attr">audio</span>: {
            <span class="hljs-attr">$actions</span>: [
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"anyone"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"write"</span> },    
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"author"</span>, <span class="hljs-attr">of</span>: <span class="hljs-string">"video"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"read"</span> },    
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"recipient"</span>, <span class="hljs-attr">of</span>: <span class="hljs-string">"video"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"read"</span> },
            ],
          },
          <span class="hljs-attr">video</span>: {
            <span class="hljs-attr">$actions</span>: [
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"anyone"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"write"</span> },    
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"author"</span>, <span class="hljs-attr">of</span>: <span class="hljs-string">"video"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"read"</span> },    
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"recipient"</span>, <span class="hljs-attr">of</span>: <span class="hljs-string">"video"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"read"</span> },
            ],
          },
          <span class="hljs-attr">image</span>: {
            <span class="hljs-attr">$actions</span>: [
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"anyone"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"write"</span> },    
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"author"</span>, <span class="hljs-attr">of</span>: <span class="hljs-string">"video"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"read"</span> },    
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"recipient"</span>, <span class="hljs-attr">of</span>: <span class="hljs-string">"video"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"read"</span> },
            ],
          },
          <span class="hljs-attr">gif</span>: {
            <span class="hljs-attr">$actions</span>: [
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"anyone"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"write"</span> },    
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"author"</span>, <span class="hljs-attr">of</span>: <span class="hljs-string">"video"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"read"</span> },    
              { <span class="hljs-attr">who</span>: <span class="hljs-string">"recipient"</span>, <span class="hljs-attr">of</span>: <span class="hljs-string">"video"</span>, <span class="hljs-attr">can</span>: <span class="hljs-string">"read"</span> },
            ],
          },
        },
      },
    };
</code></pre>
<p>This protocol definition supports various message types: text, audio, gif, video, or image. It also grants permissions to different groups of users. In this particular example, anyone can create a message, but the author and recipient also have permission to read messages. For clarity, this means anyone can write a message to the DWN, but only the recipients and senders can read the messages that they sent and received.</p>
<p><strong>Sidenote</strong>: This method is an amazing way to intentionally architect applications.</p>
<p>Here's a brief explanation of some of the properties listed in the protocol definition:</p>
<ul>
<li><p><code>types</code> - Defines all the elements used in a protocol</p>
</li>
<li><p><code>structure</code> - Outlines the relationship and interaction rules between different types</p>
</li>
<li><p><code>$actions</code> - Specifies a set of permissions outlining who is allowed to perform specific actions like reading or writing on a given type</p>
</li>
</ul>
<h2 id="heading-installing-a-protocol">Installing a protocol</h2>
<p>After I defined my protocol, I installed the protocol to my DWN. Installing the protocol enables my DWN to recognize and adhere to the rules and structures I've established. Here's how to install the protocol for the chat application:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { protocolStatus } = <span class="hljs-keyword">await</span> web5.dwn.protocols.configure({
  <span class="hljs-attr">message</span>: {
    <span class="hljs-attr">definition</span>: chatProtocolDefinition,
  },
});
</code></pre>
<h2 id="heading-problem-i-want-to-filter-for-specific-records">Problem: I want to filter for specific records</h2>
<p>My protocol is defined and installed, so I can use it now! But there's a problem. I only want to return GIFs for a new feature in my chat application.</p>
<p>This new feature will display a gallery of users' most frequently used GIFs to help users conveniently retrieve the GIFs they want to use during conversation. I could fetch all the records on my DWN and then filter using an <code>Array</code> method on the cl. But, that could be inefficient.</p>
<h2 id="heading-solution-query-by-protocol-path">Solution: Query by protocol path</h2>
<p>One way I can address this is to query by <code>protocolPath</code>. I can pass the name of my structure as a value for my <code>protocolPath</code> property. In the protocol definition, <code>gif</code> is nested inside a <code>message</code> structure. Therefore, the protocol path for a <code>gif</code> is <code>message/gif</code>.</p>
<p>The query below will only fetch the GIF records:</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { records } = <span class="hljs-keyword">await</span> web5.dwn.records.query({
  <span class="hljs-attr">message</span>: {
    <span class="hljs-attr">filter</span>: {
      <span class="hljs-attr">protocol</span>: <span class="hljs-string">"https://blackgirlbytes.dev/ChatProtocol"</span>,
      <span class="hljs-attr">protocolPath</span>: <span class="hljs-string">"message/gif"</span>,
    },
  },
});
</code></pre>
<h2 id="heading-other-ways-to-query-records">Other ways to query records</h2>
<p>There are other ways to query records using the Web5 JS SDK. You can find a list of <a target="_blank" href="https://developer.tbd.website/docs/web5/build/decentralized-web-nodes/query-from-dwn#filterable-record-properties">filterable record properties</a> in the documentation. I’ve listed a couple of examples for your convenience:</p>
<h3 id="heading-query-records-by-record-id">Query Records by Record ID</h3>
<p>The snippet below will return a record with the record ID: <code>bfw35evr6e54c4cqa4c589h4cq3v7w4nc534c9w7h5</code></p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { record } = <span class="hljs-keyword">await</span> web5.dwn.records.query({
  <span class="hljs-attr">message</span>: {
    <span class="hljs-attr">recordId</span>: <span class="hljs-string">"bfw35evr6e54c4cqa4c589h4cq3v7w4nc534c9w7h5"</span>,
  },
});
</code></pre>
<h3 id="heading-query-records-by-data-format">Query Records by Data Format</h3>
<p>The snippet below will return all records that have an <code>application/json</code> data format.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> web5.dwn.records.query({
  <span class="hljs-attr">message</span>: {
    <span class="hljs-attr">filter</span>: {
      <span class="hljs-attr">dataFormat</span>: <span class="hljs-string">'application/json'</span>
    }
  }
});
</code></pre>
<h2 id="heading-read-the-documentation">Read the documentation</h2>
<p>Remember that this technology is evolving rapidly! Web5 is in active development and technical preview. For the most current information and guidance on querying records in Web5, always refer to the official <a target="_blank" href="https://developer.tbd.website/docs/web5/build/decentralized-web-nodes/query-from-dwn">Query DWN Records</a> guide.</p>
<h2 id="heading-knowledge-check">Knowledge check</h2>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/blackgirlbytes/pen/XWoBmjL">https://codepen.io/blackgirlbytes/pen/XWoBmjL</a></div>
<p> </p>
<h2 id="heading-excited-to-continue-learning">Excited to continue learning</h2>
<p>Every Friday, the Developer Relations team has been spending time learning in public about Web5. Join us on <a target="_blank" href="http://Twitch.tv/tbdevs">Twitch.tv/tbdevs</a>. Check out a preview below</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/5joJzRkt8u4">https://youtu.be/5joJzRkt8u4</a></div>
<p> </p>
<p>You can watch the full episode <a target="_blank" href="https://lnkd.in/eyfgEuE9">here</a></p>
<h2 id="heading-like-this-content">Like this content?</h2>
<p>For more content like this, follow <a target="_blank" href="https://dev.to/tbdevs">TBDevs</a> and <a target="_blank" href="https://dev.to/blackgirlbytes">me</a>!</p>
]]></content:encoded></item><item><title><![CDATA[What's the point of Web5?]]></title><description><![CDATA[Meet Dawson
Meet Dawson Webhart, a software engineer who's part of the frontend team at StyleByte, a cutting-edge fashion company that uses augmented reality to style its customers. The team focuses on the part of the app that users see and interact ...]]></description><link>https://blackgirlbytes.dev/whats-the-point-of-web5</link><guid isPermaLink="true">https://blackgirlbytes.dev/whats-the-point-of-web5</guid><category><![CDATA[web5]]></category><category><![CDATA[decentralization]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Decentralised Identity]]></category><category><![CDATA[Blockchain]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Wed, 25 Oct 2023 02:08:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1698199506484/28dc82f4-aa69-427e-842b-8a2d8d5bd089.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-meet-dawson">Meet Dawson</h2>
<p>Meet Dawson Webhart, a software engineer who's part of the frontend team at StyleByte, a cutting-edge fashion company that uses augmented reality to style its customers. The team focuses on the part of the app that users see and interact with, and Dawson is a key contributor.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tfzrlzrsxwsr5dvqph1z.jpeg" alt="Drawing of Dawson with black hair brown skin and yellow turtleneck" /></p>
<p>Today, Dawson is at her desk, but she's not exactly working. She's scrolling through her phone, watching short workout videos to inspire her next gym session.</p>
<p>"Here are my top 10 tips to getting a peach like Megan Thee Stallion," says the fitness instructor on the video.</p>
<p>Dawson rolls her eyes just as her co-worker, Nadia Noelly, bursts into her office. "Hey, Dawson! The meeting is starting soon, and I want to get there early. They're making a big announcement!"</p>
<p>"Another announcement? What now? More ping pong tables in the lounge?" Dawson sighs, not particularly thrilled but curious enough to find out.</p>
<h2 id="heading-the-meeting">The Meeting</h2>
<p>In the meeting room, the atmosphere is electric and cult-like as every tech company is. StyleByte's Vice President of Engineering, Wilson, takes the stage. "We're moving to Web5," he announces.</p>
<p>While Nadia's eyes beam with excitement, Dawson feels a mixture of concern, exhaustion, and frustration. "Web5? We just integrated Augmented Reality, migrated to the cloud, and now this? What even is Web5?"</p>
<p>Dawson has always been cautious about change, especially when it comes to technology. She tunes out for the rest of the meeting, pondering what this shift could mean for her work.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v8fcn6n3p2j5k633xf74.jpeg" alt="Wilson talking and Nadia taking notes but Dawson is annoyed" /></p>
<p>After the meeting, Nadia is practically buzzing. "Wasn't that cool? We're moving to Web5! You know what that means, right?"</p>
<p>"More late nights and stress?" Dawson sarcastically replies.</p>
<p>"No, silly! A promotion! We could lead this initiative and finally drop our 'junior' titles. How does 'Mid Level Developer' sound?"</p>
<p>For the first time, Dawson feels a spark of interest. She's been at StyleByte for three years without a promotion. "Okay, you've got my attention. But what is Web5?"</p>
<p>"Weren't you listening? They emailed us the presentation. Check it out," Nadia says, already halfway out the door.</p>
<p>Back in her office, Dawson opens the presentation and finds a diagram explaining the evolution of the web:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gi7t09seinkvkm3sejfs.gif" alt="infographic highlighting web 1 web2 web3 and web5" /></p>
<ul>
<li><p>Web 1.0: Static, read-only content.</p>
</li>
<li><p>Web 2.0: Interactive, social, and user-generated content.</p>
</li>
<li><p>Web3: Decentralized, blockchain-based, user-controlled data.</p>
</li>
<li><p>Web5: Enhanced decentralization, peer-to-peer communication, and self-sovereign identity.</p>
</li>
</ul>
<p>Dawson finds it interesting but isn't entirely convinced. "Seems like a solution looking for a problem," she thinks.</p>
<h2 id="heading-the-ultimate-crisis-a-stolen-username">The Ultimate Crisis - a stolen username</h2>
<p>Just then, a notification pops up on her phone. It's from her favorite social media app, Incognito. Incognito’s new and very erratic CEO, Francis Francino, has just announced a name change for the app—to WebHeart.</p>
<p>“We will be changing this app’s name to WebHeart because it exemplifies what this company has evolved into. We capture the heart of the web. We will be changing our username to @webheart to reflect that.”</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o4k2mfgkymfeasnkcym5.jpeg" alt="Dawson reading her phones push notification" /></p>
<p>Dawson's eyes widen in disbelief. "@webheart" was her own username, a clever play on her last name, Webhart, and her role as a frontend web developer focused on enhancing user experience. She quickly replies to the announcement, "Hey, that's my username!"</p>
<p>Francis Francino responds almost immediately, "Oh, too bad. How about some free merchandise to make up for it?"</p>
<p>Nadia texts her, "Sorry to hear that. If we were on the decentralized web, this wouldn't have happened. Your username would've been yours, controlled by a Decentralized Identifier. Look it up."</p>
<p>Dawson feels gutted. That didn’t console her at all.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vdlxh08ii1dicw6z50l0.jpeg" alt="Dawson looking dejected" /></p>
<p>Dawson feels a mix of indignation and inspiration. If there's anything that fuels her, it's the prospect of <strong><em>revenge served cold and promotions served hot</em></strong>. She decides to dive deeper into Web5. Maybe she could build a transparent social media platform where usernames are truly owned by users. Or maybe she'll snag that promotion. Either way, Dawson is now on a mission.</p>
<p>Throughout her research, Dawson asked the following questions:</p>
<h3 id="heading-what-exactly-is-web5">What exactly is Web5?</h3>
<p>Web5 is an evolving incubator project spearheaded by TBD, Block's newest business unit. The goal is to equip developers with the essential tools for building decentralized applications that prioritize user control over identity and data.</p>
<p>From Dawson’s perspective Web5 could be considered:</p>
<ul>
<li><p><strong>Tooling</strong>: Web5 provides a suite of tools and APIs designed for implementing Self-Sovereign Identity (SSI), decentralized data storage, and secure peer-to-peer communication. This enables the creation of secure, user-centric, privacy-first applications.</p>
</li>
<li><p><strong>An Ecosystem</strong>: Web5 is part of TBD's broader ecosystem, which aims to empower developers to create their own decentralized applications and protocols.</p>
</li>
<li><p><strong>Toolbox for Developers</strong>: Web5 provides pre-built functionalities for identity management, data storage, and secure communication. This way developers can focus on building their application's features rather than worrying about the complexities of security and identity management.</p>
</li>
</ul>
<h3 id="heading-what-is-the-point-of-web5">What is the point of Web5?</h3>
<p>Web5 exists to enable Self Sovereign Identity. Self Sovereign Identity (SSI) is the concept that users should have full control and ownership over their digital identities.</p>
<h3 id="heading-why-would-someone-need-ownership-over-their-digital-identity">Why would someone need ownership over their digital identity?</h3>
<p>Because we are not used to owning our digital identity, it may seem like a futile and foreign concept. Here are a few moments when ownership of digital identity is beneficial:</p>
<ul>
<li><p>Social media:</p>
<ul>
<li><p>There’s no way someone can steal your handle, just like what happened with Dawson's "@webheart" username.</p>
</li>
<li><p>You can take your followers and content with you if you decide to switch platforms.</p>
</li>
<li><p>You have full control over how your data is shared, reducing unwanted advertising and privacy breaches.</p>
</li>
</ul>
</li>
<li><p>Healthcare systems</p>
<ul>
<li><p>You can take your medical records with you, ensuring that you have access to your own health information wherever you go.</p>
</li>
<li><p>You control who has access to your medical data, making it more secure and private.</p>
</li>
</ul>
</li>
<li><p>Banking</p>
<ul>
<li><p>Your financial transactions are secure, and only you have access to your financial data.</p>
</li>
<li><p>You can easily prove your identity for online transactions, reducing the risk of fraud.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-how-can-you-build-a-decentralized-app-using-web5">How can you build a decentralized app using Web5?</h3>
<p>You can build a web5 application using the web5.js SDK.</p>
<h3 id="heading-what-is-a-decentralized-identifier">What is a Decentralized Identifier?</h3>
<p>A decentralized identifier (DID) is a w3c open standard. It’s represented by a string of numbers and letters that identifies and verifies who you are on the web. No one can take it away from you, and no one can change it. A DID is not limited to just a person. It can point to an organization, data model, entity, or whatever it is that user is managing online.</p>
<h3 id="heading-she-experimented-with-did-by-executing-the-steps-below-you-can-do-it-too">She experimented with DID by executing the steps below (you can do it too 😉):</h3>
<p><strong>Creating a directory via her terminal</strong></p>
<pre><code class="lang-bash">mkdir decentralized-social-app

<span class="hljs-built_in">cd</span> decentralized-social-app
</code></pre>
<p><strong>Installing the web5.js SDK</strong></p>
<pre><code class="lang-bash">npm install @web5/api
</code></pre>
<p><strong>Verifying her package.json looked like this:</strong></p>
<pre><code class="lang-js">{

  <span class="hljs-string">"dependencies"</span>: {

    <span class="hljs-string">"@web5/api"</span>: <span class="hljs-string">"0.8.1"</span>

  },

  <span class="hljs-string">"type"</span>: <span class="hljs-string">"module"</span>

}
</code></pre>
<p><strong>Creating an index.js file</strong></p>
<pre><code class="lang-bash">touch index.js
</code></pre>
<p><strong>Importing the Web5 package in our pages/index.js file</strong></p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> { Web5 } <span class="hljs-keyword">from</span> <span class="hljs-string">'@web5/api'</span>;
</code></pre>
<p><strong>Creating a decentralized identifier</strong></p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> { web5, <span class="hljs-attr">did</span>: dawsonDid } = <span class="hljs-keyword">await</span> Web5.connect();
</code></pre>
<p><strong>Logging the decentralized identifier</strong></p>
<pre><code class="lang-js"><span class="hljs-built_in">console</span>.log(dawsonDid);
</code></pre>
<p><strong>Running this command in her terminal</strong></p>
<pre><code class="lang-bash">node index.js
</code></pre>
<p><strong>Here’s her result</strong></p>
<pre><code class="lang-plaintext">did:ion:EiBiHtKwEIdrqLRph3id0HoyCeuk69t6oWbw38WbyYAjvQ:eyJkZWx0YSI6eyJwYXRjaGVzIjpbeyJhY3Rpb24iOiJyZXBsYWNlIiwiZG9jdW1lbnQiOnsicHVibGljS2V5cyI6W3siaWQiOiJhdXRoeiIsInB1YmxpY0tleUp3ayI6eyJjcnYiOiJzZWNwMjU2azEiLCJrdHkiOiJFQyIsIngiOiIxOTQxS29LZ1RyX1V5cDhwcDJITTdGc3U3TzhMb3JyRXNuaXpTZ3o0T1NNIiwieSI6Im1XLTB3dGZobWxBYklFVFczY1JmZUFDRXVzcGNVTVlnM2kzTXlYUTc2X2cifSwicHVycG9zZXMiOlsiYXV0aGVudGljYXRpb24iXSwidHlwZSI6Ikpzb25XZWJLZXkyMDIwIn0seyJpZCI6ImVuYyIsInB1YmxpY0tleUp3ayI6eyJjcnYiOiJzZWNwMjU2azEiLCJrdHkiOiJFQyIsIngiOiJONFhPWWgzeWRMMHA1UGZrVzRZWmZqWjN3WXpQWmNRb1pNcmpQX04xUmI4IiwieSI6InUzRHBKc1ZkN0FRVUZEYkVaSEVhUkJNM0VCajN1ZEpJMXpUbFVsSnZJaFEifSwicHVycG9zZXMiOlsia2V5QWdyZWVtZW50Il0sInR5cGUiOiJKc29uV2ViS2V5MjAyMCJ9XSwic2VydmljZXMiOlt7ImlkIjoiZHduIiwic2VydmljZUVuZHBvaW50Ijp7Im1lc3NhZ2VBdXRob3JpemF0aW9uS2V5cyI6WyIjYXV0aHoiXSwibm9kZXMiOlsiaHR0cHM6Ly9kd24udGJkZGV2Lm9yZy9kd240IiwiaHR0cHM6Ly9kd24udGJkZGV2Lm9yZy9kd24yIl0sInJlY29yZEVuY3J5cHRpb25LZXlzIjpbIiNlbmMiXX0sInR5cGUiOiJEZWNlbnRyYWxpemVkV2ViTm9kZSJ9XX19XSwidXBkYXRlQ29tbWl0bWVudCI6IkVpQ25tcGxmb1VOemlnX01HWnA1QU1Gel9yRm5rUmtHV01jSXJSbFcyT1dGd3cifSwic3VmZml4RGF0YSI6eyJkZWx0YUhhc2giOiJFaUNnUy1nT21lY3lBeXo0V1VwTEJUQTl3MnFIVUR3ek0wd0JyUkYxbXZZY1V3IiwicmVjb3ZlcnlDb21taXRtZW50IjoiRWlBZnZHWEx2cEhEOFVRbnU3RG1OTDVKdEFMQjRaOTg2bG1VRjFMTERPN1JrQSJ9fQ
</code></pre>
<h2 id="heading-dawsons-remaining-questions">Dawson's remaining questions</h2>
<p>Dawson was having so much fun learning until she realized it was 5:00 pm and her work day was over. She still had questions like,</p>
]]></content:encoded></item><item><title><![CDATA[Closing a chapter at GitHub]]></title><description><![CDATA[Leaving a job I truly adore is a new experience for me. I'm not afraid to quit things if that means it will improve my quality of life, but I typically leave jobs when I hate the job, I'm struggling with my mental health, or I'm chasing fresh opportu...]]></description><link>https://blackgirlbytes.dev/closing-a-chapter-at-github</link><guid isPermaLink="true">https://blackgirlbytes.dev/closing-a-chapter-at-github</guid><category><![CDATA[DevRel]]></category><category><![CDATA[Career]]></category><category><![CDATA[developer relations]]></category><category><![CDATA[growth mindset,]]></category><category><![CDATA[decentralization]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Mon, 11 Sep 2023 21:48:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1694468780230/9efac455-825b-4a2b-a6bd-2fd672e3397c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Leaving a job I truly adore is a new experience for me. I'm not afraid to quit things if that means it will improve my quality of life, but I typically leave jobs when I hate the job, I'm struggling with my mental health, or I'm chasing fresh opportunities after acquiring new skills. This time is different. I find myself bidding farewell to a job I genuinely enjoy.</p>
<p>And you might be wondering, "Who the heck cares?" That's valid. Job announcements are a little pretentious. However, I believe in transparency regarding my career and technical journey. I want others to learn from my successes and failures, and this blog post is a part of that continued commitment.</p>
<p>In this blog post, I will:</p>
<ul>
<li><p>Reflect on my journey at GitHub.</p>
</li>
<li><p>Share my next career move and the reasons behind it.</p>
</li>
<li><p>Delve into the fears that come with such a transition.</p>
</li>
<li><p>Outline my aspirations and the knowledge I aim to gain in the next chapter of my professional life.</p>
</li>
</ul>
<h2 id="heading-my-journey-at-github">My journey at GitHub</h2>
<p>Two years ago, I entered a new era of my career as a Junior Developer Advocate at GitHub. Before that, I was working as a software engineer and was desperate to become a developer advocate. I liked coding (and still do), but it was unfulfilling because my diverse skill set was not the best fit for the role. I wanted to empower, educate, and provide support to other technologists. After a few rejections and a slightly <a target="_blank" href="https://dev.to/blackgirlbytes/how-did-i-become-a-developer-advocate-ied">unconventional career journey</a>, GitHub gave me a chance. I signed my offer in August 2021 and prematurely wrote this tweet announcing that people needed to follow me because I would work at GitHub. I didn't even start the job until September 7th 😆.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/blackgirlbytes/status/1427382988283723781">https://twitter.com/blackgirlbytes/status/1427382988283723781</a></div>
<p> </p>
<p>At GitHub, I:</p>
<ul>
<li><p>Made my first open source contribution</p>
</li>
<li><p>Empowered others to engage in open source</p>
</li>
<li><p>Spoke in a keynote</p>
</li>
<li><p>Wrote blog posts that people actually read</p>
</li>
<li><p>Live streamed for the first time</p>
</li>
<li><p>Got my first promotion from junior to mid-level</p>
</li>
<li><p>Embraced failure as a teacher, delivering less-than-ideal talks, championing questionable ideas, and occasionally flaking or oversleeping due to an overloaded schedule.</p>
</li>
</ul>
<p>The most impactful part for me was the recognition and appreciation of my perspective by my colleagues and the broader developer community. Feeling valued and heard was a new experience for me, and I'm endlessly grateful that my company and the developer community supported my endeavors. I'm thankful that my coworkers, managers, and friends I made outside of GitHub knew how to help me highlight my strengths. As I reflect this week, nostalgia washes over me. I'll miss the relationships I've built over the last two years, from my teammates to the Blacktocats (our Black Employee Resource Group) and even the CEO and his team. I'll also miss the projects I invested so much time in, like Open Source Friday. However, new endeavors are on the horizon.</p>
<h2 id="heading-my-next-steps">My next steps</h2>
<p>In a few weeks, I will be a Staff Developer Advocate at Block's newest business unit, <a target="_blank" href="https://developer.tbd.website/">TBD</a>. Many companies acquire other companies or open source projects to help support their growth. Block, previously known as Square, also acquires other companies like Tidal, but it also supports in-house projects developed by their employees. TBD is an initiative led by individuals who have spearheaded projects at CashApp and other Block subsidiaries, with a focus on building decentralized technologies that advance economic empowerment.</p>
<h2 id="heading-what-draws-me-to-working-at-tbd">What draws me to working at TBD</h2>
<p>In a rapidly evolving tech landscape, companies like GitHub, Microsoft, and OpenAI are pioneering the field of generative AI. I've had the privilege of participating in this exciting industry trend. So, you might wonder why I'm now choosing to transition to a company with a strong focus on decentralization.</p>
<h3 id="heading-embracing-the-power-of-yes">Embracing the power of "Yes"</h3>
<p>I have a personal policy of saying yes. When I was ~20, I read the book The Defining Decade: Why Your Twenties Matter--And How to Make the Most of Them Now. It's not the best book. (I was reading a lot of self-help books because, for some reason, I thought I failed at life when I turned 20). A quote in the book says, "Yes is how you get your first job, and your next job, and your spouse, and even your kids. Even if it's a bit edgy, a bit out of your comfort zone, saying yes means you will do something new, meet someone new, and make a difference."</p>
<p>As I recently celebrated my 28th birthday, this philosophy holds even greater significance. When I was trying to decide between joining this company or staying at GitHub, I decided I would procrastinate and watch my favorite Black YouTube video content creators instead. I stumbled upon one of Gyasi Linje's videos, in which he quoted the same words from the same book! I took that as a sign. Saying "yes" to ventures beyond my comfort zone has propelled me to where I am today.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/Qcq1ocbH5ic?si=y-2I6HFqaRZsa26C">https://youtu.be/Qcq1ocbH5ic?si=y-2I6HFqaRZsa26C</a></div>
<p> </p>
<h3 id="heading-black-mentorship">Black mentorship</h3>
<p>I credit part of my rapid growth as a Developer Advocate to starting my DevRel career under the guidance of a Black manager, Brian Douglas. As I transition to the next phase of my career, I'm fortunate to have Angie Jones, the VP of Developer Relations, as my new manager. Angie is admired for her work and her character among all developer relations professionals. She is also one of the few Black VPs in DevRel that I could think of off the top of my head. As I progress in my career, having a manager who understands how to navigate the industry as a Black woman is paramount. Brian's mentorship was invaluable in my early journey, and I'm confident that Angie's leadership will continue to provide me with the insights and support I need to thrive in this field.</p>
<h3 id="heading-team">Team</h3>
<p>I recently met many members of the TBD team at an offsite, and they were <strong><em>all</em></strong> brilliant and friendly. What adds to my excitement about joining this team is that I already have trust and respect for several team members, some of whom I met while at Resilient Coders, a coding bootcamp I attended. <a target="_blank" href="https://twitter.com/Dayhaysoos">Nick DeJesus</a> and <a target="_blank" href="https://twitter.com/EbonyJLouis">Ebony Louis</a> have expertise in leading impactful, but behind the scenes work. I'm eager to collaborate with them and learn from their expertise. Nick has been a great mentor to me since I became a developer. I remember I joined a company that was using Redux, and he took the time to explain how it worked.</p>
<p>Additionally, <a target="_blank" href="https://twitter.com/Ace_KYD">Ace</a> recently joined the TBD team as a Staff Developer Advocate, and from what I've observed, he's absorbed so much of the technical knowledge around what TBD is building. I anticipate a dynamic collaboration where we can complement each other's strengths and provide a well-rounded approach to our work.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vtz76k0xsp9h36732cid.jpg" alt="Angie me and Ebony" /></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xcanp05n270x2xir03tk.jpg" alt="me Angie and Ace" /></p>
<h3 id="heading-title">Title</h3>
<p>People say things like money and titles don't matter, but that's a privileged take. I'm a black immigrant woman raised by a single mother of three in the hood; money and titles always matter. They're not the only factors that matter, but they do determine the trajectory of one's life. Due to imposter syndrome, I always sign up for junior roles at every new job. This time, I'm trusting myself to make Staff-level contributions and influence the team, the company, and the industry.</p>
<p>Beyond my own career trajectory, the aspect of representation is crucial. We need more underrepresented folks in leadership positions. It shouldn't even be rare. My goal is to reach a level where I can influence the prioritization of hiring more underrepresented individuals across the board. This step in my career is a meaningful stride towards fostering diversity and inclusion in the tech industry.</p>
<h3 id="heading-product">Product</h3>
<p>When I've mentioned this new opportunity with fellow developer friends, one recurring theme of skepticism has been the product. Understandably, they're unsure about it because it's still in development, and the term "decentralization" can often conjure images of gimmicks and scams prevalent in the crypto industry. Some, including myself, have questioned whether decentralization is a solution in search of a problem.</p>
<p>But as I've explored the technology that TBD is building, I realize:</p>
<ul>
<li><p>We are already searching for decentralized solutions for our social media platforms, especially as we've witnessed the decline and growing distrust of many social media applications. <em>Cough, cough. Twitter/X, Facebook and Instagram/Meta.</em></p>
</li>
<li><p>How technology is used determines its ethical implications; it is inherently neutral. For instance, people can use my main passion, AI, for harm and benefit. In the case of TBD, they focus on creating solutions that simplify sending money across borders. While this may not appear revolutionary to everyone, I've personally experienced the frustration of sending money to family members in Guyana and Antigua or friends in Nigeria. It's frustrating to stand in check cashing lines or to wire money successfully between banks. Another example is although there's a large developer presence in Nigeria, they're not eligible for GitHub Sponsors or many of the ways to get paid through open source. Simplifying these financial transactions can make a difference for the global south.</p>
</li>
</ul>
<p>This technology can improve financial equity, and it's not something I will get bored of. In fact, I've said this in a few blog posts and talks before -- I'm tired of our industry; we are too focused on building tools that only benefit privileged people.</p>
<p>There is a steep learning curve to understand the protocols and SDKs, but I welcome the challenge.</p>
<h2 id="heading-change-is-scary">Change is scary</h2>
<p>While I'm excited, I'm also nervous because change is scary, and I'm not 100% sure what to expect. I like knowing everything that's going to happen all the time. For example, I look up spoilers while I'm watching a movie.</p>
<p>I'll have to adapt to a different work culture, tweak my DevRel strategy for an early-stage company, and learn a lot of new technical concepts. I also anticipate that my unconventional DevRel strategy and personality may take time for the new company to warm up to. Still, I'm fully committed to embracing these challenges and enthusiastically navigating the unknown.</p>
<h2 id="heading-my-aspirations">My aspirations</h2>
<p>My greatest strengths are my storytelling skills and my ability to break concepts down for beginners, which I think the decentralized web needs more of. There's a lot of complexity around decentralization because it requires a paradigm shift in how we think, build, and use the Internet. Unfortunately, I don't see many resources that break down these concepts in a consumable way. I am most excited about creating beginner content and gradually building that into more advanced content.</p>
<p>In the upcoming months, I also hope to:</p>
<ul>
<li><p>Create sample applications that exemplify the potential of Web5.</p>
</li>
<li><p>Cultivate meaningful relationships both within the company and the wider community.</p>
</li>
<li><p>Support the enablement of open source externally and internally.</p>
</li>
<li><p>Continue my exploration of generative AI and integrate it into my work.</p>
</li>
<li><p>Evaluate the effectiveness and relevance of the DevRel strategies I've written about and implemented. Perhaps I wrote about those strategies, and they only work at a large company with a well-established DevRel team. Let's see how they work at an open source startup.</p>
</li>
</ul>
<p>I started building a few things for my own understanding of Web5. I built a <a target="_blank" href="https://github.com/blackgirlbytes/decentralized-to-do-list">decentralized to-do list</a> and a <a target="_blank" href="https://github.com/blackgirlbytes/did-alias-generator">DID alias generator</a>. Both projects are incomplete and don't use Web5 to its full potential, but I plan to add more incrementally. The final product could serve as a sample application demonstrating the advantages of Web5, perhaps in the form of an app that allows specific tasks from the to-do list to be shared with different users—whether they be partners, coworkers, or friends. Users could utilize aliases on the DWN instead of a DID (a lengthy alphanumeric string representing your digital identity). These aliases would be connected to their social media accounts, which could be a form of authentication on the shared to-do list application.</p>
<p>Saying goodbye to GitHub is bittersweet for me. I'm immensely grateful for the opportunities, relationships, and growth this chapter has provided. But, I'm also eagerly saying yes to having a voice in the evolution of the web. (If I see anything sus going on, you know I will speak up. 😉) As I embark on this new journey, I hope that, at TBD, we can collectively drive positive change within the industry, shaping the decentralized future of the web to benefit the less privileged. To the community, thank you for supporting me thus far. Just as I did when I took my first steps in Developer Relations, I invite you to continue this journey alongside me. Together, we'll explore decentralization, open source, and AI and make a meaningful impact on the tech landscape.</p>
]]></content:encoded></item><item><title><![CDATA[How to make an impact as a developer advocate]]></title><description><![CDATA[I find it hard to engage in discussions about my strategy for building a following and driving content engagement. While I never shy away from amplifying my content on social media, discussing these topics fills me with imposter syndrome, so I usuall...]]></description><link>https://blackgirlbytes.dev/how-to-make-an-impact-as-a-developer-advocate</link><guid isPermaLink="true">https://blackgirlbytes.dev/how-to-make-an-impact-as-a-developer-advocate</guid><category><![CDATA[Career]]></category><category><![CDATA[developer relations]]></category><category><![CDATA[Developer Advocate]]></category><category><![CDATA[leadership]]></category><category><![CDATA[GitHub]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Sun, 20 Aug 2023 17:35:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1692552701467/0b2b70f1-92bf-4e84-85de-e2c97a7102fc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I find it hard to engage in discussions about my strategy for building a following and driving content engagement. While I never shy away from amplifying my content on social media, discussing these topics fills me with imposter syndrome, so I usually respond with, “I don’t know. I just do it.” Additionally, for me to answer questions coherently, I need space to think and organize my thoughts. However, beneath these discussions lies a more profound question: How can a developer advocate genuinely leave a lasting impression?</p>
<p>As much as I would like to deny it, I think it’s evident that within almost two years working as Developer Advocate at GitHub, I’ve made a significant impact both within the company and across the developer community. Instead of being bashful, I’m choosing to embrace my influence and share my knowledge in a blog post.</p>
<p>Keep in mind:</p>
<ul>
<li><p>These strategies worked for me, but developer advocacy is not one size fits all because every company and developer community has different needs and goals.</p>
</li>
<li><p>This blog post is tailored specifically to Developer Advocates and may not directly apply to the broader spectrum of Developer Relations roles. Roles such as community managers, technical writers, and developer marketers have different objectives and responsibilities.</p>
</li>
<li><p>It's completely fine if your aspirations don't align with creating a sweeping impact. Your focus can be on diligently executing your role, and that's perfectly valid. I’m not asserting that you must do this; rather, I’m aiming to provide insights for those who wish to explore that path.</p>
</li>
<li><p>I’m primarily a content focused Developer Advocate with coding and community engagement forming complementary facets of my role.</p>
</li>
</ul>
<h2 id="heading-why-make-an-impact-as-a-developer-advocate">Why make an impact as a developer advocate?</h2>
<p>People like to deny it, but Developer Advocates are influencers. I don’t say influencer in the sense that we’re on Instagram taking pictures with flat tummy tea, but we influence the developer community and our companies.</p>
<p>Sometimes, the impetus driving one toward developer advocacy originates from a sense of disillusionment with the world of software engineering. This pivot opens doors to:</p>
<ul>
<li><p>Exploring and experimenting with new technologies.</p>
</li>
<li><p>Supporting fellow developers and having fun.</p>
</li>
<li><p>Establishing a public presence and engaging in meaningful conversations.</p>
</li>
<li><p>The opportunity to travel and connect with communities worldwide.</p>
</li>
</ul>
<h3 id="heading-reality-check-we-live-in-a-capitalist-society">Reality check: we live in a capitalist society</h3>
<p>While we do get to do these things, companies don’t pay us 6 figures to have fun. Many companies hire Developer Advocate to spread awareness, and ensure their products thrive, leading to increased revenue. We can achieve this through community engagement, conference talks, hands-on coding, and compelling content. The trust established within the developer community directly translates into a willingness to embrace our company’s products. The ultimate goal is to create a ripple effect where the knowledge you share with developers inspires them to educate others, thus amplifying the reach and impact.</p>
<h4 id="heading-navigating-ethical-advocacy">Navigating ethical advocacy</h4>
<p>But, our job goes beyond promoting a tool. You don’t want to encourage people to try out a technology that’s not actually good or serving them. That’s inauthentic and irresponsible. Our role includes providing honest feedback to our colleagues – whether it's product managers, engineers, or leadership – on areas that need improvement. When you've nurtured strong internal relationships and your impact is recognized within your company, it’s easier to guide the direction of the product.</p>
<p>While Developer Advocacy isn't a popularity contest, nor does it involve forcing people to use your company's technology, your goal is to cultivate relationships and establish a sufficiently strong reputation within both the developer community and your organization. This enables you to best serve developers with integrity and bring value to your company.</p>
<p>Your job is to make an impact that reverberates.</p>
<h2 id="heading-tips-for-making-an-impact">Tips for making an impact</h2>
<h3 id="heading-team-and-management">Team and management</h3>
<p>Working with a team and manager that sets you up for success is key.</p>
<p>Stay away from managers that:</p>
<ul>
<li><p>Place blame</p>
</li>
<li><p>Constantly change expectations</p>
</li>
<li><p>Aren’t invested in your success</p>
</li>
</ul>
<p>Lean into managers and teams that:</p>
<ul>
<li><p>Regularly give positive feedback</p>
</li>
<li><p>Occasionally give you constructive criticism, so you can improve</p>
</li>
<li><p>Find opportunities for you to grow</p>
</li>
<li><p>Positively mention your name in circles that you’re not in</p>
</li>
</ul>
<p><strong>My personal experience</strong></p>
<p>I’m grateful that I had good management throughout my tenure at GitHub because it helped lay a foundation for success. I had the opportunity to do activities like speak in the GitHub Universe Keynote because my colleagues and managers advocated for me and supported me.</p>
<h3 id="heading-understand-expectations">Understand expectations</h3>
<p>You can gain insights and make a good impression as early as the interview. (I’m not great at this, but I do see how impactful it is when people are good at this). During the interview phase, get an understanding of why the company is hiring and the strengths and weaknesses of the team you'll be joining. People struggle to get dev advocate jobs because they don’t understand why the company is trying to fill the role.</p>
<p>It’s important to understand what the company expects from you because you do not want to work at a company as a developer advocate with misaligned expectations. For example, if you are hoping to maintain and build the community, but they’re hoping you’re mostly going to be writing code, you will be very unhappy and so will the company.</p>
<p>Ask yourself the following questions:</p>
<ul>
<li><p>What’s the company excelling at?</p>
</li>
<li><p>What do you excel at?</p>
</li>
<li><p>Do those align?</p>
</li>
</ul>
<p>Jason Lengstrof made a video where he talks about the key to getting a job in Developer Relations is knowing what the company is looking for. I agree with this sentiment because it also helps you determine how you’re going to shine.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/3X-EUEOg638">https://youtu.be/3X-EUEOg638</a></div>
<p> </p>
<h3 id="heading-cultivate-a-strong-first-impression">Cultivate a Strong First Impression</h3>
<p>I’m not great at first impressions because I get super anxious. I believe there are several moments to change people’s minds about you. However, first impressions help set the trajectory of your time at the company. When you make a positive first impression, it’s easier to get buy-in from colleagues and support from the developer community.</p>
<p><strong>My personal experience:</strong></p>
<p>After I got my offer, I made my first contribution to open source, and I wrote a blog post called “Conquering the fear of contributing to open source”. I tweeted the blog post on the first day of my job at GitHub.</p>
<p>Beyond views and retweets, I was asked to do a keynote at All Things Open on this topic. And I turned this into a talk for other conferences. I didn’t write the blog post in hopes of speaking at a conference. I was just over eager about the job, but it helped to craft my brand as authentic, vulnerable, approachable, and passionate about open source.</p>
<p>This showed my team my work’s caliber and resonated within the developer community, placing me on their radar.</p>
<p>Check out my tips on <a target="_blank" href="https://dev.to/blackgirlbytes/tips-to-succeed-in-your-first-devrel-job-48m7">starting your first DevRel job</a> to learn more.</p>
<h3 id="heading-identify-what-the-company-cares-about">Identify what the company cares about</h3>
<p>By identifying your company's goals and aligning your efforts accordingly, you can ensure that your work resonates with the company's strategic direction and contributes positively to the developer community's understanding and adoption of key tools. Read your company and team goals occasionally because those goals will evolve over time.</p>
<p>Here are some helpful questions to ask yourself:</p>
<ul>
<li><p>Does this product make the company more money?</p>
</li>
<li><p>Did they invest heavily into this product?</p>
</li>
<li><p>Are they talking about this product a lot in meetings?</p>
</li>
<li><p>Does it seem like this product aligns with industry trends?</p>
</li>
<li><p>Is the company and its customers still learning how to use this product and how this product could be valuable?</p>
</li>
</ul>
<p><strong>My personal experience:</strong></p>
<p>For me, GitHub Copilot seemed like something I should invest my time in. When I started working at GitHub, I initially focused on open source and GitHub Pages, but as the company's focus shifted to tools like GitHub Copilot and GitHub Codespaces, I realized I needed to approach my job more strategically. GitHub Copilot received substantial investments from GitHub, Microsoft, and OpenAI. However, throughout the developer community, there were mixed reviews and miseducation about how GitHub Copilot worked. It was also evident that AI pair programming tools and generative AI were an industry trend. At the time, GitHub was still experimenting with how developers could use GitHub Copilot, and developers were still trying to learn how to use it too.</p>
<p>For me, this was a serendipitous time and opportunity to learn about GitHub Copilot. I wanted to figure out: Were the developer complaints valid? If yes, I would try to work with my coworkers to meet their needs. Were they misinformed? If yes, I would figure out how to educate them. And if it was both, I would do both.</p>
<h3 id="heading-use-the-product-as-a-beginner">Use the product as a beginner</h3>
<p>One effective strategy for aligning yourself with your company's goals and deepening your impact as a developer advocate is to fully immerse yourself in the products or tools you're promoting – from a beginner's perspective. It's common for companies to grant early access to developer advocates and other staff members before a product is made available to the general public. Use this as an opportunity to transition from a state of relative unfamiliarity to true expert before the product's official launch.</p>
<p><strong>My personal experience:</strong></p>
<p>When GitHub Copilot came out, I experimented with it. I was skeptical at first. My initial impression: So is GitHub Copilot autocomplete that sometimes doesn’t autocomplete? What’s the point?</p>
<p>As developers started to question the validity of the product and even direct questions toward me, I increased my usage and began to dig into how the tool actually worked. I wanted to confidently and knowledgeably respond to their inquiries.</p>
<p>Over time, I went from skeptic to enthusiast. It's easy to dismiss an innovation at first glance, but using the product to gain my own perspective enhanced my ability to authentically advocate for the product.</p>
<h3 id="heading-document-your-first-time-experiences">Document your first-time experiences</h3>
<p>Many times, we prefer to wait until we have an elaborate, complex implementation of a tool, but some products need “getting started” or “hello world” examples.</p>
<p><strong>My personal experience:</strong></p>
<p>At first, I couldn’t get GitHub Copilot to reproduce anything. It would only do something for the first time and never do it again. I finally found success in promoting GitHub Copilot to write a binary search algorithm. I took that example and wrote about it.</p>
<p>Keep in mind, the product you advocate for doesn’t have to be new or groundbreaking. it’s new to you, and it’s new to someone else, so your perspective on getting started is valuable. Sometimes, I would even tweet out my excitement when I got GitHub Copilot to do something that I didn’t expect it to do! Knowledge sharing before you gain ultimate expertise is super valuable for anyone who is a beginner user of that product.</p>
<h3 id="heading-create-fun-memorable-demos">Create fun, memorable demos</h3>
<p>People may argue with me about this, but if you’re trying to create awareness about a product, all of your demos don’t have to be practical. It’s okay to create a few demos that are eye-catching or fun to make people curious about the product. To make it fun and memorable, try integrating trending pop culture phenomena, emerging technologies, or both.</p>
<p>The first time I realized the value in small, but creative demos was when I saw <a target="_blank" href="https://twitter.com/lizziepika">Lizzie Siegle</a> do a presentation about Twilio. In her demo, she calls and messages people in the audience, then they get “rick rolled.” Out of all the talks and demos that day, Lizzie’s demonstration stood out. Here are a few developer advocates who I believe are also great at producing creative demos: <a target="_blank" href="https://twitter.com/colbyfayock">Colby Fayock</a>, <a target="_blank" href="https://twitter.com/whitep4nth3r">Salma Alam-Naylor</a>, and <a target="_blank" href="https://twitter.com/nutlope">Hassan El Mghari</a>. One of Hassan’s most popular demos is <a target="_blank" href="https://www.roomgpt.io/">RoomGPT</a>, which uses AI to redesign rooms.</p>
<p>Reuse that content – take your demo and turn it into a blog post, a conference talk, a webinar, a workshop, a tweet, and a TikTok.</p>
<p><strong>My personal experience:</strong></p>
<p>“I wrote this tweet with Copilot” became almost a meme for me. Every time I presented about GitHub Copilot, I did a demo where I would write a comment prompting GitHub Copilot to generate the code that calls the Twitter API to post a tweet that said, “I wrote this tweet with Copilot and I’m at x conference right now.” True, nobody would typically use GitHub Copilot to publish tweets, but that’s not the point. The goal was to spark awareness of GitHub Copilot. As a result, the tweet:</p>
<ul>
<li><p><strong>Piqued people’s interest:</strong> At the time, the developer community was popping on Twitter and I wanted people to wonder <em>“How could GitHub Copilot write tweets? Should I check out this product?”</em></p>
</li>
<li><p><strong>Community engagement:</strong> I saw other people tweet, “I wrote this tweet with Copilot” meaning they tried out the demo too.</p>
</li>
<li><p><strong>Invitation from conferences:</strong> Some conference organizers invite me to do the talk at their conference because they wanted me to post that I wrote a tweet with Copilot, and I was at their conference.</p>
</li>
<li><p><strong>Some practical utility:</strong> Even though the demo is silly, it showed that GitHub Copilot can help you interact with an API in a language that you are unfamiliar with.</p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/MichelleBakels/status/1650952175068037122?s=20">https://twitter.com/MichelleBakels/status/1650952175068037122?s=20</a></div>
<p> </p>
<h3 id="heading-integration-with-widely-used-frameworks-apis-and-tools">Integration with widely used frameworks, APIs, and tools</h3>
<p>When you build with and use a product you're advocating for, you become an expert in it. However, you don’t just have to keep the product within your company’s ecosystem.</p>
<p>Here are my reasons for integrating other technologies with your product:</p>
<ul>
<li><p>It helps you become aware of the limitations of the product</p>
</li>
<li><p>It makes it easy for developers to integrate the product into their daily workflow. For example: If they’re often using TypeScript, but your demos are only in Python, they may not realize you can use your company’s product with TypeScript.</p>
</li>
<li><p>You may catch the attention of people who built those frameworks or build with those frameworks, which presents an opportunity to collaborate.</p>
</li>
</ul>
<p>As a result, you can introduce a novel avenue to an entirely fresh audience.</p>
<p><strong>My personal experience</strong></p>
<p>I realized the importance of building examples with other frameworks when people would ask me, “Does this work with React or Astro?”, but I didn’t know the answer. People would also ask me things like does GitHub Copilot work better if you’re using it in a new project or using it in a large codebase with legacy code. I could try to ask other developers for their experience, but with a product so new, I felt more confident saying yes or no if I’ve tried it out on my own.</p>
<p>So, I started to build little projects with different frameworks. I also used GitHub Copilot when contributing to large open source projects. Now, I can confidently answer, “Yes, and here’s how you do it.”</p>
<h3 id="heading-make-it-practical">Make it practical</h3>
<p>As you build and integrate the product into your daily workflow, the use cases of the product become more evident. Start taking notes and creating content around these use cases. It’s helpful to lean into your developer community to figure out how they are using the product, too. There may be experts among your users that you can feature and collaborate with.</p>
<p><strong>My personal experience</strong></p>
<p>My team and I helped people see the value in GitHub Copilot by showing them that you can leverage GitHub Copilot for:</p>
<ul>
<li><p>Adding code snippets to documentation</p>
</li>
<li><p>Brainstorming</p>
</li>
<li><p>Syntax recollection</p>
</li>
<li><p>Unit testing</p>
</li>
<li><p>Converting applications from Javascript to TypeScript</p>
</li>
</ul>
<p>I believe this encouraged developers to adopt GitHub Copilot because they realized it was more than just autocomplete.</p>
<h3 id="heading-listen-to-developers">Listen to developers</h3>
<p>As you’re creating content, take a look at the questions and confusion developers have about the tool you advocate for. You may find their inquiries on social media platforms or your company’s discussion board. You can create content answering those questions. I also suggest maintaining a periodic session where you meet with product managers to express the pain points of users and you all can work together to figure out how to solve them. This way you can improve the overall developer experience through content and product improvements.</p>
<p><strong>My personal experience</strong></p>
<p>I often saw development teams wonder if it was worth it to purchase GitHub Copilot for Business. In turn, I wrote a blog post called, “<a target="_blank" href="https://dev.to/github/could-github-copilot-be-a-valuable-investment-for-my-team-4l9h">Can GitHub Copilot be a valuable investment for my team?</a>”</p>
<p>I also saw many people complaining that GitHub Copilot’s suggestions were inadequate and distracting. I empathize with that experience. However, I had a ton of tricks for getting optimal results for GitHub Copilot, so I wrote a blog post called, “<a target="_blank" href="https://dev.to/github/a-beginners-guide-to-prompt-engineering-with-github-copilot-3ibp">A Beginner’s Guide for Prompt Engineering with GitHub Copilot</a>.” To my surprise, my CEO shared this blog post with customers to improve their experience with GitHub Copilot. Writing that blog post strengthened my impact on the company internally.</p>
<h3 id="heading-thought-leadership">Thought leadership</h3>
<p>There is merit in going beyond how to use the product by providing your thoughts on how the product can transform the industry. We can start productive discourse by challenging our industry leaders.</p>
<p><strong>My personal experience</strong></p>
<p>When people argued that GitHub Copilot could limit learning, I wrote a blog post called, “<a target="_blank" href="https://dev.to/github/how-im-using-github-copilot-to-learn-p5js-39gh">How I’m using GitHub Copilot to learn p5.js</a>”, where I talk about taking an intentional and strategic approach to learning a new programming language alongside an AI pair programmer.</p>
<p>I also wrote blog posts and delivered conference talks about how <a target="_blank" href="https://dev.to/github/how-containerization-promotes-equity-in-tech-54h5">GitHub Codespaces and other cloud-based IDEs are catalysts for diversity, equity, and inclusion</a>.</p>
<p>Like I mentioned earlier, we are influencers and we have the power to invoke a paradigm shift, challenge norms, and start conversations that can reshape the tech industry.</p>
<p>Ask yourself the question: How can we leverage this developer productivity tool to ethically improve our society?</p>
<h3 id="heading-teach-your-company">Teach your company</h3>
<p>Developer Advocacy is even more effective when other people in the company are advocating for the product. You’re not the only one who needs to be knowledgeable about your company’s developer tools. Some technologists within your organization like to speak at conferences and write blog posts, too! There are individuals in customer success, support, product, engineering, legal, and leadership who may need to know more about how the product works, so they can successfully do their job. As a developer advocate, you may have the most experience using the product, so share that experience internally.</p>
<p><strong>My personal experience</strong></p>
<p>As GitHub and Microsoft have been focusing more on artificial intelligence and GitHub Copilot, my coworkers have been looking to increase their knowledge on the product, so they could best do their jobs. Some people may have initially been on different teams, but now they’ve moved to a Copilot-focused team. To assist in the knowledge transfer, I shared slide decks and repositories with Microsoft and GitHub, so that anyone can feel confident speaking about GitHub Copilot. I also did presentations:</p>
<ul>
<li><p>Introducing Customer Success managers at Microsoft to GitHub Copilot.</p>
</li>
<li><p>During GitHub’s Day of Learning, I presented a talk called “How to talk about GitHub Copilot” to the entire company.</p>
</li>
<li><p>I showed GitHub Campus Experts how to talk about GitHub Copilot as well.</p>
</li>
</ul>
<p>In essence, I’m creating more knowledgeable advocates for the product.</p>
<p>The beauty of this is now I won’t be one of the few people at my company that can speak about GitHub Copilot. Other people can, too! Less work for me, haha.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>By embracing authenticity, cultivating expertise, and engaging with tools from a beginner's perspective, you're not just advocating products – you're shaping the narrative of innovation itself.</p>
<p>As you code, create, and collaborate, remember that your influence extends beyond the immediate. It's in the connections you foster, the solutions you inspire, and the conversations you initiate. <strong>I believe</strong> developer advocacy isn't just about tools; it's about catalyzing change and leaving an indelible mark on the tech landscape.</p>
<p>So, step into your role with confidence. Your journey is a beacon, guiding others through the ever-evolving world of technology. Embrace the power of your impact, and know that your dedication will echo through the codebase, the community, and the future of tech.</p>
<p><em>The blog post was filled with my opinions, but it’s not the only way to do developer advocacy. What approaches do you take to help you make an impact within your developer community and within your company?</em></p>
<p><strong>Please note: I used ChatGPT to write my conclusion because I am not great with writing conclusions.</strong></p>
]]></content:encoded></item><item><title><![CDATA[Building an AI-Powered, Decentralized App for Time Management]]></title><description><![CDATA[The beauty of developer advocacy is that it offers the freedom to build anything, anytime, and in any way I desire. The downside is that it's a role that comes with its fair share of responsibilities, often leaving little room for personal exploratio...]]></description><link>https://blackgirlbytes.dev/building-an-ai-powered-decentralized-app-for-time-management</link><guid isPermaLink="true">https://blackgirlbytes.dev/building-an-ai-powered-decentralized-app-for-time-management</guid><category><![CDATA[web5]]></category><category><![CDATA[openai]]></category><category><![CDATA[AI]]></category><category><![CDATA[github copilot]]></category><category><![CDATA[Next.js]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Sun, 06 Aug 2023 23:45:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691365479464/51306706-4dd6-4353-aea7-5725a70361a8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The beauty of developer advocacy is that it offers the freedom to build anything, anytime, and in any way I desire. The downside is that it's a role that comes with its fair share of responsibilities, often leaving little room for personal exploration. While this allowed me to become an expert in my company's tools and products, it also means I risk falling behind on the latest technologies</p>
<p>Due to the hectic move of my life, I didn’t have reliable internet, so I couldn't hop on Zoom calls, watch Twitch streams, or host webinars for most of July. This was a blessing in disguise because it was the perfect opportunity to experiment with different technologies, despite the painfully slow execution times due to unreliable internet.</p>
<p>With some of that time, I developed a prototype for a to-do list on steroids, which I’ve named Time Blind. This application allows users to create a to-do list and then expand each task to identify subtasks and estimate how long each task will realistically take.</p>
<h3 id="heading-what-is-the-purpose-of-the-application">What is the purpose of the application?</h3>
<p>It sounds fictitious, but time blindness is the inability to recognize when time has passed or to estimate how long something will take. Many people with ADHD or autism struggle with this. I struggle with this. I’m really glad I found a term for this condition because I used to be really hard on myself when I was late to appointments</p>
<p>While some might suggest better planning as a solution, it's not that simple for those of us who either overestimate our capabilities or become so engrossed in a task that we lose track of time. For instance, I might plan to attend a party at 2pm and decide to start getting ready at noon. However, in the interim, I convince myself that I can wash dishes, do laundry, wash my hair (a process that takes at least 3 hours as a black woman), cook, and drive. Suddenly, it's 1:55 pm, and I'm just getting into my car.</p>
<p>I once came across an application that addressed this issue, but when I couldn't find it again, I decided to create my own solution.</p>
<p><strong>Disclaimer:</strong> This article is not a step-by-step tutorial, but rather a journey through my thought process and experiences as I explored these technologies. My aim is to inspire and provide insights into how these tools can be utilized in different ways. Please bear in mind that this was my first encounter with some of these technologies, so there may be instances where I haven't followed best practices. That's part of the learning process! This project was created for fun, and as such, the focus wasn't on aesthetics. The UI is basic (a little ugly to be honest) and functional, as my expertise lies in developer relations rather than design. Enjoy the read!</p>
<h2 id="heading-the-tech-stack-a-blend-of-the-familiar-and-the-new">The Tech Stack: A Blend of the Familiar and the New</h2>
<p>In this project, I've combined tools and technologies that I'm well-versed in with some that were new to me.</p>
<h3 id="heading-familiar">Familiar</h3>
<ul>
<li><p><strong>Next.js</strong> - This React framework is a favorite of mine, particularly for its ease in defining serverless API endpoints.</p>
</li>
<li><p><strong>GitHub Pages</strong> - A free hosting solution for frontend web apps, it was a perfect fit for the initial iteration of my project (before I added a backend).</p>
</li>
<li><p><strong>GitHub Actions</strong> - I leveraged GitHub Actions to deploy my Next.js app to GitHub Pages.</p>
</li>
<li><p><strong>Copilot Chat</strong> - This was handy for generating JS Doc comments and unit tests for my code.</p>
</li>
<li><p><strong>OpenAI GPT-4</strong> - While I wouldn't call myself an expert, I've dabbled with OpenAI's models before. For this app, I used GPT-4 to break tasks into subtasks and estimate the time each subtask would take.</p>
</li>
<li><p><strong>GitHub Codespaces</strong> - I love using this because of its boilerplate templates, which save me from writing boilerplate code myself. It also makes it easier to create shareable demos for other developers to try out.</p>
</li>
</ul>
<h3 id="heading-new-to-me">New to me</h3>
<ul>
<li><p><strong>Web5 SDK</strong> - This is an SDK for building decentralized web apps with DIDs, VCs, and DWNs. The central goal of Web 5 is to empower users with full control over their identity and data. This sets it apart from Web 3 protocols, which primarily identify users through crypto wallet addresses. In contrast, Web 5 introduces innovative features like self-owned decentralized identifiers, verifiable credentials, and decentralized web nodes, enabling secure data storage and message relaying. The value of decentralized applications became more evident to me after Elon purchased Twitter. He’s made so many changes that I don’t appreciate. Elon even changed the name of Twitter to X and took someone’s handle. That made me realize how easily someone can take the handle @blackgirlbytes. All of those factors piqued my interest in decentralization. The ease of storing data in the DWN was a bonus, requiring less overhead than a SQL database.</p>
</li>
<li><p><strong>Web5 assistant</strong> - There’s a ChatGPT plugin for the Web5 SDK. It was really helpful in navigating a technology that I’m not familiar with.</p>
</li>
<li><p><strong>Applitools</strong> - I used this to implement automated visual tests to my application.</p>
</li>
<li><p><strong>Playwright</strong> - I used Playwright for unit tests.</p>
</li>
<li><p><strong>Railway</strong> - I needed a different hosting solution since GitHub Pages only supports frontend applications. I initially chose Vercel, but the long API calls to OpenAI would time out on the Hobby plan. Railway didn't have this limitation, but I'm currently using the trial plan, so I'm not sure how long I can use it for free.</p>
</li>
</ul>
<h2 id="heading-building-the-application">Building the application</h2>
<h3 id="heading-github-codespace-nextjs-template">GitHub Codespace Next.js template</h3>
<p>Ah, GitHub Codespace templates – the reason why I will never run <code>npx create-next-app@latest</code>. I don’t hate running this command; I’m just a bit of a lazy developer. GitHub Codespace templates have a ton of ready-made boilerplate applications written in various, popular frameworks which makes it easy for me to get up and running in a sandbox environment.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f1n8aprmi8qohgg268uk.png" alt="Highlights the use this template button for Nextjs" /></p>
<p>You can create a Next.js GitHub Codespace template by navigating to <a target="_blank" href="https://github.com/codespaces/templates">https://github.com/codespaces/templates</a>. Then choosing the “Use this template” button for Next.js. This will trigger a codespace to open with boilerplate Next.js code with a browser preview.</p>
<p>What I particularly appreciate about this setup is the pre-configured dev container. It ensures that anyone who opens my project gets a running environment without any additional configuration on their part. This feature significantly streamlines the process of setting up a development environment, especially for new contributors or team members.</p>
<p>GitHub Codespaces also supports environment variables and secrets. This means you can open my repository in a GitHub Codespace without worrying about generating an API key. I've already stored one in my repository settings, so there's no need to figure out how to securely share environment variables with multiple people.</p>
<h3 id="heading-understanding-web5-basics">Understanding Web5 basics</h3>
<h4 id="heading-authentication">Authentication</h4>
<p>To authenticate users, Web 5 uses a W3C standard called Decentralized Identifiers (DID). A decentralized identifier is a verifiable id that can connect me to Web 5. The identifiers we use today are often tied to a specific service provider. For example, I’m @blackgirlbytes on Twitter and GitHub. In the Web 5 ecosystem, my id could look something like:</p>
<pre><code class="lang-plaintext">did:key:z6MkhvthBZDxVvLUswRey729CquxMiaoYXrT5SYbCAATc8V9
</code></pre>
<p>Here’s how you can instantiate and connect to a DWN using a decentralized identifier:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { web5, <span class="hljs-attr">did</span>: aliceDid } = <span class="hljs-keyword">await</span> Web5.connect();
</code></pre>
<p>Here’s what how I implemented this for Next.js in my <code>src/pages/index.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> [web5Instance, setWeb5Instance] = useState(<span class="hljs-literal">null</span>);
<span class="hljs-keyword">const</span> [aliceDid, setAliceDid] = useState(<span class="hljs-literal">null</span>);

useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">connectToWeb5</span>(<span class="hljs-params"></span>) </span>{
      <span class="hljs-keyword">const</span> { web5, did } = <span class="hljs-keyword">await</span> Web5.connect();
      setWeb5Instance(web5);
      setAliceDid(did);
    }

    connectToWeb5();

  }, []);
</code></pre>
<h4 id="heading-crud">CRUD</h4>
<p>Similar to REST APIs, a user can interact with Distributed Web Nodes (DWN) using CRUD principles. The DWN is our personal data store, so we’ll need to create, read, update, and delete data to interact with our store.</p>
<p><strong>Create (write) records</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> { record } = <span class="hljs-keyword">await</span> web5.dwn.records.create({
  <span class="hljs-attr">data</span>: <span class="hljs-string">"Its me, snitches"</span>,
  <span class="hljs-attr">message</span>: {
    <span class="hljs-attr">dataFormat</span>: <span class="hljs-string">'text/plain'</span>,
  },
});

<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'writeResult'</span>, record);
</code></pre>
<p><strong>Read records</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> readResult = <span class="hljs-keyword">await</span> record.data.text();
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'readResult'</span>, readResult)
</code></pre>
<p><strong>Update (edit) records</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> updateResult = <span class="hljs-keyword">await</span> record.update({<span class="hljs-attr">data</span>: <span class="hljs-string">"Professional bug maker"</span>});
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'updateResult'</span>, updateResult)
</code></pre>
<p><strong>Delete records</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> deleteResult = <span class="hljs-keyword">await</span> record.delete();
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'deleteResult'</span>, deleteResult)
</code></pre>
<h3 id="heading-starting-with-the-to-do-list">Starting with the To Do list</h3>
<p>Before building Time Blind, I started by building a to-do list. I wanted to get the core functionality down, especially since I was new to the Web5 SDK. I built a few components that leveraged the methods I mentioned above.</p>
<p>Here’s an example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addTask</span>(<span class="hljs-params">event</span>) </span>{
    event.preventDefault(); <span class="hljs-comment">// Prevent form from submitting and refreshing the page</span>
    <span class="hljs-keyword">if</span> (web5Instance &amp;&amp; aliceDid &amp;&amp; newTask.trim() !== <span class="hljs-string">''</span>) {
      <span class="hljs-keyword">const</span> taskData = {
        <span class="hljs-string">'@context'</span>: <span class="hljs-string">'https://schema.org/'</span>,
        <span class="hljs-string">'@type'</span>: <span class="hljs-string">'Action'</span>,
        <span class="hljs-attr">name</span>: newTask,
        <span class="hljs-attr">completed</span>: <span class="hljs-literal">false</span>,
      };

      <span class="hljs-keyword">const</span> { record } = <span class="hljs-keyword">await</span> web5Instance.dwn.records.create({
        <span class="hljs-attr">data</span>: taskData,
        <span class="hljs-attr">message</span>: {
          <span class="hljs-attr">dataFormat</span>: <span class="hljs-string">'application/json'</span>,
          <span class="hljs-attr">schema</span>: <span class="hljs-string">'https://schema.org/Action'</span>,
        },
      });

      <span class="hljs-comment">// Send the record to the DWN.</span>
      <span class="hljs-keyword">await</span> record.send(aliceDid);

      setTasks(<span class="hljs-function">(<span class="hljs-params">prevTasks</span>) =&gt;</span> [...prevTasks, { <span class="hljs-attr">id</span>: record.id, <span class="hljs-attr">text</span>: newTask }]);
      setNewTask(<span class="hljs-string">''</span>);
    }
  }
</code></pre>
<p>When a user creates a task, the application uses the dwn.records.create method from the Web5.js SDK. This method creates a new record with the task data and sends it to the Decentralized Web Node (DWN) associated with the user's Decentralized Identifier (DID). The task data includes the task name and its completion status.</p>
<p>You might’ve noticed that I’m using a schema. By using a schema, I’m ensuring that my tasks have a consistent, predictable structure.</p>
<p>If you want to check out the code for this to-do list, here is the <a target="_blank" href="https://github.com/blackgirlbytes/decentralized-to-do-list">repository</a>.</p>
<h3 id="heading-copilot-chat-for-generating-tests-with-playwright-and-applitools">Copilot Chat for generating tests with Playwright and Applitools</h3>
<p>I’m not super familiar with Playwright or Applitools, so I leaned on Copilot Chat to help me generate tests for me. Below are examples of interactions I had with Copilot Chat to generate the unit tests.</p>
<p><strong>Copilot Chat generates more tests for me</strong></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/voow1dzq82ztqqkkh0ky.png" alt="Image description" /></p>
<p><strong>I asked Copilot Chat for clarification on some code it suggested</strong></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/51ywc5e3sce46psb1pa3.png" alt="Image description" /></p>
<p><strong>I asked Copilot Chat for alternative suggestions after realizing the initial suggestion won’t work in my codebase.</strong></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jn7q6c61iayszi8w96oc.png" alt="Image description" /></p>
<p><strong>Copilot Chat gave me advice on how to navigate the Applitools Eyes interface.</strong></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1433h9yl4ene3rs5us3y.png" alt="Image description" /></p>
<h3 id="heading-deploying-with-github-pages-with-github-actions">Deploying with GitHub Pages with GitHub Actions</h3>
<p>I used a GitHub Action to deploy my Next.js app to GitHub Pages.. It's important to note that this approach is suitable for applications without a server. . Upon successful deployment, the workflow automatically generated a URL for me: <a target="_blank" href="https://blackgirlbytes.github.io/decentralized-to-do-list/">https://blackgirlbytes.github.io/decentralized-to-do-list/</a>.</p>
<p><strong>Here’s what the action workflow looked like:</strong></p>
<pre><code class="lang-yaml"><span class="hljs-comment"># Sample workflow for building and deploying a Next.js site to GitHub Pages</span>
<span class="hljs-comment">#</span>
<span class="hljs-comment"># To get started with Next.js see: https://nextjs.org/docs/getting-started</span>
<span class="hljs-comment">#</span>
<span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">Next.js</span> <span class="hljs-string">site</span> <span class="hljs-string">to</span> <span class="hljs-string">Pages</span>

<span class="hljs-attr">on:</span>
  <span class="hljs-comment"># Runs on pushes targeting the default branch</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [<span class="hljs-string">"main"</span>]

  <span class="hljs-comment"># Allows you to run this workflow manually from the Actions tab</span>
  <span class="hljs-attr">workflow_dispatch:</span>

<span class="hljs-comment"># Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages</span>
<span class="hljs-attr">permissions:</span>
  <span class="hljs-attr">contents:</span> <span class="hljs-string">read</span>
  <span class="hljs-attr">pages:</span> <span class="hljs-string">write</span>
  <span class="hljs-attr">id-token:</span> <span class="hljs-string">write</span>

<span class="hljs-comment"># Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.</span>
<span class="hljs-comment"># However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.</span>
<span class="hljs-attr">concurrency:</span>
  <span class="hljs-attr">group:</span> <span class="hljs-string">"pages"</span>
  <span class="hljs-attr">cancel-in-progress:</span> <span class="hljs-literal">false</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-comment"># Build job</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v3</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Detect</span> <span class="hljs-string">package</span> <span class="hljs-string">manager</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">detect-package-manager</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">|
          if [ -f "${{ github.workspace }}/yarn.lock" ]; then
            echo "manager=yarn" &gt;&gt; $GITHUB_OUTPUT
            echo "command=install" &gt;&gt; $GITHUB_OUTPUT
            echo "runner=yarn" &gt;&gt; $GITHUB_OUTPUT
            exit 0
          elif [ -f "${{ github.workspace }}/package.json" ]; then
            echo "manager=npm" &gt;&gt; $GITHUB_OUTPUT
            echo "command=ci" &gt;&gt; $GITHUB_OUTPUT
            echo "runner=npx --no-install" &gt;&gt; $GITHUB_OUTPUT
            exit 0
          else
            echo "Unable to determine package manager"
            exit 1
          fi
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Node</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">node-version:</span> <span class="hljs-string">"16"</span>
          <span class="hljs-attr">cache:</span> <span class="hljs-string">${{</span> <span class="hljs-string">steps.detect-package-manager.outputs.manager</span> <span class="hljs-string">}}</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">Pages</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/configure-pages@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-comment"># Automatically inject basePath in your Next.js configuration file and disable</span>
          <span class="hljs-comment"># server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized).</span>
          <span class="hljs-comment">#</span>
          <span class="hljs-comment"># You may remove this line if you want to manage the configuration yourself.</span>
          <span class="hljs-attr">static_site_generator:</span> <span class="hljs-string">next</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Restore</span> <span class="hljs-string">cache</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/cache@v3</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">path:</span> <span class="hljs-string">|
            .next/cache
</span>          <span class="hljs-comment"># Generate a new cache whenever packages or source files change.</span>
          <span class="hljs-attr">key:</span> <span class="hljs-string">${{</span> <span class="hljs-string">runner.os</span> <span class="hljs-string">}}-nextjs-${{</span> <span class="hljs-string">hashFiles('**/package-lock.json',</span> <span class="hljs-string">'**/yarn.lock'</span><span class="hljs-string">)</span> <span class="hljs-string">}}-${{</span> <span class="hljs-string">hashFiles('**.[jt]s',</span> <span class="hljs-string">'**.[jt]sx'</span><span class="hljs-string">)</span> <span class="hljs-string">}}</span>
          <span class="hljs-comment"># If source files changed but packages didn't, rebuild from a prior cache.</span>
          <span class="hljs-attr">restore-keys:</span> <span class="hljs-string">|
            ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json', '**/yarn.lock') }}-
</span>      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">${{</span> <span class="hljs-string">steps.detect-package-manager.outputs.manager</span> <span class="hljs-string">}}</span> <span class="hljs-string">${{</span> <span class="hljs-string">steps.detect-package-manager.outputs.command</span> <span class="hljs-string">}}</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">with</span> <span class="hljs-string">Next.js</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">${{</span> <span class="hljs-string">steps.detect-package-manager.outputs.runner</span> <span class="hljs-string">}}</span> <span class="hljs-string">next</span> <span class="hljs-string">build</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Static</span> <span class="hljs-string">HTML</span> <span class="hljs-string">export</span> <span class="hljs-string">with</span> <span class="hljs-string">Next.js</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">${{</span> <span class="hljs-string">steps.detect-package-manager.outputs.runner</span> <span class="hljs-string">}}</span> <span class="hljs-string">next</span> <span class="hljs-string">export</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Upload</span> <span class="hljs-string">artifact</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/upload-pages-artifact@v2</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">path:</span> <span class="hljs-string">./out</span>

  <span class="hljs-comment"># Deployment job</span>
  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">name:</span> <span class="hljs-string">github-pages</span>
      <span class="hljs-attr">url:</span> <span class="hljs-string">${{</span> <span class="hljs-string">steps.deployment.outputs.page_url</span> <span class="hljs-string">}}</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">needs:</span> <span class="hljs-string">build</span>
    <span class="hljs-attr">steps:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">GitHub</span> <span class="hljs-string">Pages</span>
        <span class="hljs-attr">id:</span> <span class="hljs-string">deployment</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/deploy-pages@v2</span>
</code></pre>
<h3 id="heading-incorporating-ai-for-task-breakdown-and-estimation">Incorporating AI for task breakdown and estimation</h3>
<p>With a functional to-do list in place, the next step was to incorporate AI to dissect each task on the list and provide estimated completion times. I added this on the server rather than the frontend to maintain the confidentiality of the API key required to make calls to the OpenAI model.</p>
<p>In my request to OpenAI, I specified that I wanted to use the GPT-4 model, I gave the model an identity, and I made a request. You can see the code below:</p>
<pre><code class="lang-javascript">openai.createChatCompletion({
      <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4"</span>, <span class="hljs-comment">// Using GPT-4</span>
      <span class="hljs-attr">messages</span>: [
        { <span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>, <span class="hljs-string">"content"</span>: <span class="hljs-string">`You are a helpful planning assistant. Please help me break down the following task on my to-do list with an estimated time that it could take: <span class="hljs-subst">${task}</span>`</span> },
      ],
    });
</code></pre>
<p>My request prompts the AI model to act as a helpful planning assistant, breaking down the specified task and estimating the time it might take to complete.</p>
<h3 id="heading-copilot-chat-for-documenting-my-code">Copilot Chat for documenting my code</h3>
<p>By highlighting the code, I can prompt Copilot Chat to generate JS Doc comments for my code.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6qdb1xj7wzavydpd4yh7.png" alt="Image description" /></p>
<p><strong>Here’s an example of the JS Doc comments that Copilot Chat generated for my API endpoint:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">/**
 * This function is an API endpoint that generates a task breakdown using OpenAI's GPT-4 model.
 * It expects a POST request with a body containing a 'tasks' property.
 * If the OpenAI API key is not configured or if the 'tasks' property is not provided, it responds with an error.
 * If the OpenAI API request fails, it responds with the error returned by the OpenAI API.
 * If the OpenAI API request is successful, it responds with the generated task breakdown.
 *
 * <span class="hljs-doctag">@param <span class="hljs-type">{Object}</span> <span class="hljs-variable">req</span></span> - The request object. It should have a 'body' property with a 'tasks' property.
 * <span class="hljs-doctag">@param <span class="hljs-type">{Object}</span> <span class="hljs-variable">res</span></span> - The response object. It is used to send the response back to the client.
 * <span class="hljs-doctag">@returns <span class="hljs-type">{Promise&lt;void&gt;}</span> </span>- A Promise that resolves when the response has been sent.
 */</span>
<span class="hljs-keyword">const</span> { Configuration, OpenAIApi } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"openai"</span>);

<span class="hljs-keyword">const</span> configuration = <span class="hljs-keyword">new</span> Configuration({
  <span class="hljs-attr">apiKey</span>: process.env.OPENAI_API_KEY,
});
<span class="hljs-keyword">const</span> openai = <span class="hljs-keyword">new</span> OpenAIApi(configuration);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">req, res</span>) </span>{
  <span class="hljs-keyword">if</span> (!configuration.apiKey) {
    res.status(<span class="hljs-number">500</span>).json({
      <span class="hljs-attr">error</span>: {
        <span class="hljs-attr">message</span>: <span class="hljs-string">"OpenAI API key not configured, please follow instructions in README.md"</span>,
      }
    });
    <span class="hljs-keyword">return</span>;
  }

  <span class="hljs-keyword">const</span> task = req.body.tasks || <span class="hljs-string">''</span>;
  <span class="hljs-keyword">if</span> (task === <span class="hljs-string">''</span>) {
    res.status(<span class="hljs-number">400</span>).json({
      <span class="hljs-attr">error</span>: {
        <span class="hljs-attr">message</span>: <span class="hljs-string">"Please enter a valid task"</span>,
      }
    });
    <span class="hljs-keyword">return</span>;
  }

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> completion = <span class="hljs-keyword">await</span> openai.createChatCompletion({
      <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4"</span>, <span class="hljs-comment">// Using GPT-4</span>
      <span class="hljs-attr">messages</span>: [
        { <span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>, <span class="hljs-string">"content"</span>: <span class="hljs-string">`You are a helpful planning assistant. Please help me break down the following task on my to-do list with an estimated time that it could take: <span class="hljs-subst">${task}</span>`</span> },
      ],
    });

    <span class="hljs-keyword">const</span> result = completion.data.choices[<span class="hljs-number">0</span>].message.content;
    res.status(<span class="hljs-number">200</span>).json({ result });
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-comment">// Consider adjusting the error handling logic for your use case</span>
    <span class="hljs-keyword">if</span> (error.response) {
      <span class="hljs-built_in">console</span>.error(error.response.status, error.response.data);
      res.status(error.response.status).json(error.response.data);
    } <span class="hljs-keyword">else</span> {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">`Error with OpenAI API request: <span class="hljs-subst">${error.message}</span>`</span>);
      res.status(<span class="hljs-number">500</span>).json({
        <span class="hljs-attr">error</span>: {
          <span class="hljs-attr">message</span>: <span class="hljs-string">'An error occurred during your request.'</span>,
        }
      });
    }
  }
}
</code></pre>
<h3 id="heading-deploying-with-railway">Deploying with Railway</h3>
<p>I chose to deploy my application to Railway because I needed a hosting solution that supports full stack applications. This worked perfectly for me! However, I did encounter a few challenges while navigating through Railway's user interface. For example, I just wanted to deploy my repository, and I got stuck in a loop of configuring the GitHub App for Railway. The part of the documentation I checked lacked visual aids, and I’m a visual learner, so that was hard for me. I ended up watching a YouTube video to navigate the platform. Despite these minor hiccups, my overall experience with Railway was positive, and I was particularly pleased with the successful deployment of my application.</p>
<h2 id="heading-final-thoughts">Final thoughts</h2>
<h3 id="heading-struggles">Struggles</h3>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/blackgirlbytes/status/1683480039851974665?s=20">https://twitter.com/blackgirlbytes/status/1683480039851974665?s=20</a></div>
<p> </p>
<p>The app is unbearably slow. My proficiency in performance optimization is admittedly lacking, as I've never held a role where optimizing an application's speed was a primary responsibility. I believe the key to enhancing my application's performance lies in the GPT-4 calls. I was told making my prompt more specific should help, but I’m not sure how. If you have suggestions for improvement, feel free to make a <a target="_blank" href="https://github.com/blackgirlbytes/time-blind">pull request</a>. I would love to learn from folks.</p>
<h3 id="heading-i-had-fun">I had fun</h3>
<p>Coding for fun is therapeutic. Hopefully, I make time to do this again.</p>
<h3 id="heading-be-easy-on-me">Be easy on me</h3>
<p>Like I mentioned, this is not a perfect application written in perfect code. I’m just sharing it as a means for learning in public, for insight, and to start a conversation.</p>
<h2 id="heading-check-it-out">Check it out</h2>
<h3 id="heading-decentralized-to-do-list">Decentralized to do list</h3>
<p>You can access my decentralized to do list here: <a target="_blank" href="https://blackgirlbytes.github.io/decentralized-to-do-list/">https://blackgirlbytes.github.io/decentralized-to-do-list/</a></p>
<p>If you want to improve it, you can make a pull request: <a target="_blank" href="https://github.com/blackgirlbytes/decentralized-to-do-list">https://github.com/blackgirlbytes/decentralized-to-do-list</a></p>
<h3 id="heading-time-blind">Time Blind</h3>
<p>You can access my Time Blind app here: <a target="_blank" href="https://time-blind-production.up.railway.app/">https://time-blind-production.up.railway.app/</a></p>
<p>If you want to improve it, you can make a pull request: <a target="_blank" href="https://github.com/blackgirlbytes/time-blind">https://github.com/blackgirlbytes/time-blind</a></p>
<p>If it stops working, you can open an issue in my repository!</p>
<p><strong>What are your opinions on the different technologies that I’ve leveraged? What tools and technologies should I try next? Comment below.</strong></p>
]]></content:encoded></item><item><title><![CDATA[How container technology promotes equity in tech]]></title><description><![CDATA[In the tech industry, we often talk a lot about diversity, equity, and inclusion. Sometimes, we mention belonging. But, if we’re being honest very little improvements have been made to the state of diversity in our field. During the peak of the Black...]]></description><link>https://blackgirlbytes.dev/how-container-technology-promotes-equity-in-tech</link><guid isPermaLink="true">https://blackgirlbytes.dev/how-container-technology-promotes-equity-in-tech</guid><category><![CDATA[GitHub]]></category><category><![CDATA[github-codespaces]]></category><category><![CDATA[codespaces]]></category><category><![CDATA[containers]]></category><category><![CDATA[Diversity]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Sat, 05 Aug 2023 00:45:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1691196708549/6ce52a30-1da1-4219-ae9f-00e787200a70.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the tech industry, we often talk a lot about diversity, equity, and inclusion. Sometimes, we mention belonging. But, if we’re being honest very little improvements have been made to the <a target="_blank" href="https://builtin.com/diversity-inclusion/state-of-dei-in-tech-2022-results">state of diversity</a> in our field. During the peak of the Black Lives Matter movement, companies made commitments to amplify diversity. Initiatives like renaming default branches from <code>master</code> to <code>main</code> were undertaken, but their true impact warrants scrutiny. The insights from <a target="_blank" href="https://builtin.com/diversity-inclusion/state-of-dei-in-tech-2022-results">Built In's State of Diversity 2022 Report</a> illustrate my point: ¼ of the surveyed companies were over 70 percent white, with 73 percent acknowledging the absence of Black leaders in executive positions. Additionally, the report highlighted that 39 percent of women and BIPOC employees felt their voices and perspectives were ignored in the decision-making process. Today, we’re also seeing that <a target="_blank" href="https://www.shrm.org/resourcesandtools/hr-topics/behavioral-competencies/global-and-cultural-effectiveness/pages/why-are-dei-roles-disappearing-.aspx">DEI roles are slowly disappearing</a>.</p>
<p>Part of the issue is that we’re laser-focused on the wrong things. We often build our products and companies that fine-tune the lives of those who already have a head start. For example: we have multiple platforms that make sharing documents easier or share code. We’re using artificial intelligence to accelerate developer productivity. However, we are missing technological breakthroughs that address fundamental human predicaments such as hunger, homelessness, and the glaring lack of diversity in the tech sphere. I’m not naive. I acknowledge that this is because these problems take more effort to solve. Perhap, it doesn’t have to be such a heavy lift. The tools we’ve developed to solve first-world problems have the potential to uplift those marginalized by circumstance. Specifically, I believe that while container technology streamlines software deployment, it also shatters barriers, paving the way for a more equitable landscape. In this blog post, we’ll explore the powerful synergy between containerization and equity in the tech industry.</p>
<p>We’ll break this down by understanding the definitions of:</p>
<ul>
<li><p>Privilege</p>
</li>
<li><p>Equality</p>
</li>
<li><p>Equity</p>
</li>
</ul>
<p>Then, we will take a look at:</p>
<ul>
<li><p>Why we use containers</p>
</li>
<li><p>The history of container technology</p>
</li>
<li><p>And how they promote equity in our industry</p>
</li>
</ul>
<h2 id="heading-privilege">Privilege</h2>
<p>Privilege is a good thing, but the word can sometimes evoke unintended negative reactions. The term “privilege” is often misconstrued as “you didn’t work for your achievements.” However, privilege refers to the fact that you have access to something that other people may not have. It's a universal truth: everyone holds some form of privilege. There are different types of privilege including, but not limited to: race, education, sexuality, gender, class, language, ethnicity, ability, and age.</p>
<p>A prime example of someone who doesn’t always acknowledge his privilege is Drake.</p>
<p><img src="https://media.giphy.com/media/TGamxxMMiaWw8/giphy.gif" alt /></p>
<p>While his song "Started from the Bottom" chronicles his path to stardom, it sometimes obscures the fact that he had a head start due to his acting career as a child star on Degrassi: The Next Generation. Since becoming a rapper, he’s amassed over:</p>
<ul>
<li><p>5 Grammys</p>
</li>
<li><p>7 studio albums</p>
</li>
<li><p>3 compilation albums</p>
</li>
<li><p>4 extended plays</p>
</li>
<li><p>7 mixtapes</p>
</li>
<li><p>140 singles</p>
</li>
<li><p>84 music videos</p>
</li>
</ul>
<p>This is not to diminish his accomplishments, but rather to highlight how privilege plays a role. He worked hard to be one of the few Canadian rappers who are popular in the United States.</p>
<p>On a more personal note, my own life is full of disadvantages—living in homeless shelters, being an immigrant, a woman, and Black. But amid these experiences, I acknowledge the privileges I hold— a supportive family, access to education, a role at GitHub, and a public platform as a Developer Advocate.</p>
<p>The important thing is that we use our privileges to uplift others.</p>
<h2 id="heading-equity-vs-equality">Equity vs. Equality</h2>
<p>Equity and equality are terms that are often used interchangeably, but they have different meanings.</p>
<p>Equality means each individual or group of people is given the same resources or opportunities. Equity recognizes that each person has different circumstances and allocates the exact resources and opportunities needed to reach an equal outcome.</p>
<h2 id="heading-what-is-a-container">What is a container?</h2>
<p>According to the official Docker website, “A container is a standard unit of software that packages up code and all its dependencies so the application runs quickly and reliably from one computing environment to another”</p>
<p>The way I think of it is: a container holds code for the app, other tools that it depends on, and settings that make sure it works consistently across different computers. In this way, the application will behave the same regardless of whether it resides on your computer, production, or your uncle's 2015 Dell machine. Containers enable software engineers to program in a consistent environment. Your dev environment mirrors production with the same operating system, configurations, and dependencies. This ensures bugs and features behave the same across all environments.</p>
<h2 id="heading-why-containers">Why containers?</h2>
<p>If you’re a developer, and you’ve ever said the words, “It works on my machine”, you know the pain and embarrassment of working tirelessly on a project, but you’re unable to show the fruit of your labor to your coworkers because it doesn’t work on their computers or on a different environment. Because of this, the software industry has spent years in pursuit of a solution to running and shipping software automatically reliably from one environment to another.</p>
<p>It was an incremental climb to developing a solution.</p>
<h2 id="heading-a-brief-history-on-container-technology">A brief history on container technology</h2>
<h3 id="heading-chroot">Chroot</h3>
<p>We started trying to solve this problem in the 1970s with <code>chroot</code>, which stands for “Change root.” It allows developers to change the root directory for a running process and its children. Developers can use chroot to create a new isolated environment with its own root directory. Creating isolated environments to build and test software helps developers ensure that software can run in specific environments and avoids potential conflicts with system libraries and dependencies.</p>
<h3 id="heading-cgroups">Cgroups</h3>
<p>In the 2000s, the industry created Cgroups, also known as control groups. They fairly manage and divide resources like CPU, memory, and storage among processes or groups of processes. This way each application isn’t fighting for resources. Cgroups are one of the building blocks of containerization because they help containers ensure they are receiving a fair share of resources.</p>
<h3 id="heading-docker">Docker</h3>
<p>Then, in March 2013, folks like Solomon Hykes popularized the use of containers. Docker, an open source platform, introduced a suite of management and packaging tools for containerization. It enables developers to create, deploy, and manage applications within containers. Overall, it made containers more accessible for technologists.</p>
<h2 id="heading-how-container-technology-promotes-equity">How container technology promotes equity</h2>
<p>The reason that software development teams are not diverse is not because of a lack of interest from people of diverse and even underprivileged backgrounds. Common factors for a lack of diversity at a tech company are:</p>
<ul>
<li><p>Barriers to Entry: Many potential talents face difficulties accessing the field in the first place.</p>
</li>
<li><p>Stunted Growth and Inclusivity: Even when they manage to enter, they often encounter challenges in advancing and feeling valued and included within their teams. After years of feeling stuck or excluded, disenfranchised people may feel more tempted to quit.</p>
</li>
</ul>
<p>Barriers to entry exist for many reasons, including the following:</p>
<ul>
<li><p>Limited access to computers or limited access to devices with strong computing power</p>
</li>
<li><p>Lack of knowledge on how to initiate their journey into software development.</p>
</li>
</ul>
<h3 id="heading-access">Access</h3>
<p>Container technology ushered in the emergence of other tools like Replit, GitPod, and GitHub Codespaces, which empower people with low computing power or limited computing resources to code even on devices like their phones or iPads. These tools run in your browser, which means that you consume less of your machine's resources, so you don’t need heavy computing power.</p>
<h3 id="heading-time-to-start">Time-to-start</h3>
<p>Whether you are joining a team, contributing to an open source, or you’re just trying to learn how to code, setting up your environment as a new developer is an overwhelming task. For companies, project configurations can be automated, ensuring that any developer contributing to the codebase can effortlessly set up and run projects. If you’re a single developer, trying to learn a new programming language or framework, you can leverage <a target="_blank" href="https://github.com/codespaces/templates">GitHub Codespace Templates</a>. We have templates for frameworks and languages like, Next.js, Ruby, Django with boilerplate code. This immediate access circumvents the time-consuming setup phase.</p>
<h3 id="heading-stunted-growth-and-inclusivity">Stunted Growth and Inclusivity</h3>
<p>From onboarding to deployment, minorities don’t always get the mentorship and sponsorship they deserve, which can lead to feeling stuck in your career and excluded.</p>
<h4 id="heading-onboarding">Onboarding</h4>
<p>Navigating outdated documentation during onboarding can be frustrating, underscoring the value of tools like GitHub Codespaces.</p>
<h4 id="heading-getting-help">Getting help</h4>
<p>Collaborating on remote teams can pose challenges in sharing local environments with coworkers. GitHub Codespaces provides solutions through features like port forwarding and liveshare, facilitating seamless collaboration and troubleshooting.</p>
<h4 id="heading-deployment">Deployment</h4>
<p>Leveraging container technology like GitHub Codespaces minimizes the risk of discrepancies between local, staging, and production environments. This ensures a more consistent and reliable development experience.</p>
<h2 id="heading-the-hard-part">The hard part</h2>
<p>I work at GitHub, so I’ll focus on one tool I know most intimately: GitHub Codespaces. Although GitHub Codespaces streamlines the onboarding process, it uses configuration-as-code to establish a consistent development environment.</p>
<p>In some of my past blog posts, I outline how to set up a development container in GitHub Codespaces for a:</p>
<ul>
<li><p><a target="_blank" href="https://dev.to/github/how-to-set-up-a-dev-container-for-a-nextjstypescript-app-2jd">Next.js/Typescript project</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/github/chatgpt-meets-github-codespaces-how-im-optimizing-chatgpt-quickstart-plugins-for-remote-development-5bc8">Python project</a></p>
</li>
</ul>
<p>The TLDR, to make GitHub Codespaces install and run your project, you should provide your devcontainer with the following:</p>
<ul>
<li><p>Installation commands like <code>npm install</code></p>
</li>
<li><p>Execution commands <code>npm run dev</code></p>
</li>
<li><p>The port you want the project to run on like <code>[forwardPort: 3000]</code></p>
</li>
<li><p>And Codespace lifecycle properties like <code>[postCreateCommand]</code> - These control when the commands you provided should run.</p>
</li>
</ul>
<p>Below are examples of two devcontainer.json files that I created for specific projects.</p>
<h3 id="heading-python">Python</h3>
<pre><code class="lang-json">
<span class="hljs-comment">// For format details, see https://aka.ms/devcontainer.json. For config options, see the</span>

<span class="hljs-comment">// README at: https://github.com/devcontainers/templates/tree/main/src/python</span>

{

  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Python 3"</span>,

  <span class="hljs-comment">// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile</span>

  <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/python:0-3.11-bullseye"</span>,

  <span class="hljs-attr">"features"</span>: {

    <span class="hljs-attr">"ghcr.io/devcontainers-contrib/features/coverage-py:2"</span>: {}

  }

  <span class="hljs-comment">// Features to add to the dev container. More info: https://containers.dev/features.</span>

  <span class="hljs-comment">// "features": {},</span>

  <span class="hljs-comment">// Use 'forwardPorts' to make a list of ports inside the container available locally.</span>

  <span class="hljs-string">"forwardPorts"</span>: [<span class="hljs-number">5003</span>],

  <span class="hljs-comment">// Use 'postCreateCommand' to run commands after the container is created.</span>

  <span class="hljs-attr">"postCreateCommand"</span>: <span class="hljs-string">"pip install -r requirements.txt"</span>,

  <span class="hljs-attr">"postAttachCommand"</span>: <span class="hljs-string">".devcontainer/addcodespacename.sh &amp;&amp; python main.py"</span>,

 <span class="hljs-comment">// Configure tool-specific properties.</span>

  <span class="hljs-attr">"customizations"</span>: {

        <span class="hljs-attr">"codespaces"</span>: {

            <span class="hljs-attr">"openFiles"</span>: [

                <span class="hljs-string">".well-known/ai-plugin.json"</span>,

                <span class="hljs-string">"openapi.yaml"</span>

            ]

        }

    }

}

  <span class="hljs-comment">// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.</span>

  <span class="hljs-comment">// "remoteUser": "root"</span>

}
</code></pre>
<h3 id="heading-nextjstypescript">Next.js/TypeScript</h3>
<pre><code class="lang-json"><span class="hljs-comment">// For format details, see https://aka.ms/devcontainer.json. For config options, see the</span>
<span class="hljs-comment">// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node</span>
{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Node.js &amp; TypeScript"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/typescript-node:0-18"</span>,
    <span class="hljs-attr">"waitFor"</span>: <span class="hljs-string">"onCreateCommand"</span>,
    <span class="hljs-attr">"updateContentCommand"</span>: <span class="hljs-string">"pnpm install"</span>,
    <span class="hljs-attr">"postAttachCommand"</span>: <span class="hljs-string">"pnpm dev"</span>,
    <span class="hljs-attr">"customizations"</span>: {
        <span class="hljs-attr">"vscode"</span>: {
            <span class="hljs-attr">"extensions"</span>: [
                <span class="hljs-string">"streetsidesoftware.code-spell-checker"</span>,
                <span class="hljs-string">"dbaeumer.vscode-eslint"</span>,
                <span class="hljs-string">"esbenp.prettier-vscode"</span>,
                <span class="hljs-string">"DavidAnson.vscode-markdownlint"</span>,
                <span class="hljs-string">"ms-vscode-remote.remote-containers"</span>
            ]
        }
    },
    <span class="hljs-attr">"portsAttributes"</span>: {
        <span class="hljs-attr">"3000"</span>: {
            <span class="hljs-attr">"label"</span>: <span class="hljs-string">"Application"</span>,
            <span class="hljs-attr">"onAutoForward"</span>: <span class="hljs-string">"openPreview"</span>
        }
    },
    <span class="hljs-attr">"forwardPorts"</span>: [<span class="hljs-number">3000</span>]
}
</code></pre>
<h2 id="heading-this-is-only-a-start">This is only a start</h2>
<p>Containers help you standardize environments and use less of your local machine's resources. This lowers the barriers for folks with:</p>
<ul>
<li><p>Low computing power</p>
</li>
<li><p>Low access to coding education</p>
</li>
<li><p>A tough onboarding process</p>
</li>
</ul>
<p>Looking forward, I hope that we can invest more time and effort into the following technological advancements:</p>
<ul>
<li><p>Bridging the digital divide by improving internet access for folks in more underdeveloped countries or rural areas</p>
</li>
<li><p>Introduce coding to underrepresented folks at an early stage</p>
</li>
<li><p>Prioritize accessibility for developers with visible and non-visible disabilities</p>
</li>
</ul>
<p><em>I’ll leave you with these thoughts: rather than ignoring the value of DEI, how can our industry build upon already existing technologies to drive impactful change for DEI? And what issues do you hope our industry addresses in the near future?</em></p>
]]></content:encoded></item><item><title><![CDATA[How I'm using GitHub Copilot to learn p5.js]]></title><description><![CDATA[Introduction
Because I’m an avid advocate for GitHub Copilot and other forms of AI-assisted programming, people often ask me the same questions: “Does GitHub Copilot stunt learning? Will it limit my ability to learn code? Will I become overly reliant...]]></description><link>https://blackgirlbytes.dev/how-im-using-github-copilot-to-learn-p5js</link><guid isPermaLink="true">https://blackgirlbytes.dev/how-im-using-github-copilot-to-learn-p5js</guid><category><![CDATA[GitHub]]></category><category><![CDATA[github copilot]]></category><category><![CDATA[AI]]></category><category><![CDATA[learning]]></category><category><![CDATA[Programming Tips]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Mon, 10 Jul 2023 04:58:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1688964533649/ec37aef7-c2ab-4640-9cc9-9152302794e2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>Because I’m an avid advocate for GitHub Copilot and other forms of AI-assisted programming, people often ask me the same questions: “Does GitHub Copilot stunt learning? Will it limit my ability to learn code? Will I become overly reliant on it?” Concerns about stunted learning, limited coding abilities, and over reliance are valid. However, based on my experience, intentional use of GitHub Copilot has actually sharpened my coding skills. I’m an experienced JavaScript developer who used GitHub Copilot to gain proficiency in reading, writing, and debugging Python. While I successfully combined my existing coding expertise with GitHub Copilot's code generation abilities, I am not great at verbally explaining how I used it as a learning tool. In conversations with developer friends and even in a recent conference talk, I felt I could not deliver convincing evidence that this works for me and can work for others, too! My inability to express my thoughts makes me feel like I’m mindlessly advocating for a company’s product just because I work there. I want to demonstrate its value as a learning tool rather than a crutch to empower developers. Generative AI is here to stay and evolve whether we like it or not. We can either cower in fear or learn to leverage it for the well-being of society.</p>
<p>In this blog post, I aim to articulate this methodology effectively. Writing helps me organize my thoughts, so I'm sharing my insights with the hope of benefiting others. While the primary reason I write is for myself, I also believe that using my company's tools and sharing best practices is part of effective Developer Advocacy. By understanding how GitHub Copilot can be responsibly used as a learning tool, readers can explore more use cases for AI-assisted programming. Throughout this post, I will illustrate how to use GitHub Copilot to learn a programming language or framework, with a focus on my current experience with p5.js.</p>
<h2 id="heading-what-is-p5js-and-why-am-i-learning-it">What is p5.js and why am I learning it?</h2>
<p>P5.js is an open source JavaScript library for creative coding, with a focus on making coding accessible and inclusive.</p>
<p>I opted to learn p5.js as a means to rekindle my dormant creative side. Ever since I learned how to code, I stopped tapping into my creative side. I’ve learned that the purpose of creative coding is to make something expressive instead of something functional, and I need that in my life.I aspire to create purely expressive works, unburdened by the need to cater to a broad audience or meet functional demands. It's liberating to code free from concerns such as fixing bugs for a company's financial impact or facing potential criticism on blog posts about the usefulness of my demos.</p>
<h2 id="heading-what-is-github-copilot">What is GitHub Copilot?</h2>
<p>It's an AI pair programmer that draws context from comments and code and suggests individual lines and whole functions instantly!</p>
<p><strong>Here are some past posts I've written about GitHub Copilot if you want to learn more:</strong></p>
<ul>
<li><p><a target="_blank" href="https://dev.to/github/how-to-send-a-tweet-with-github-copilot-4ih7">How to send a tweet with GitHub Copilot</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/github/a-beginners-guide-to-prompt-engineering-with-github-copilot-3ibp">A beginner’s guide to prompt engineering with GitHub Copilot</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/github/could-github-copilot-be-a-valuable-investment-for-my-team-4l9h">Could GitHub Copilot be a valuable investment for my team?</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2023-06-20-how-to-write-better-prompts-for-github-copilot/">How to use GitHub Copilot: prompts, tips, and use cases</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2023-05-12-how-i-used-github-copilot-to-build-a-browser-extension/">How I used GitHub Copilot to build a browser extension</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2022-09-14-8-things-you-didnt-know-you-could-do-with-github-copilot/">8 things you didn’t know you could do with GitHub Copilot</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/github/how-to-build-a-markdown-editor-in-two-minutes-with-github-copilot-khb">How to build a markdown editor in two minutes (with GitHub Copilot)</a></p>
</li>
</ul>
<p><strong>Here are some other informative posts about GitHub Copilot I didn't write:</strong></p>
<ul>
<li><p><a target="_blank" href="https://github.blog/2023-05-17-inside-github-working-with-the-llms-behind-github-copilot/">Inside GitHub: Working with the LLMs behind GitHub Copilot</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2023-06-27-the-economic-impact-of-the-ai-powered-developer-lifecycle-and-lessons-from-github-copilot/">The economic impact of the AI-powered developer lifecycle and lessons from GitHub Copilot</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2023-06-27-the-economic-impact-of-the-ai-powered-developer-lifecycle-and-lessons-from-github-copilot/">Survey reveals AI’s impact on the developer experience</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2023-02-22-responsible-ai-pair-programming-with-github-copilot/">Responsible AI pair programming with GitHub Copilot</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2023-05-05-web-summit-rio-2023-building-an-app-in-18-minutes-with-github-copilot-x/">Web Summit Rio 2023: Building an app in 18 minutes with GitHub Copilot X</a></p>
</li>
</ul>
<h2 id="heading-how-i-learn-programming-concepts">How I learn programming concepts</h2>
<p>Before we get into how we use GitHub Copilot to learn, I want to debunk some misconceptions about learning programming concepts. From my experience, developers tend to have a shared conventional way that people should learn to code that may make them rebuttal the way that GitHub Copilot helps you to learn. Everyone learns differently. Some people learn by doing, while some people learn through observation. However, I think there’s a difference between how we think we learn a programming language versus the reality of how we actually learn a programming language. Below are a few examples:</p>
<h3 id="heading-expectation-learning-to-code-is-straightforward">Expectation - Learning to code is straightforward</h3>
<p>When I look back at my coding education, I remember the experience in a straightforward manner that looked something like:</p>
<ol>
<li><p>I listened to an instructor (college, bootcamp, or online video) introduce a concept</p>
</li>
<li><p>I watched the instructor demonstrate the concept</p>
</li>
<li><p>I applied what I learned from the class in my homework</p>
</li>
</ol>
<h3 id="heading-reality-software-engineering-is-a-non-linear-career-path-that-involves-various-steps">Reality - Software engineering is a non-linear career path that involves various steps</h3>
<p>The reality is coding is a continuous, non-linear journey. The “curse of knowledge” or “knowledge bias” often leads us to forget what learning code was really like. The curse of knowledge refers to the cognitive bias where individuals who possess knowledge or expertise in a particular subject find it difficult to remember or accurately assess the difficulty and challenges faced by novices or learners who are still acquiring that knowledge.</p>
<p>When I started teaching beginners to code, I sometimes felt frustrated. <em>Why aren’t they quickly understanding the box model? I showed them a fun, but comprehensive illustration. They should get it.</em></p>
<p>Then, I realized how confusing learning the CSS Box Model was for me when I first learned to code. I remembered that there are senior engineers who still confuse padding with margin. And I remembered that I continue to struggle with other concepts every single day. (I still get confused with the <code>useEffect</code> hook and the <code>Promise.all()</code> method).</p>
<p>In practice, learning to code involves troubleshooting, reading documentation, copying code snippets, browsing Stack Overflow, and grappling with the frustration of code not working as expected during assignments. This aspect of the learning journey is often overlooked but is a common experience when mastering a new programming language or framework. Even today, when working with new technologies, I encounter similar frustrations.</p>
<h3 id="heading-expectation-to-get-better-at-writing-code-write-more-code">Expectation - To get better at writing code, write more code.</h3>
<p>Some of the most common advice for novice and experienced developers looking to improve their coding skills or to learn a new programming concept is to write more code</p>
<h3 id="heading-reality-improve-your-coding-skills-by-reading-code">Reality - Improve your coding skills by reading code</h3>
<p>Writing more code helps, but reading code is even better. My friend Ramón Huidobro introduced me to this book called The Programmer's Brain.</p>
<p>“What Every Programmer Needs to Know about Cognition" by Felienne Hermans. While Felienne acknowledges that writing code is important, she also emphasizes that our field doesn’t place enough importance or instruction on reading code. She believes in personalizing the learning process so that you can comprehend the code and improve your short-term, working, and long-term memory to become a better programmer. Watch <a target="_blank" href="https://www.infoq.com/presentations/reading-code/">one</a> of Felienne’s presentations to learn more!</p>
<p>I believe that while you may not always understand snippets of code, it’s helpful to read code, so that you can recognize the notation and feel less overwhelmed by it over time.</p>
<h3 id="heading-expectation-you-have-to-understand-why-you-write-every-single-line-of-code">Expectation - You have to understand why you write every single line of code</h3>
<p>While I believe that code comprehension is key, I think there will always be times when we don’t understand code and that comprehension can grow over time. One of the biggest frustrations I had when I worked as a software engineer was that my coworkers wanted me to understand every single line of code that I wrote.</p>
<p><strong><em>Them:</em></strong> <em>Why did you write that?</em> <strong><em>Me:</em></strong> <em>I’m not sure. It’s something I saw online. I thought it was an interesting approach, but I don’t fully understand it.</em> <strong><em>Them:</em></strong> <em>Don’t just copy things you see online.</em></p>
<p>You might agree with my past coworkers, and what they’re saying holds some truth, but read the next paragraph to understand why I don’t fully agree with this mindset.</p>
<h3 id="heading-reality-copying-code-and-procedures-supports-ritualistic-learning">Reality - Copying code and procedures supports ritualistic learning</h3>
<p>I’ve found that many engineers like the idea of knowing the why before the how. I, on the other hand, learn best from learning how to do something then after that I learn WHY I am doing something. It clicks better in my brain this way. Like I mentioned earlier, everyone learns differently.</p>
<p>Here’s an example: for 3 months straight from January 2018 to March 2018, I knew how to push code to GitHub, but I didn’t understand what any of the commands meant._ Why was I writing them? I had no clue. _I just knew I needed to type them in the terminal to get my code on GitHub. However, when I encountered problems, such as being unable to push due to lack of repository access or facing a merge conflict, I would Google the issues and gain more context about the solutions and how each command worked. After a few months, I learned the meaning of these commands and I knew how to navigate problems that came up around those commands. The approach didn’t inhibit my learning in any way because now I work at today’s most popular web-based hosting service for Git repositories.</p>
<p>This is not a made up way of learning. This approach is called ritualistic learning. It involves following a set of instructions or steps without necessarily comprehending the underlying principles or reasons behind them. Over time, as you gain more experience and exposure to the subject matter, your understanding gradually develops.</p>
<h2 id="heading-how-github-copilot-helps-me-learn">How GitHub Copilot helps me learn</h2>
<p>For the sake of clarity (and me wanting to feel fancy), I’ll name the framework for using GitHub Copilot to learn a new programming concept: <strong>AI-Driven Learning</strong>. It incorporates 5 steps including:</p>
<ul>
<li><p>Conceptual Pseudocoding</p>
</li>
<li><p>Syntax Familiarization</p>
</li>
<li><p>Iteration</p>
</li>
<li><p>AI Rubber Ducking</p>
</li>
<li><p>Self-Directed Application</p>
</li>
</ul>
<p>Let’s dive into each of the steps to understand what they mean and how to apply them!</p>
<h3 id="heading-conceptual-pseudocoding">Conceptual Pseudocoding</h3>
<p>I discovered the importance of conceptual pseudocoding while planning my segment for the GitHub Universe Keynote in 2022. Collaborating with <a target="_blank" href="https://twitter.com/LostInTangent">Jonathan Carter</a>, the Technical Advisor to the CEO, we aimed to create a fun and visual demonstration of GitHub Copilot that could fit within the allotted 5-minute timeframe.</p>
<p>During our Slack brainstorming session, I had an epiphany! <em>Why not showcase GitHub Copilot's capabilities by creating an image with p5.js? Jonathan liked the idea, and we were all set. There was just one tiny hitch – I had never written anything in p5.js before. Why did I suggest it in the first place? But then, a glimmer of hope emerged. Maybe I could grasp it quickly? How hard could it be? Perhaps less than an hour of learning would suffice. And now that I’m looking at code samples of p5.js, I’m not sure why there are so many numbers. Is this math?</em></p>
<p>After a few attempts of exchanging screenshots and screen recordings with Jonathan, we developed a plan to provide a comment at the top of the file, providing GitHub Copilot with the context of what we wanted GitHub Copilot to build. It said:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* 
Draw a  draw a green house, 
with a blue roof, 
a red door,
 and two windows 
*/</span>
</code></pre>
<p>This helped me to break down the different elements of my p5.js creation.</p>
<p>And just like <em>magic</em>, GitHub Copilot followed all the instructions.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d0a5rt2ifx7zamkjcqez.png" alt="Green house with blue roof red door and two windwos" /></p>
<p>This process helped GitHub Copilot understand our desired outcome and helped me, the programmer, gain clarity on what I wanted to achieve. Although pseudocoding is often emphasized in college, coding bootcamps, and interviews, it tends to be overlooked once we enter the industry. By writing comments that prompt and provide context to GitHub Copilot, developers can consider the application's functionality and structure thoughtfully.</p>
<p>To illustrate this further, let's create our own example by installing <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=osteele.p5-server">p5.js</a> and <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=GitHub.copilot">GitHub Copilot</a> and writing a high-level prompt to draw an ice-cream cone:</p>
<pre><code class="lang-javascript">
<span class="hljs-comment">/* draw a light brown ice cream cone with

- a scoop of light pink ice cream

- a red cherry on top

*/</span>
</code></pre>
<h3 id="heading-syntax-familiarization">Syntax Familiarization</h3>
<p>After you write a comment or some code, GitHub Copilot may suggest code. We call this ghost text. You can accept the ghost text by pressing tab. While many developers acknowledge that tabbing through your code boosts your productivity, they’re concerned that not typing code will reduce their memory for syntax, especially for beginners.</p>
<p>Intentionality plays a key role here. Although you're not actively typing the code, allowing GitHub Copilot to generate it provides exposure to the syntax and typical file structure of the language. At this stage, complete understanding of the code is not necessary, but continual exposure helps prevent it from appearing unfamiliar. This exposure primes your brain to break down the code more effectively, aiding comprehension.</p>
<p><strong>I’ll draw a parallel between understanding complex words and understanding code through syntax familiarization to best illustrate my point.</strong></p>
<p><em>I’m not afraid of big or unfamiliar words. Perhaps, reading them aloud is not my strong suit, but my brain is able to process the meaning of the words pretty quickly, and that’s because I learned Latin in middle school. I can infer that a word like, “soporific” means to make you sleepy. The prefix first half of the word “sopor” is Latin for “deep sleep”. The second half of the word “fic” is Latin for “to make.” Readers of this blog post might even be able to infer this even if they’re not familiar with Latin. They may recognize the word “fic” from the word “fiction”, which also implies that you’re making or inventing something from your mind.</em></p>
<p>Just as my previous knowledge of Latin helps me decipher complex words based on prefixes and suffixes, familiarity with code syntax enables you to infer meaning and context. Syntax familiarization offers additional benefits by exposing developers to various programming concepts that can be applied across languages. While specific syntax may differ, underlying principles remain consistent. This exposure broadens developers' mindsets, encourages exploration of diverse approaches and solutions, and facilitates knowledge transfer.</p>
<p>Take a look at this GIF where GitHub Copilot generated code to draw an ice cream cone:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/op8k36v3tr9af4r4ahut.gif" alt="GIF where GitHub Copilot attempts to generate an ice cream cone with an ice cream scoop except the ice cream cone is facing the wrong direction" /></p>
<p>While GitHub Copilot didn’t generate a perfect ice cream cone, I learned a couple of things about the syntax and the structure of the file:</p>
<ul>
<li><p>P5.js file start with a set up function</p>
</li>
<li><p>The set up function uses a method called createCanvas, which I can infer initializes the canvas for our creation</p>
</li>
<li><p>P5.js files also use a function called draw and this is where all the elements of our drawing will live</p>
</li>
<li><p>I can determine the background color by using the method background and passing in RGB color codes</p>
</li>
<li><p>I can create shapes like triangles, ellipses, and arcs by specifying the name of the shape and passing in numbers. Although, at the moment, I’m not exactly sure what the numbers do. I assume that they determine the size and position of the shapes.</p>
</li>
<li><p>I can color the shapes using the method fill and passing in RGB color codes</p>
</li>
</ul>
<p>By intentionally engaging with syntax familiarization, developers can leverage their prior knowledge, make inferences, and establish meaningful connections between different programming concepts.</p>
<h3 id="heading-iteration">Iteration</h3>
<p>During conversations with my developer friends, the issue of GitHub Copilot generating flawed code often arises. They argue that this can mislead beginners and teach them poor programming practices. I won’t lie. Mindlessly trusting incorrect code generative code CAN mislead beginners. However, I believe that encountering imperfect code is an integral part of the learning process, regardless of whether GitHub Copilot is involved. When exploring a new programming language, especially at the beginning of my career, I often resort to copying code from StackOverflow, skimming through documentation, and pasting code snippets haphazardly. Sometimes, the code I copy doesn't even work, but it still provides a starting point and helps me grasp the problem at hand. With time, I learn better practices and approaches, gradually refining my skills.</p>
<p>The same principle applies to GitHub Copilot. In the example above, GitHub Copilot attempted to generate an ice cream cone with a light pink scoop and a cherry on top. However, the generated triangle for the cone had the pointy part facing upwards, whereas cones typically have the pointy part facing downwards. While it could be argued that GitHub Copilot misled me, I wouldn't have known how to create a triangle without its guidance. This presents an opportunity for me to debug and iterate on the generated code, enabling me to learn and develop a deeper understanding.</p>
<p>Though I may not fully comprehend the numerical notation used, I can modify the values to achieve the desired result.</p>
<p>Check out the GIF below to see how I adjusted the values to flip the triangle in the desired direction:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m4eoh28vcb9u4xarm9k8.gif" alt="GIF where I edit the coordinates of the triangle until it’s transformed from an upward pointing triangle to a downward pointing triangle" /></p>
<p>When GitHub Copilot offers code suggestions that contain minor errors or imperfections, it allows learners to adopt a hands-on approach. By attempting to execute the suggested code, identifying and resolving encountered issues, and subsequently refining the code to correct errors, learners gain practical experience in writing and editing within the given framework.</p>
<h3 id="heading-ai-rubber-ducking">AI Rubber Ducking</h3>
<p>With trial and error, I achieved the desired result, but I still don’t truly understand the numerical notation or why it worked. I can now see that the numbers for each triangle represent vertices, but I don’t know the formula. In this situation, I would love to have a conversation with someone more knowledgeable than me to get a better understanding, but I don’t want to bother anyone. Or maybe I can Google, but the search engine results don’t always have the answers for my specific use-case.</p>
<p>Fortunately, I have the option to engage in a conversation with my AI pair programmer using a tool called Copilot Chat. At GitHub, we have a suite of Copilot tools called Copilot X. These tools are made to help developers beyond their editor because we recognize developers do more than just code. One of the products within Copilot X is called Copilot Chat. Copilot Chat is an IDE extension that provides a ChatGPT-esque experience. It offers an IDE extension that provides a ChatGPT-esque experience, leveraging the context of your open files within the editor. From my experience, highlighting the relevant lines of code enhances Copilot Chat’s performance. Copilot Chat can generate code, unit tests, explanations, and more. Learn more about Copilot Chat’s latest and greatest updates for June 2023 <a target="_blank" href="https://code.visualstudio.com/updates/v1_80#_github-copilot">here</a>. Try out Copilot Chat’s slash commands to maximize its benefits! \</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a6xagz6b6xz6qwnohus7.png" alt="Slash commands in Copilot Chat" /></p>
<p>For our particular scenario, I’ll use Copilot Chat to help me better understand the generated p5.js code. I’ll ask clarifying questions like:</p>
<p><strong>Can you explain this line of code to me?</strong> <code>triangle(100, 200, 300, 200, 200, 400);</code></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lw8f3odi4w2npmnres2y.gif" alt="GIF of Copilot Chat explaining the triangle function to me" /></p>
<p><strong>So is the method structured this way</strong> <code>triangle(x1, y1, x2, y2, x3, y3)</code>?</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8jmcdzwy7jailrjsy6jh.gif" alt="GIF of Copilot Chat confirming the order of arguments and vertices" /></p>
<p><strong>How big is the canvas? How do I know where each coordinate is?</strong></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rbx91g3mex8k426acur2.gif" alt="GitHub Copilot explaining the canvas size" /></p>
<p>From communicating with Copilot Chat, I’ve learned a few p5.js fundamentals:</p>
<ul>
<li><p>The createCanvas(400, 400) method for defining the width and height of the canvas</p>
</li>
<li><p>The utilization of the Cartesian coordinate system in the canvas</p>
</li>
<li><p>The order of vertices for the triangle function: x1, y1, x2, y2, and x3, y3</p>
</li>
<li><p>The arc function's notation: arc(centerX, centerY, width, height, startAngle, stopAngle)</p>
</li>
<li><p>The syntax for creating ellipses: ellipse(centerX, centerY, width, height)</p>
</li>
</ul>
<p>If you want to create this modify drawing, here’s the code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/* draw a light brown ice cream cone with

- a scoop of light pink ice cream

- a red cherry on top

*/</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{
  createCanvas(<span class="hljs-number">400</span>, <span class="hljs-number">400</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// light blue background</span>

    background(<span class="hljs-number">200</span>, <span class="hljs-number">220</span>, <span class="hljs-number">255</span>);

    <span class="hljs-comment">// light brown ice cream cone</span>

    fill(<span class="hljs-number">255</span>, <span class="hljs-number">200</span>, <span class="hljs-number">100</span>);

    triangle(<span class="hljs-number">100</span>, <span class="hljs-number">200</span>, <span class="hljs-number">300</span>, <span class="hljs-number">200</span>, <span class="hljs-number">200</span>, <span class="hljs-number">400</span>);

    <span class="hljs-comment">// light pink ice cream half-circle</span>

    fill(<span class="hljs-number">255</span>, <span class="hljs-number">200</span>, <span class="hljs-number">200</span>);

    arc(<span class="hljs-number">200</span>, <span class="hljs-number">200</span>, <span class="hljs-number">200</span>, <span class="hljs-number">200</span>, PI, TWO_PI);

    <span class="hljs-comment">// red cherry</span>

    fill(<span class="hljs-number">255</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);

    ellipse(<span class="hljs-number">200</span>, <span class="hljs-number">100</span>, <span class="hljs-number">30</span>, <span class="hljs-number">30</span>);
}
</code></pre>
<p>With my newfound knowledge, I’m ready to challenge myself to create more!</p>
<h3 id="heading-self-directed-application">Self-Directed Application</h3>
<p>Now that I know how to draw shapes and control the position of shapes, especially triangles, I am ready to take on a more challenging task: drawing my parents' national flag. The Guyanese flag prominently features triangles of different sizes and colors.</p>
<p><strong>Here’s my attempt at drawing a Guyanese flag</strong></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y80mlsdo2u3h7z0bn1q5.png" alt="Drawing of the Guyanese flag" /></p>
<p>Here’s the code for the flag:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// draw a Guyanese flag</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{
    createCanvas(<span class="hljs-number">700</span>, <span class="hljs-number">400</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// background is green</span>
    background(<span class="hljs-number">0</span>, <span class="hljs-number">153</span>, <span class="hljs-number">0</span>);
    stroke(<span class="hljs-number">0</span>);
    strokeWeight(<span class="hljs-number">2</span>);
    flag();
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">flag</span>(<span class="hljs-params"></span>) </span>{
    yellowTriangle();
    redTriangle();
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">yellowTriangle</span>(<span class="hljs-params"></span>) </span>{
   <span class="hljs-comment">// yellow triangle and white outline</span>
   stroke(<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>);
   strokeWeight(<span class="hljs-number">4</span>);
   fill(<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0</span>);
   triangle(<span class="hljs-number">0</span>, <span class="hljs-number">400</span>, <span class="hljs-number">0</span>, <span class="hljs-number">5</span>, <span class="hljs-number">715</span>, <span class="hljs-number">200</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">redTriangle</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// red triangle and black outline</span>
    stroke(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);
    strokeWeight(<span class="hljs-number">7</span>);
    fill(<span class="hljs-number">255</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);
    triangle(<span class="hljs-number">0</span>, <span class="hljs-number">400</span>, <span class="hljs-number">0</span>, <span class="hljs-number">5</span>, <span class="hljs-number">350</span>, <span class="hljs-number">200</span>);
}
</code></pre>
<p>I continued to apply my knowledge of shape manipulation to build a snowman with a top hat, a carrot nose, and a few buttons.GitHub Copilot and Copilot Chat came in handy as I explored animation and user interaction. This allowed me to add a background with randomly generated green squares, and now users can draw random brown lines by dragging their mouse across the canvas.</p>
<p><strong>Check out my snowman below!</strong></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kqnz0veh6ts2kdjn42ps.gif" alt="GIF of a snowman with a background that has green generative squares" /></p>
<p>Here’s the code to leverage for your own modification purposes:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// draw a snowman</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{
    createCanvas(<span class="hljs-number">400</span>, <span class="hljs-number">400</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// background is dark blue</span>

    <span class="hljs-comment">// background(0, 0, 102);</span>

    stroke(<span class="hljs-number">0</span>);

    strokeWeight(<span class="hljs-number">2</span>);

    snowman();
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">snowman</span>(<span class="hljs-params"></span>) </span>{
    changeBackground();

    <span class="hljs-comment">// call all functions</span>

    body();

    eyes();

    nose();

    buttons();

    hat();

    arms();
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">body</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// snowman body</span>
    fill(<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>);
    ellipse(<span class="hljs-number">200</span>, <span class="hljs-number">300</span>, <span class="hljs-number">150</span>, <span class="hljs-number">150</span>);
    ellipse(<span class="hljs-number">200</span>, <span class="hljs-number">200</span>, <span class="hljs-number">100</span>, <span class="hljs-number">100</span>);
    ellipse(<span class="hljs-number">200</span>, <span class="hljs-number">120</span>, <span class="hljs-number">75</span>, <span class="hljs-number">75</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">eyes</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// snowman eyes</span>
    fill(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);
    ellipse(<span class="hljs-number">185</span>, <span class="hljs-number">110</span>, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>);
    ellipse(<span class="hljs-number">215</span>, <span class="hljs-number">110</span>, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">nose</span>(<span class="hljs-params"></span>)</span>{
    <span class="hljs-comment">// snowman nose</span>
    fill(<span class="hljs-number">255</span>, <span class="hljs-number">102</span>, <span class="hljs-number">0</span>);
    triangle(<span class="hljs-number">200</span>, <span class="hljs-number">120</span>, <span class="hljs-number">200</span>, <span class="hljs-number">130</span>, <span class="hljs-number">220</span>, <span class="hljs-number">125</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">buttons</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// snowman buttons</span>
    fill(<span class="hljs-number">250</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);
    ellipse(<span class="hljs-number">200</span>, <span class="hljs-number">180</span>, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>);
    ellipse(<span class="hljs-number">200</span>, <span class="hljs-number">200</span>, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>);
    ellipse(<span class="hljs-number">200</span>, <span class="hljs-number">220</span>, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">hat</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// snowman hat</span>
    fill(<span class="hljs-number">250</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>);
    rect(<span class="hljs-number">150</span>, <span class="hljs-number">65</span>, <span class="hljs-number">100</span>, <span class="hljs-number">20</span>);
    rect(<span class="hljs-number">170</span>, <span class="hljs-number">33</span>, <span class="hljs-number">60</span>, <span class="hljs-number">30</span>);
}

<span class="hljs-comment">// create snowman arms</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">arms</span>(<span class="hljs-params"></span>) </span>{
    stroke(<span class="hljs-number">102</span>, <span class="hljs-number">51</span>, <span class="hljs-number">0</span>);
    strokeWeight(<span class="hljs-number">5</span>);
    line(<span class="hljs-number">150</span>, <span class="hljs-number">200</span>, <span class="hljs-number">100</span>, <span class="hljs-number">150</span>);
    line(<span class="hljs-number">250</span>, <span class="hljs-number">200</span>, <span class="hljs-number">300</span>, <span class="hljs-number">150</span>);

}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">changeBackground</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// make the background be random green squares</span>
    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">var</span> i = <span class="hljs-number">0</span>; i &amp;lt; <span class="hljs-number">100</span>; i++) {
        fill(<span class="hljs-number">0</span>, <span class="hljs-number">255</span>, <span class="hljs-number">0</span>);
        rect(random(<span class="hljs-number">400</span>), random(<span class="hljs-number">400</span>), random(<span class="hljs-number">50</span>), random(<span class="hljs-number">50</span>));
        frameRate(<span class="hljs-number">2</span>);
    }
  }

  <span class="hljs-comment">// draw with mouse</span>

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">mouseDragged</span>(<span class="hljs-params"></span>) </span>{
    fill(<span class="hljs-number">0</span>);
    ellipse(mouseX, mouseY, <span class="hljs-number">10</span>, <span class="hljs-number">10</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
</code></pre>
<p>Building on my understanding of shape manipulation and animation, I embarked on creating a 3D drawing without a specific plan or goal in mind. I let the generative nature of p5.js guide me, focusing on developing elements in 3D, adding shadows, and incorporating lighting effects.</p>
<p><strong>Here’s my 3D creation. It’s giving space!</strong></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/blackgirlbytes/status/1670723278946680832?s=20">https://twitter.com/blackgirlbytes/status/1670723278946680832?s=20</a></div>
<p> </p>
<p>Check out the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// create a 3d sphere with WEBGL and p5.js</span>

<span class="hljs-keyword">let</span> angleX = <span class="hljs-number">0</span>;

<span class="hljs-keyword">let</span> angleY = <span class="hljs-number">0</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setup</span>(<span class="hljs-params"></span>) </span>{
    createCanvas(<span class="hljs-number">400</span>, <span class="hljs-number">400</span>, WEBGL);
}

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">draw</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-comment">// background is dark blue</span>
    background(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">102</span>);
    <span class="hljs-comment">// set up lighting</span>
    ambientLight(<span class="hljs-number">60</span>, <span class="hljs-number">60</span>, <span class="hljs-number">60</span>);
    pointLight(<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">80</span>, <span class="hljs-number">-100</span>, <span class="hljs-number">100</span>);
    <span class="hljs-comment">// set up material properties</span>
    specularMaterial(<span class="hljs-number">250</span>);
    shininess(<span class="hljs-number">20</span>);
    rotateX(angleX);
    rotateY(angleY);
    <span class="hljs-comment">// draw 3D sphere</span>
    noStroke();
    fill(<span class="hljs-number">255</span>, <span class="hljs-number">204</span>, <span class="hljs-number">0</span>);
    sphere(<span class="hljs-number">100</span>);
    <span class="hljs-comment">// draw 3D torus</span>
    noFill();
    stroke(<span class="hljs-number">255</span>, <span class="hljs-number">204</span>, <span class="hljs-number">0</span>);
    torus(<span class="hljs-number">200</span>, <span class="hljs-number">200</span>);
    angleX += <span class="hljs-number">0.01</span>;
    angleY += <span class="hljs-number">0.02</span>;
}
</code></pre>
<p>As a culmination of the previous steps, I am now able to apply the acquired knowledge and concepts independently while coding. Through repeated engagement with pseudocoding, syntax familiarization, iteration, and AI rubber ducking, I have developed an intuitive understanding of foundational knowledge in p5.js.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Whether you're a novice developer or an experienced professional, the journey of learning and mastering programming is a constant process of growth. It's important to recognize that learning is rarely a linear path and often involves various cognitive methods that are often overlooked. From copying and pasting code snippets to exploring new concepts, these approaches play a significant role in our development as programmers. By intentionally embracing AI tools like GitHub Copilot and other AI pair programming tools, we can enhance our learning experience and leverage the power of generative AI.</p>
<p>To recap, the AI-Driven Learning involves:</p>
<ul>
<li><p>conceptual pseudocoding,</p>
</li>
<li><p>syntax familiarization,</p>
</li>
<li><p>iteration,</p>
</li>
<li><p>AI rubber ducking,</p>
</li>
<li><p>and self-directed application.</p>
</li>
</ul>
<p>Try out GitHub Coplot, try out my approach, and share your thoughts about shaping the future of programming and redefining how we think about learning and programming.</p>
]]></content:encoded></item><item><title><![CDATA[How to build a markdown editor in two minutes]]></title><description><![CDATA[Is it possible to build a markdown editor in 2 minutes? It is for me (if I'm using GitHub Copilot). In fact, I proposed building a markdown editor with GitHub Copilot for a 15-minute demo, and my manager seemed a bit nervous that my idea was overly a...]]></description><link>https://blackgirlbytes.dev/how-to-build-a-markdown-editor-in-two-minutes</link><guid isPermaLink="true">https://blackgirlbytes.dev/how-to-build-a-markdown-editor-in-two-minutes</guid><category><![CDATA[github copilot]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[generative ai]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Sat, 17 Jun 2023 19:04:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1687028455890/7a025176-31d8-4ab0-8677-135e2cd6df58.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Is it possible to build a markdown editor in 2 minutes? It is for me (if I'm using GitHub Copilot). In fact, I proposed building a markdown editor with GitHub Copilot for a 15-minute demo, and my manager seemed a bit nervous that my idea was overly ambitious. However, he still entrusted me with the task. To my surprise, GitHub Copilot generated a markdown editor faster than I predicted. <strong>In this blog post, I’ll teach you how to build a markdown editor, too!</strong></p>
<p><em>But before I do that, I want to manage readers' expectations.</em></p>
<ul>
<li><p>The markdown editor we’re building will be more functional than stylistic. Translation: it might look a little ugly.</p>
</li>
<li><p>We use a prepackaged React component to render markdown called React Markdown.</p>
</li>
<li><p>As a bonus, we’ll use Copilot Chat to improve the markdown editor’s user interface. However, this product is in technical preview and not yet available to everyone. If you don’t have access to it yet, you can substitute it for ChatGPT.</p>
</li>
<li><p>You’ll need access to GitHub Copilot in your editor to get the best out of this tutorial!</p>
</li>
<li><p>GitHub Copilot and other Generative AI tools are non-deterministic. This means these tools will sometimes generate different outputs. You may receive slightly different output, but feel free to experiment with GitHub Copilot until you reach your desired outcome. Feel free to share what it created for you!</p>
</li>
<li><p>GitHub Copilot and other generative AI tools are advancing quickly. The advice in this tutorial is relevant for today – June 2023, but it might be outdated in the near future.</p>
</li>
</ul>
<h2 id="heading-use-github-copilot-to-build-a-markdown-editor">Use GitHub Copilot to build a markdown editor</h2>
<h3 id="heading-prerequisites">Prerequisites:</h3>
<ul>
<li><p>Create a <a target="_blank" href="https://github.com/signup">GitHub account</a> (if you don’t have one)</p>
</li>
<li><p>Sign up for <a target="_blank" href="https://github.com/features/copilot#pricing">GitHub Copilot</a></p>
</li>
<li><p>Install the <a target="_blank" href="https://docs.github.com/en/copilot/getting-started-with-github-copilot">GitHub Copilot extension</a> in an editor of your choice</p>
</li>
</ul>
<p>Now that we have everything we need let’s get started!</p>
<h3 id="heading-step-1-create-a-nextjs-github-codespace-template-30-seconds">Step 1: Create a Next.js GitHub Codespace template (30 seconds)</h3>
<p>I use <a target="_blank" href="https://github.com/codespaces/templates">GitHub Codespace templates</a> when I want to avoid installing boilerplate package dependencies and setting up my environment from scratch. It comes in handy when I want to spin up a quick proof of concept or deliver a demo. In our case, we want to save time installing Next.js and its accompanying dependencies.</p>
<p>You can create a Next.js GitHub Codespace template by navigating to <a target="_blank" href="https://github.com/codespaces/templates">https://github.com/codespaces/templates</a>. Then choosing the “Use this template” button for Next.js. This will trigger a codespace to open with boilerplate Next.js code with a browser preview.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f1n8aprmi8qohgg268uk.png" alt="Highlights the use this template button for Nextjs" /></p>
<h3 id="heading-step-2-install-specific-dependencies-30-seconds">Step 2: Install specific dependencies (30 seconds)</h3>
<p>Using a GitHub Codespace template reduced the need to install a few boilerplate dependencies, but we still have more to install.</p>
<ul>
<li><p>Ensure the GitHub Copilot extension is installed. See <a target="_blank" href="https://docs.github.com/en/copilot/getting-started-with-github-copilot">here</a> for instructions.</p>
</li>
<li><p>Install the React Markdown npm package. To do this, run the following command in your codespace’s terminal: <code>npm install react-markdown</code></p>
</li>
<li><p>Install the styled-components npm package. To do this, by run the following command in your codespace's terminal: <code>npm install styled-components@latest</code></p>
</li>
</ul>
<h3 id="heading-step-3-delete-the-code-in-your-indexjs-file-2-seconds">Step 3: Delete the code in your <code>index.js</code> file (2 seconds)</h3>
<p>Every GitHub Codespace template includes boilerplate code to empower developers in experimenting and swiftly prototyping their ideas. However, for our goals, we will write different code in our <code>index.js</code> file; we don't need the existing code.</p>
<p>Keep the index.js file, but delete the code inside.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sdpc2dvryylqjh29khbh.gif" alt="Deleting code" /></p>
<h3 id="heading-step-4-prompt-github-copilot-with-a-comment-4-seconds">Step 4: Prompt GitHub Copilot with a comment (4 seconds)</h3>
<p>The comment below prompts GitHub Copilot to explain our overall goal and provide context to our AI programming assistant. Learn more about this method from my previous DEV post – A <a target="_blank" href="https://dev.to/github/a-beginners-guide-to-prompt-engineering-with-github-copilot-3ibp">Beginner’s Guide to Prompt Engineering with GitHub Copilot</a>. Copy the comment below and paste it at the top of your <code>index.js</code> file.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/*
Create a basic markdown editor in Next.js with the following features:
- Use React hooks
- Create state for markdown with the default text "## markdown preview"
- A text area where users can write markdown 
- Show a live preview of the markdown text as I type
- Support for basic markdown syntax like headers, bold, italics 
- Use React markdown npm package 
- The markdown text and resulting HTML should be saved in the component's state and updated in real time 
*/</span>
</code></pre>
<h3 id="heading-step-5-trigger-suggestions-from-github-copilot-18-seconds">Step 5: Trigger suggestions from GitHub Copilot (18 seconds)</h3>
<p>I pressed the <code>RETURN</code> key twice to trigger a suggestion from GitHub Copilot. I usually press the <code>SPACEBAR</code>, <code>ENTER</code>, or <code>RETURN</code> on my keyboard to trigger suggestions from GitHub Copilot after providing context.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/slmyfg9amruedl8twsfx.gif" alt="receiving and accepting ghost text suggestions" /></p>
<p>💡 When you create a new line, you should see a suggestion, or <strong>ghost text</strong>, from GitHub Copilot.</p>
<p>💡 You can tell that GitHub Copilot will provide you with a suggestion when the Copilot icon in the status bar is spinning. I like to refer to it as "thinking". In the GIF below, I highlighted the Copilot icon, so you can see how it spins when processing.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jr12rgdkafv4i7b2hmsk.gif" alt="Copilot thinking" /></p>
<p>💡 You can tell that GitHub Copilot is going to provide you with a suggestion when the Copilot icon in the status bar is spinning. I like to refer to it as “thinking”. In the GIF below, I highlighted the Copilot icon, so you can see how it spins when it is processing.</p>
<p>💡 Because the output for GitHub Copilot is non-deterministic, results may vary.</p>
<p>📝 Here's the GitHub Copilot gave me output:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactMarkdown <span class="hljs-keyword">from</span> <span class="hljs-string">'react-markdown'</span>;
<span class="hljs-keyword">import</span> styled <span class="hljs-keyword">from</span> <span class="hljs-string">'styled-components'</span>;

<span class="hljs-keyword">const</span> Index = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [markdown, setMarkdown] = useState(<span class="hljs-string">'## markdown preview'</span>);

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    setMarkdown(e.target.value);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{markdown}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">ReactMarkdown</span>&gt;</span>{markdown}<span class="hljs-tag">&lt;/<span class="hljs-name">ReactMarkdown</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Index;
</code></pre>
<p>✨ Feel free to tweak the output to your liking!</p>
<h3 id="heading-step-6-save-the-file-and-try-it-out-30-seconds">Step 6: Save the file and try it out! (30 seconds)</h3>
<p>GitHub Copilot generated code that looks correct, but how do we know it works? Let's try writing in our markdown editor's input box to see if it renders an accurate live preview of the text.</p>
<p>I'll test the following markdown elements:</p>
<p><strong>Bullet points</strong></p>
<pre><code class="lang-plaintext">- bullet
- bullet
- this is the markdown for bullets
- ...
</code></pre>
<p><strong>Bold</strong></p>
<pre><code class="lang-plaintext">I am **bold**
How to make a word **bold**: 
- sandwiched it between two asterisks on the left 
- and two asterisks on the right
</code></pre>
<p><strong><em>Italic</em></strong></p>
<pre><code class="lang-plaintext">I am *italic*
How to make a word *italic*: 
- sandwiched it between one asterisk on the left 
- and one asterisk on the right
</code></pre>
<p><strong>Link</strong></p>
<pre><code class="lang-plaintext">I am [link](google.com)
How to convert a word into a [link](google.com): 
- sandwiched it between an opening and closing bracket 
- then place an actual link next to it
- sandwich that link between two parentheses
</code></pre>
<p><strong>Heading</strong></p>
<pre><code class="lang-plaintext">I am  ###### heading
How to convert a word into a ##### heading: 
- Preface the word with hashtags 
- The more hashtags, the smaller the word gets
- More hashtags indicate the heading is less important
- # Heading 1 - I am super important.
- ## Heading 2 - I am a subtitle
- ### Heading 3 - I am less important
- #### Heading 4 - I am even smaller and less important
</code></pre>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l084jfhhpj5fr0abkj52.gif" alt="Rendering markdown elements" /></p>
<p>💪🏾 We did it! We developed a markdown editor with GitHub Copilot in less than 2 minutes.</p>
<p><img src="https://media.giphy.com/media/ae6m4ljnl69urJ539F/giphy.gif" alt="We did it Joe with Kamala Harris" /></p>
<h2 id="heading-bonus-use-copilot-chat-to-style-test-and-explain-your-ui">Bonus: Use Copilot Chat to style, test, and explain your UI</h2>
<p>That was fun, but we can do more. We can write unit tests, style our UI, and get an explanation of the code. We can do independently, but it's exponentially more fun to do pair program with GitHub Copilot for this.</p>
<p>To complete the second half of this tutorial, you will need access to <a target="_blank" href="https://github.com/github-copilot/chat_waitlist_signup/join">Copilot Chat</a>. Additionally, you need an active subscription to <a target="_blank" href="https://github.com/features/copilot">GitHub Copilot</a> to access Copilot Chat. Learn more <a target="_blank" href="https://github.com/features/preview/copilot-x">here</a>.</p>
<p><strong>Copilot Chat</strong> is a ChatGPT-like experience in your editor, but it’s not just a chat window. Because it’s deeply embedded into your IDE, Copilot Chat has context of what a developer types and what error messages a developer receives.</p>
<p>Let’s try using Copilot Chat to style, test, and explain the code in our markdown editor!</p>
<p>I feel comfortable with this framework, so I confidently accepted the previously generated code. However, you might be unfamiliar with React or Next.js, so the generated code looks foreign to you. This is a problem because you don’t want to blindly accept code. Understanding code that you will merge into a production environment is vital. Fortunately, Copilot Chat can provide an in-depth explanation of your code.</p>
<h3 id="heading-step-1-open-the-extension">Step 1: Open the extension!</h3>
<p>Following installation, try opening the extension. It should render a panel with a welcome message.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n3x9aebjth1sy6x54b6t.png" alt="Welcome message in Copilot Chat" /></p>
<h3 id="heading-step-2-get-an-explanation-of-the-generated-code-block">Step 2: Get an explanation of the generated code block</h3>
<p>Let’s have Copilot Chat explain the <code>handleChange</code> function.</p>
<ul>
<li><p>First, highlight the code block for the <code>handleChange</code> function</p>
</li>
<li><p>Right click after highlighting</p>
</li>
<li><p>Choose “Copilot”</p>
</li>
<li><p>Choose “Explain This”</p>
</li>
</ul>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6ldwjt1qi9300egekt1t.gif" alt="Shows the generated explanation" /></p>
<p>After you follow the above steps, Copilot Chat should provide an explanation similar to the one below!</p>
<blockquote>
<p>This code defines a function called handleChange that takes an event object as its argument. The handleChange function is typically used as an event handler for a textarea element in a React component. When the user types into the textarea, the handleChange function is called with an event object that contains information about the user's input. The handleChange function uses the setMarkdown function to update the value of a state variable called markdown. The setMarkdown function is a function that is returned by the useState hook provided by the React library. The useState hook is used to add state to functional components in React. By using the setMarkdown function to update the markdown state variable, the component that contains this code can re-render itself to reflect the new state. Overall, this code defines a function called handleChange that is used to update the value of a state variable called markdown in response to user input. The setMarkdown function is used to update the state variable, and the useState hook is used to add state to a functional component in React.</p>
</blockquote>
<p>💡 You can repeat this step with any individual line of code or code block if you need more clarity.</p>
<p>💡 The more lines of code that you highlight, the less granular the explanation will be. If you want an overview, highlight the entire file, but if you want a granular explanation, highlight individual code blocks.</p>
<h3 id="heading-step-3-style-your-markdown-editor">Step 3: Style your markdown editor</h3>
<p>Let's communicate with Copilot Chat to guide us in styling our markdown editor.</p>
<p>✍🏿 Here’s the question that I asked Copilot Chat: “Can you propose code to make my markdown editor have a more modern UX design? Please use styled-components.”</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r7difoix6aiqse3c87d4.gif" alt="Asking Copilot Chat a question" /></p>
<h3 id="heading-step-4-review-copilot-chats-response">Step 4: Review Copilot Chat’s response</h3>
<p>I want to re-emphasize that generative AI and GitHub Copilot have non-deterministic output, so results may vary. Copilot Chat proposed code that handles:</p>
<ul>
<li><p>importing the styled-components npm package</p>
</li>
<li><p>styling the markdown editor's container</p>
</li>
<li><p>styling the text input</p>
</li>
<li><p>styling the markdown preview</p>
</li>
</ul>
<p>See the generated code below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> ReactMarkdown <span class="hljs-keyword">from</span> <span class="hljs-string">'react-markdown'</span>;
<span class="hljs-keyword">import</span> styled <span class="hljs-keyword">from</span> <span class="hljs-string">'styled-components'</span>;

<span class="hljs-keyword">const</span> Container = styled.div<span class="hljs-string">`
  display: flex;
  flex-direction: column;
  height: 100vh;
  width: 100vw;
  align-items: center;
  justify-content: center;
  background-color: #f5f5f5;
`</span>;

<span class="hljs-keyword">const</span> TextArea = styled.textarea<span class="hljs-string">`
  width: 50%;
  height: 50%;
  padding: 1rem;
  border-radius: 5px;
  border: none;
  box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
  font-size: 1rem;
  resize: none;
`</span>;

<span class="hljs-keyword">const</span> Preview = styled(ReactMarkdown)<span class="hljs-string">`
  width: 50%;
  height: 50%;
  padding: 1rem;
  border-radius: 5px;
  border: none;
  box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1);
  font-size: 1rem;
  overflow-y: scroll;
  background-color: white;
`</span>;

<span class="hljs-keyword">const</span> Index = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [markdown, setMarkdown] = useState(<span class="hljs-string">'## markdown preview'</span>);

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function"><span class="hljs-params">e</span> =&gt;</span> {
    setMarkdown(e.target.value);
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Container</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">TextArea</span> <span class="hljs-attr">value</span>=<span class="hljs-string">{markdown}</span> <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span> /&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Preview</span>&gt;</span>{markdown}<span class="hljs-tag">&lt;/<span class="hljs-name">Preview</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Container</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Index;
</code></pre>
<p>I reviewed the code, and it looked like a feasible solution to me, so I copied the generated code and pasted it into my <code>index.js</code> file.</p>
<h3 id="heading-step-5-check-out-the-results">Step 5: Check out the results</h3>
<p>Here’s what my final results looked like:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kl3mkqkt55g8p3qrhta7.png" alt="styled markdown editor" /></p>
<p>I guess this is Copilot’s version of a modern UX design, and it looks a bit better to me, but it could use some improvement. This is a great opportunity for you as the developer to tweak the code to match your vision!</p>
<h3 id="heading-step-6-keep-experimenting">Step 6: Keep experimenting</h3>
<p>I spent over 20 minutes experimenting with Copilot Chat to improve my prompt game and understand Copilot’s limitations. I asked it different questions like:</p>
<ul>
<li><p>How do I add a toolbar?</p>
</li>
<li><p>How do I add a dark mode and light mode theme?</p>
</li>
</ul>
<p>Here’s what it came up with:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sc3wupf3vn35kzy1na24.png" alt="A markdown editor with a toolbar and dark mode" /></p>
<p>🧑🏾‍🎨 Get creative and make your markdown editor your own!</p>
<h3 id="heading-step-7-write-unit-tests-with-copilot-chat">Step 7: Write unit tests with Copilot Chat</h3>
<p>While writing unit tests is critical for any production application's longevity, it's also a really tedious process. I'm happy that the industry is moving towards the direction of automating away boilerplate code and repetitive code.</p>
<p>We can request that Copilot Chat generate unit tests for our markdown editor using slash commands.</p>
<p>After I typed "/tests" in Copilot Chat, I received proposed unit tests accompanied by a brief explanation. See the results below:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { render, fireEvent } <span class="hljs-keyword">from</span> <span class="hljs-string">'@testing-library/react'</span>;
<span class="hljs-keyword">import</span> Index <span class="hljs-keyword">from</span> <span class="hljs-string">'./index'</span>;

describe(<span class="hljs-string">'Index'</span>, <span class="hljs-function">() =&gt;</span> {
  it(<span class="hljs-string">'renders the bold, italic, and theme toggle buttons'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { getByText } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Index</span> /&gt;</span></span>);
    expect(getByText(<span class="hljs-string">'Bold'</span>)).toBeInTheDocument();
    expect(getByText(<span class="hljs-string">'Italic'</span>)).toBeInTheDocument();
    expect(getByText(<span class="hljs-string">'Dark Mode'</span>)).toBeInTheDocument();
  });

  it(<span class="hljs-string">'toggles between dark and light mode when the theme toggle button is clicked'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { getByText, container } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Index</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> themeToggle = getByText(<span class="hljs-string">'Dark Mode'</span>);
    expect(container.firstChild).toHaveStyle(<span class="hljs-string">'background-color: #fff'</span>);
    fireEvent.click(themeToggle);
    expect(container.firstChild).toHaveStyle(<span class="hljs-string">'background-color: #000'</span>);
    fireEvent.click(themeToggle);
    expect(container.firstChild).toHaveStyle(<span class="hljs-string">'background-color: #fff'</span>);
  });

  it(<span class="hljs-string">'updates the markdown text when the textarea is changed'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { getByLabelText, getByText } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Index</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> textarea = getByLabelText(<span class="hljs-string">'Markdown Input'</span>);
    fireEvent.change(textarea, { <span class="hljs-attr">target</span>: { <span class="hljs-attr">value</span>: <span class="hljs-string">'# Hello World!'</span> } });
    expect(getByText(<span class="hljs-string">'# Hello World!'</span>)).toBeInTheDocument();
  });

  it(<span class="hljs-string">'applies bold formatting to selected text when the bold button is clicked'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { getByText, getByLabelText } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Index</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> textarea = getByLabelText(<span class="hljs-string">'Markdown Input'</span>);
    fireEvent.change(textarea, { <span class="hljs-attr">target</span>: { <span class="hljs-attr">value</span>: <span class="hljs-string">'Hello **World**!'</span> } });
    <span class="hljs-keyword">const</span> boldButton = getByText(<span class="hljs-string">'Bold'</span>);
    fireEvent.click(boldButton);
    expect(textarea.value).toBe(<span class="hljs-string">'Hello **World**!'</span>);
    fireEvent.change(textarea, { <span class="hljs-attr">target</span>: { <span class="hljs-attr">value</span>: <span class="hljs-string">'Hello **World!**'</span> } });
    fireEvent.click(boldButton);
    expect(textarea.value).toBe(<span class="hljs-string">'Hello World!'</span>);
  });

  it(<span class="hljs-string">'applies italic formatting to selected text when the italic button is clicked'</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> { getByText, getByLabelText } = render(<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Index</span> /&gt;</span></span>);
    <span class="hljs-keyword">const</span> textarea = getByLabelText(<span class="hljs-string">'Markdown Input'</span>);
    fireEvent.change(textarea, { <span class="hljs-attr">target</span>: { <span class="hljs-attr">value</span>: <span class="hljs-string">'Hello *World*!'</span> } });
    <span class="hljs-keyword">const</span> italicButton = getByText(<span class="hljs-string">'Italic'</span>);
    fireEvent.click(italicButton);
    expect(textarea.value).toBe(<span class="hljs-string">'Hello *World*!'</span>);
    fireEvent.change(textarea, { <span class="hljs-attr">target</span>: { <span class="hljs-attr">value</span>: <span class="hljs-string">'Hello *World!*'</span> } });
    fireEvent.click(italicButton);
    expect(textarea.value).toBe(<span class="hljs-string">'Hello World!'</span>);
  });
});
</code></pre>
<blockquote>
<p>These tests cover the basic functionality of the component, including rendering the correct buttons, toggling between dark and light mode, updating the markdown text, and applying bold and italic formatting to selected text. Note that these tests assume that the TextArea and Preview components are working correctly, so you may want to write additional tests for those components as well.</p>
</blockquote>
<p>Please note: I didn't try out the unit tests, so use at your own expense. I strongly recommend running the tests and reviewing the code before merging into a branch.</p>
<p>💾 ...And we're done! Experimenting with GitHub Copilot and Copilot Chat is always fun for me. For more content like this follow <a target="_blank" href="dev.to/blackgirlbytes">me</a> or <a target="_blank" href="dev.to/github">GitHub</a> on DEV!</p>
<p>👀 Also, I'd love to hear your thoughts in the comments below.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/shorts/EiXvNA75g7I">https://www.youtube.com/shorts/EiXvNA75g7I</a></div>
]]></content:encoded></item><item><title><![CDATA[The Ultimate Guide to Writing Technical Blog Posts]]></title><description><![CDATA[Really long introduction about how I started writing tech blog posts
Technical skill and content creation are equally important for your software development or (software development adjacent) career. Technical skills such as coding help you to perfo...]]></description><link>https://blackgirlbytes.dev/the-ultimate-guide-to-writing-technical-blog-posts</link><guid isPermaLink="true">https://blackgirlbytes.dev/the-ultimate-guide-to-writing-technical-blog-posts</guid><category><![CDATA[Blogging]]></category><category><![CDATA[Technical writing ]]></category><category><![CDATA[Career]]></category><category><![CDATA[learning]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Wed, 07 Jun 2023 01:03:42 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1686099596972/6016d9c3-ca0f-4203-ba51-e897e0a741c6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-really-long-introduction-about-how-i-started-writing-tech-blog-posts">Really long introduction about how I started writing tech blog posts</h2>
<p>Technical skill and content creation are equally important for your software development or (software development adjacent) career. Technical skills such as coding help you to perform the job at a base level, but content creation can solidify you as a leader in the industry. I acknowledge that not everyone has the privilege of creating content alongside completing their daily job duties and personal responsibilities, but it is a worthy investment. Creating technical content can make it easier to land jobs, get promoted, and influence the direction of our industry because it enables hiring managers and other tech leaders to take a peek into your brain and your thought process. More importantly, it helps you absorb and solidify concepts that you’ve learned. You can be the smartest, most skilled software developer in the world, but if no one knows who you are, then your opportunities may be limited. Content creation helps you advocate for yourself. It might seem cringe, but you can put yourself out there in a non-cringey authentic way. Folks like Kelsey Hightower established and advanced their careers by sharing their thoughts in an authentic and thoughtful way.</p>
<p>My favorite form of technical content creation is blogging. Thanks to my mom, I developed a passion for reading and writing at an early age, so writing has always been my preferred method of self-expression. I had an endless supply of picture books, cassette-tape audio books, novels, poetry, and half-filled notebooks documenting my childhood experiences. When there was no heat in my house, my mom would bring my siblings and me to the library, so the library became my second home. <em>Disclaimer:</em> I’m not a perfect writer; it’s just something I enjoy doing.</p>
<p>Unfortunately, I abandoned writing in early adulthood because I learned that it’s hard to make money as a writer, and I had one goal in mind: make LOADS of money. I grew up poor, and I was determined to improve my quality of life, so I focused all my energy on a career that makes money: software development.</p>
<p>Years later, I started my third full-time software development job, and my manager Andy Cunningham encouraged me to write what I learned on the job. As part of my sprint, I’d fix a bug or implement a new feature, and then I would write about it. One of my first technical blog posts was about how I used GitHub Actions to sync our repository with our AWS S3 Buckets. Months later, I landed my current role as a Developer Advocate, and part of my role is to blog.</p>
<p>While I was excited to combine my childhood skill (writing) with the skill I learned in adulthood (coding), I was also intimidated. Writing about technology didn’t seem as easy as writing a poem or an essay. With poetry, I had all creative authority, and with essays, teachers gave us guidelines. But, what was a technical blog post supposed to look like? I worried and struggled with the following concepts:</p>
<ul>
<li><p>Will people read it or even care to read it?</p>
</li>
<li><p>Will people think I’m wrong or stupid?</p>
</li>
<li><p>Do I have anything valuable to say?</p>
</li>
<li><p>Is my blog post too short?</p>
</li>
<li><p>Is my blog post too long and overwhelming?</p>
</li>
<li><p>I want to tell the audience everything, but when should I stop the blog post?</p>
</li>
</ul>
<p>I didn’t have any structure or strategy for writing my blog posts. After a year of writing technical blog posts and learning from great content creators like Kurt Kemple, I’ve developed a strategy that I’m comfortable with. In this blog post, I’ll share my strategy in hopes of empowering you.</p>
<h3 id="heading-address-your-fears">Address your fears</h3>
<p>A common reason that technologists don’t write is because they’re scared.</p>
<p><strong>If you’re scared that you don’t have anything new or different to write about…</strong> Remind yourself that you don’t have to write about anything revolutionary or inventive, write what you know. While someone may have already written about a similar topic, they won’t explain it the same way you will. And the way you explain and describe information will reach a particular audience that learns and consumes information the same way you do.</p>
<p><strong>If you’re scared that your writing skills aren’t up to par…</strong> Remind yourself that this is your platform to practice. You will improve over time, and sometimes blog posts don’t need to have flowery vocabulary and complex sentences. Sometimes, the simpler a blog is written, the easier it is for the audience to consume.</p>
<p><strong>If you’re scared that you don’t know enough…</strong> Perhaps, you only know HTML, but you know more than someone who doesn’t know HTML. You will continue to grow and learn over time. You don’t need to wait until you get to a certain point because as technologists, we’re always learning. There will always be something that we don’t know.</p>
<p><strong>If you’re scared of making mistakes…</strong> Embrace your mistakes; they help you grow. I make mistakes all the time. Sometimes, I have grammatical errors in my blog posts or even technical errors, and someone corrects me. I learn from those mistakes and I’ve become a better writer, educator, and engineer as a result. Don’t aim to make mistakes, but when you do, know that everyone makes mistakes and it’s part of our journey to greatness.</p>
<p><strong>If you’re scared that you don’t have time…</strong> This is totally fair as we all have varying responsibilities and limited time. However, it is a worthy investment to reflect on what you’ve learned and share your knowledge with the world. If possible, work with your manager to carve out regularly scheduled time to write, and your blog posts don’t have to be long. They can be as short or as long as you want. You have creative authority over your content.</p>
<p><strong>If you’re scared of criticism…</strong> Remind yourself that you are writing for you. You are writing, so that you can look back and reflect on your growth. You are writing, so that you won’t have to repeatedly Google or ask your coworkers for help on the same questions. The harmful opinions of others don’t matter. You can always delete their comments or respectfully respond and continue to live life. I’ve found that people like to critique others when they feel threatened.</p>
<h3 id="heading-keep-a-list-of-things-youve-learned">Keep a list of things you’ve learned</h3>
<p>As you write code at your job, complete side projects, or contribute to open source projects, keep a running list of things you’ve learned.</p>
<p>I keep a list in my Notes app on my Mac computer and iPhone. It looks like this</p>
<pre><code class="lang-markdown"><span class="hljs-section">### Idea list</span>
Hack.Diversity

<span class="hljs-bullet">-</span> How to negotiate salary
<span class="hljs-bullet">-</span> Write thank you letters after interviews
<span class="hljs-bullet">-</span> How to pass the technical interview
<span class="hljs-bullet">-</span> How to learn / navigate a new codebase quickly 
<span class="hljs-bullet">-</span> Tips for passing the CompTIA+ test
<span class="hljs-bullet">-</span> Code
<span class="hljs-bullet">-</span> Invite Automation
<span class="hljs-bullet">-</span> Teaching to Empower: Supporting Early Career Devs
<span class="hljs-bullet">-</span> Generate Social Cards with JavaScript
<span class="hljs-bullet">-</span> From Code to Cloud — Git Emoji
<span class="hljs-bullet">-</span> Build a Blockchain Simulation with JavaScript
<span class="hljs-bullet">-</span> Make better pull requests
<span class="hljs-bullet">-</span> Fuzzy Search Made Easy
<span class="hljs-bullet">-</span> Overcoming the Fear of Contributing to Open Source
<span class="hljs-bullet">-</span> How to Convince Your Boss to Open Source a Project
<span class="hljs-bullet">-</span> Create the Perfect ReadME for your Open Source Project 
Small things I learned with code

<span class="hljs-bullet">-</span> Linked issues
<span class="hljs-bullet">-</span> Fusejs
<span class="hljs-bullet">-</span> How to make a pull request template
<span class="hljs-bullet">-</span> .github/.github/PULL<span class="hljs-emphasis">_REQUEST_</span>TEMPLATE.md
<span class="hljs-bullet">-</span> https://github.com/open-sauced/.github/blob/main/.github/PULL<span class="hljs-emphasis">_REQUEST_</span>TEMPLATE.md
<span class="hljs-bullet">-</span> .github
<span class="hljs-bullet">-</span> Issue templates
<span class="hljs-bullet">-</span> Forms yaml 
<span class="hljs-bullet">-</span> Being autonomous
<span class="hljs-bullet">-</span> Turning a Checkbox into a circle
<span class="hljs-bullet">-</span> Handling routing with netlify
<span class="hljs-bullet">-</span> Dependencies vs devDependencies
<span class="hljs-bullet">-</span> React functions run on load or after
<span class="hljs-bullet">-</span> Dealing with broken images in React 
<span class="hljs-bullet">-</span> SEQA 
<span class="hljs-bullet">-</span> Rendering components
<span class="hljs-bullet">-</span> Using classList
<span class="hljs-bullet">-</span> Invite automation
<span class="hljs-bullet">-</span> Automatically generate a social image card
<span class="hljs-bullet">-</span> Pull request template forms
GitHub ideas

<span class="hljs-bullet">-</span> Prompt engineering tips with GitHub Copilot
<span class="hljs-bullet">-</span> Lowering barriers with GitHub Codespaces
<span class="hljs-bullet">-</span> Automatically install extensions with GitHub Codespaces
<span class="hljs-bullet">-</span> Automatically install npm dependencies with GitHub Codespaces
<span class="hljs-bullet">-</span> Automatically run your node app with GitHub Codespaces
<span class="hljs-bullet">-</span> GitHub Actions extension
<span class="hljs-bullet">-</span> Using GitHub Pages to federate your Mastodon identity 
<span class="hljs-bullet">-</span> Building a to do list user interface with GitHub Copilot 
<span class="hljs-bullet">-</span> Sending a toot with GitHub Copilot
<span class="hljs-bullet">-</span> P5.js with GitHub Copilot
<span class="hljs-bullet">-</span> I made a GitHub action with my voice
<span class="hljs-bullet">-</span> I used AI to build AI
<span class="hljs-bullet">-</span> How does GitHub Copilot help businesses
</code></pre>
<p>As you can see, my ideas range from simple concepts like "Converting a checkbox into a circle with CSS" to more advanced and creative concepts (like "Building a GitHub Action with my voice"). Some of the ideas are also repeated. Whenever I get an idea or one of my managers mentions that I should cover a topic, I write it down. Keeping a list of ideas is helpful, so that when you want to write, you’re not also wasting energy and time, brainstorming topics.</p>
<h3 id="heading-choose-the-topic-you-feel-most-excited-about">Choose the topic you feel most excited about</h3>
<p>It’s worth noting that I haven’t written about many of the topics listed above. I only write about what I’m most passionate about at the moment or most needed at my job (because this is my job). If it’s one of the ideas on the list, then I will write about it. However, if I have a random spark of inspiration, I will act on the idea immediately. On the other hand, I may also have to write about a topic requested by my coworkers, and I’ll focus on that. I choose the most urgent or the most exciting topic because that helps motivate me.</p>
<p>Also, consider granularity in your topics. If you want to write about a general topic, such as React, it would be difficult to write about every single concept of React. It would take a book or documentation to cover the entire framework. Instead, I suggest creating a general overview of React or picking a very subtopic such as, “Understanding the useEffect Hook” or “How I used React to build a blog”</p>
<h3 id="heading-read-other-blog-posts-for-inspiration">Read other blog posts for inspiration</h3>
<p>Before writing anything, I always read. Reading inspires my:</p>
<ul>
<li><p>Storytelling</p>
</li>
<li><p>My writing style</p>
</li>
<li><p>My choice of words and sentence structure</p>
</li>
<li><p>My perspective</p>
</li>
<li><p>My writing technique</p>
</li>
</ul>
<p>By immersing myself in various texts, I can absorb different writing styles and techniques, allowing me to adapt and experiment with my own writing. Additionally, reading exposes me to diverse ideas and perspectives, broadening my understanding of the world and providing me with fresh insights to incorporate into my writing. It also helps me identify areas for improvement, such as refining my sentence structure or expanding my vocabulary. You don’t have to read a really long blog post or novel, but reading a quick paragraph is beneficial in refining my writing.</p>
<h3 id="heading-determine-your-audience">Determine your audience</h3>
<p>Now that you know what you want to write about, and you’re inspired to write, it’s time to determine who you are writing for.</p>
<p>As humans, we have a tendency to want to write for everyone. We want to teach and help everyone, and that’s not wrong, but I wouldn’t suggest doing this for a blog post. I often talk with people who have goals around content creation, and they want to target junior engineers, mid-level engineers, and senior engineers simultaneously. If you try to reach everybody, you might end up creating a really long blog post that no one wants to read or you might overwhelm yourself and never actually finish the blog post. Trust me; it’s happened to me before and other technical writers. Even if I do finish it, the blog post ends up having every low engagement and it looks messy.</p>
<p>If you choose a very specific audience, then the other audiences will still benefit. For example, I’ve written blog posts for beginners, but sometimes senior engineers let me know that they still learned something new from the blog post or that they appreciated the way I broke down fundamentals.</p>
<p>The person I usually pick to write for is me, specifically past me. Here are examples:</p>
<ul>
<li><p>I wrote the blog post “Overcoming the fear of Contributing to Open Source” to myself when I was in a coding bootcamp and didn’t really understand open source.</p>
</li>
<li><p>I wrote “How I used dev containers to enable GitHub Codespaces for ChatGPT” to myself as a GitHub Developer Advocate who was acting as “Customer Zero (well maybe customer 100)” on GitHub Codespaces.</p>
</li>
<li><p>I wrote “How to speak at conferences when you’re scared of public speaking” to me in high school who was scared of public speaking.</p>
</li>
<li><p>And I’m writing this blog post to myself before I ever wrote a technical blog post.</p>
</li>
</ul>
<p>I have also written to my future self. Like, I often create advice for open source maintainers, but I only started maintaining a project in 2023. The advice I wrote in 2021 and 2022 is helpful for present day me.</p>
<h3 id="heading-build-an-outline">Build an outline</h3>
<p>Now, it’s time to plan what you write. Building an outline helps to align your thoughts in a way that readers will understand. Feel free to tweak the outline templates below, but this is what I use to write my own blog posts</p>
<h4 id="heading-outline-for-how-to-blog-posts">Outline for “how-to” blog posts</h4>
<p>If I’m writing a blog post guiding people step-by-step on how to do accomplish a task, I will use an outline like the one below:</p>
<pre><code class="lang-markdown">
Intro
<span class="hljs-bullet">-</span> Hook
<span class="hljs-bullet">-</span> Problem statement/What this solves for myself or readers

Step-by-Step Guide
<span class="hljs-bullet">1.</span> Step 1
Optional: brief explanation of the step with supporting links for folks to learn more
<span class="hljs-bullet">2.</span> Step 2
Optional: brief explanation of the step with supporting links for folks to learn more    
<span class="hljs-bullet">3.</span> Step 3
...
N. Final Step

Conclusion
<span class="hljs-bullet">-</span> Recap of the process
<span class="hljs-bullet">-</span> Final thoughts or additional tips
<span class="hljs-bullet">-</span> Call to action (e.g., encourage readers to try the steps and share their results/feedback)
</code></pre>
<p>Check out an example that follows this outline: <a target="_blank" href="https://dev.to/github/how-to-send-a-tweet-with-github-copilot-4ih7">How to send a tweet with GitHub Copilot</a></p>
<h4 id="heading-outline-for-explainer-blog-posts">Outline for explainer blog posts</h4>
<p>I define an explainer blog post as a blog post that explains a topic, but it doesn’t necessarily walk people through accomplishing a task. The main purpose is for readers to get an introduction to a concept.</p>
<pre><code class="lang-markdown">Intro
<span class="hljs-bullet">-</span> Hook
<span class="hljs-bullet">-</span> Brief overview of the topic and why care

Body
<span class="hljs-bullet">1.</span> Key Concept 1
<span class="hljs-bullet">    -</span> Definition/explanation
<span class="hljs-bullet">    -</span> Examples 
<span class="hljs-bullet">    -</span> Importance or relevance
<span class="hljs-bullet">2.</span> Key Concept 2
<span class="hljs-bullet">    -</span> Definition/explanation
<span class="hljs-bullet">    -</span> Examples
<span class="hljs-bullet">    -</span> Importance or relevance
<span class="hljs-bullet">3.</span> Key Concept 3
<span class="hljs-bullet">    -</span> Definition/explanation
<span class="hljs-bullet">    -</span> Examples
<span class="hljs-bullet">    -</span> Importance or relevance
...
N. Final Key Concept
<span class="hljs-bullet">    -</span> Definition/explanation
<span class="hljs-bullet">    -</span> Examples
<span class="hljs-bullet">    -</span> Importance or relevance

Conclusion
<span class="hljs-bullet">-</span> Summary of the key concepts
<span class="hljs-bullet">-</span> Closing thoughts or implications
<span class="hljs-bullet">-</span> Call to action (e.g., encourage readers to explore further or ask questions)
</code></pre>
<p>Here’s an example of a blog post that follows this outline: <a target="_blank" href="https://dev.to/github/why-are-people-developing-inside-containers-38o6">Why are people developing in containers?</a></p>
<h4 id="heading-outline-for-thought-leadershipopinion-blog-posts">Outline for thought leadership/opinion blog posts</h4>
<p>These types of posts are posts where I just share my opinion on the direction that industry is going. Many times, I use it to create productive conversation and share my leadership skills.</p>
<pre><code class="lang-markdown">Intro
<span class="hljs-bullet">-</span> Hook
<span class="hljs-bullet">-</span> Brief introduction to the topic/opinion and why it matters to me

Body
<span class="hljs-bullet">1.</span> Supporting Point 1
<span class="hljs-bullet">    -</span> Explanation of the point
<span class="hljs-bullet">    -</span> Supporting evidence or examples
<span class="hljs-bullet">2.</span> Supporting Point 2
<span class="hljs-bullet">    -</span> Explanation of the point
<span class="hljs-bullet">    -</span> Supporting evidence or examples
<span class="hljs-bullet">3.</span> Supporting Point 3
<span class="hljs-bullet">    -</span> Explanation of the point
<span class="hljs-bullet">    -</span> Supporting evidence or examples
...
N. Final Supporting Point
<span class="hljs-bullet">    -</span> Explanation of the point
<span class="hljs-bullet">    -</span> Supporting evidence or examples

Counter arguments (optional)
<span class="hljs-bullet">-</span> Address potential counterarguments or opposing views

Conclusion
<span class="hljs-bullet">-</span> Reinforce the opinion and provide a call to action
</code></pre>
<p>Here’s an example of a blog post that follows this outline: <a target="_blank" href="https://dev.to/blackgirlbytes/the-hard-parts-of-developer-advocacy-for-me-530h">The Hard Parts of Developer Advocacy for me</a></p>
<h4 id="heading-outline-for-listicle-blog-posts">Outline for listicle blog posts</h4>
<p>These are posts that are often written in list format. The reason they’re written this way is to make the concept fun, quick and easy to consume for readers. These types of blog posts are often have titles to the ones below:</p>
<ul>
<li><p>Top Ten Tips for…</p>
</li>
<li><p>5 Must-Have…</p>
</li>
<li><p>7 Amazing…</p>
</li>
</ul>
<pre><code class="lang-markdown">Intro
<span class="hljs-bullet">-</span> Hook or intriguing statement related to the topic
<span class="hljs-bullet">-</span> Brief introduction to the theme or subject of the listicle

Listicle Items
<span class="hljs-bullet">1.</span> List Item 1
<span class="hljs-bullet">    -</span> Explanation 
<span class="hljs-bullet">    -</span> Example
<span class="hljs-bullet">2.</span> List Item 2
<span class="hljs-bullet">    -</span> Explanation 
<span class="hljs-bullet">    -</span> Example
<span class="hljs-bullet">3.</span> List Item 3
<span class="hljs-bullet">    -</span> Explanation
<span class="hljs-bullet">    -</span> Example
...
N. List Item N
<span class="hljs-bullet">    -</span> Explanation
<span class="hljs-bullet">    -</span> Example

Conclusion
<span class="hljs-bullet">-</span> Final thoughts or insights
<span class="hljs-bullet">-</span> Call to action (e.g., encourage readers to share their favorite item or suggest additions to the list)
</code></pre>
<p>Here’s an example of a blog post that follows this outline: <a target="_blank" href="https://github.blog/2022-09-14-8-things-you-didnt-know-you-could-do-with-github-copilot">8 things you didn’t know you could do with GitHub Copilot</a></p>
<h3 id="heading-take-a-shower">Take a shower</h3>
<p>This is an odd suggestion, but I do my best thinking in the shower. I think the sound of running water helps me to focus on my thoughts. In the shower, I can write a whole blog post in my mind. Besides taking a shower, you can try other activities that can stimulate your mind:</p>
<ul>
<li><p>Walking</p>
</li>
<li><p>Jogging</p>
</li>
<li><p>Listening to music</p>
</li>
<li><p>Meditating</p>
</li>
</ul>
<h3 id="heading-enter-a-flow-state-for-writing">Enter a flow state for writing</h3>
<p>Disable all distractions and start writing. I strongly recommend that you don’t edit as you write. I find that disruptive for my flow. I fill out each part of the outline that I created in whatever order that I prefer. I write the way I speak, and I just keep going. After I’ve written all my thoughts on paper, I will start editing.</p>
<p>My editing process consists of deleting irrelevant paragraphs, fixing spelling mistakes, and removing unnecessary punctuation marks. I’m a super light editor. I feel that if I edit it too much or spend too much time perfecting my blog posts, then I will never press publish. In the following paragraphs, I expand a bit more on my editing process. However, the way I look at it is, I want to get my thoughts out there. Once I do, someone will reach out to me – like my job and ask for a more refined version of my blog posts. Then, I could use resources my job provides me like professional editors to improve my blog posts. Also, I recognize that it doesn’t matter how much I edit; my blog post will always need more editing. It’s like code – there’s a bug somewhere. Sometimes, I just edit it after I publish. Often, people message me to say that I spelled a word wrong, and I usually update it afterwards.</p>
<p>It’s no big deal. Write for completion rather than perfection.</p>
<h3 id="heading-struggle-with-writing-record-your-voice">Struggle with writing? Record your voice</h3>
<p>There are some people who find writing difficult, and that’s okay. Brian Douglas told me about a tip that could help folks who struggle with putting words on a paper: speak. Record yourself speaking, upload the audio to your computer, and use a tool that can transcribe those words.</p>
<p>The tool I suggest is <a target="_blank" href="https://www.descript.com/">Descript</a>. It does a great job of transcribing audio. It may have a few mistakes here and there, so double check what it generates and make small edits.</p>
<h3 id="heading-read-it-aloud-or-use-a-text-to-speech-reader">Read it aloud (or use a Text-to-Speech reader)</h3>
<p>Reading my writing aloud enhances the quality of my content. When I read text I wrote in my head, I may notice particular issues, but reading aloud allows me to:</p>
<ul>
<li><p>Improve the clarity and flow</p>
</li>
<li><p>Enhance the tone and voice</p>
</li>
<li><p>Spot grammatical and stylistic errors</p>
</li>
<li><p>Evaluate the rhythm and cadence of my content</p>
</li>
<li><p>Assess the audience appeal</p>
</li>
<li><p>Sometimes, I'm too lazy to read my writing aloud or I’m struggling to focus, so I use a text-to-speech reader like, <a target="_blank" href="https://www.naturalreaders.com/">Natural Reader</a>.</p>
</li>
</ul>
<h3 id="heading-use-a-digital-writing-assistant">Use a digital writing assistant</h3>
<p>Digital writing assistants like <a target="_blank" href="https://www.grammarly.com/">Grammarly</a> find errors you might have missed. <a target="_blank" href="https://www.wordtune.com/">Word Tune</a> is another tool that I find helpful. It’s great because it takes my hard-to-understand sentences and converts them into clear, terse sentences. <a target="_blank" href="https://chat.openai.com/">ChatGPT</a> is another tool, but this one is a little more controversial. While I don’t encourage folks to use it to write whole articles, it does give great feedback. I’ll often prompt ChatGPT with the following:</p>
<ul>
<li><p>What did I do well in this blog post?</p>
</li>
<li><p>What didn’t I do well in this blog post?</p>
</li>
<li><p>Can you help me come up with a better title for this blog post?</p>
</li>
</ul>
<h3 id="heading-share-your-draft-with-stakeholders-to-gather-feedback">Share your draft with stakeholders to gather feedback</h3>
<p>I received this advice from Kurt Kemple: Share a draft of your blog post with people at work who asked you to write the blog post (product managers etc) AND someone from your target audience. When I follow this advice (because I'm lazy), I always get a high level of engagement and a quality final product. For example, I wrote this blog post called, “<a target="_blank" href="https://dev.to/github/how-do-i-resolve-merge-conflicts-5438">How do I resolve merge conflicts?</a>” I shared the draft with my friend Nathan, who recently graduated from a coding bootcamp. Nathan’s feedback helped me ensure that beginners could understand my blog post, too!</p>
<h3 id="heading-add-a-cover-image">Add a cover image</h3>
<p>In addition to well-written content, adding a cover image to your technical blog posts can significantly enhance their appeal and engagement. Don’t ignore this step. Including a cover image demonstrates your commitment to presenting your technical content in a professional and polished manner. It shows that you've put thought and effort into crafting a visually appealing and well-designed post, which can elevate your credibility as a writer and technical expert.</p>
<p>I’m not an artist nor am I great at design. I often use the following tools to help me create an image like:</p>
<ul>
<li><p>Canva</p>
</li>
<li><p>Figma</p>
</li>
</ul>
<p>I’ve also seen folks like <a target="_blank" href="https://www.linkedin.com/in/bekah-hawrot-weigel/">Bekah H.W.</a> and <a target="_blank" href="https://www.linkedin.com/in/brianldouglas/">Brian Douglas</a> use <a target="_blank" href="https://www.midjourney.com/">Midjourney</a> to create cover art. I believe my friend Mayank uses <a target="_blank" href="https://excalidraw.com/">Excalidraw</a> to create cover art.</p>
<p>Several of my covers images aren't that cute, but here are a few that I think look great:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vheilhhqo8x937tgg5xt.png" alt="Image description" /></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nfzoh0ow4gqc4g53jl27.png" alt="Image description" /></p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9d8z2v59hwefgduboesk.png" alt="Image description" /></p>
<h3 id="heading-publish">Publish</h3>
<p>Publish your blog post on the platform of your choice. You can use:</p>
<ul>
<li><p>DEV</p>
</li>
<li><p>Hashnode</p>
</li>
<li><p>Free Code Camp</p>
</li>
<li><p>Medium</p>
</li>
<li><p>Or your personal website</p>
</li>
</ul>
<p>You can make the decision on where you want to post based on your target audience and how you want to own your content. I sometimes use a platform called <a target="_blank" href="https://bloggu.io/">BloggU</a> to cross-post on multiple platforms.</p>
<h3 id="heading-share-it-on-social-media">Share it on social media</h3>
<p>Congratulations, you posted the blog, but you’re not done yet. Share your post with others helps the post gain more engagement. Sometimes, I receive messages from folks I’ve never met before that my blog post was helpful for them. Social media enables me to reach folks worldwide. I try to share my blog posts on:</p>
<ul>
<li><p>Twitter</p>
</li>
<li><p>Bluesky</p>
</li>
<li><p>Mastodon</p>
</li>
<li><p>LinkedIn</p>
</li>
<li><p>Discord</p>
</li>
<li><p>Sometimes I share posts with my coworkers on Slack (could be cringe, but no one is going to know that I created these things if I don’t tell them)</p>
</li>
</ul>
<p>I try not to announce things in a self-centered way. You can if you want to, but I want to show that my intentions are to share knowledge and grow rather than be at the center of attention. So I might add a small blurb that says something along the lines of: “Hey y’all! I used to struggle writing blog posts, but now I’ve gotten the hang of it, so I wrote a blog post to help others develop a good strategy, too. Check it out and let me know your thoughts.”</p>
<h2 id="heading-additional-resource">Additional Resource</h2>
<p><a target="_blank" href="https://theworst.dev/developer-advocates-guide-to-content-creation">The Developer Advocate’s Guide to Content Creation</a> by <a target="_blank" href="https://www.linkedin.com/in/theworstdev/">Kurt Kemple</a></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Writing technical blog content is not easy, but I’m hoping the above steps can help you to stay in the flow and create content that you’re proud of. Again, I want to emphasize that we’re not striving for perfection. This blog itself is far from perfect, but it accomplishes two things: If I ever forget my process or I’m feeling impostor syndrome, I can always re-read this post as a reminder It helps aspiring technical blog writers to level up their careers</p>
<h2 id="heading-call-to-action">Call to action</h2>
<p>I would love to hear about different writing strategies to improve your blog content or anything that I listed that’s been helpful to you. For more content like this, follow me!</p>
<p>Stay cool, friends 😎</p>
]]></content:encoded></item><item><title><![CDATA[How to set up a dev container for a Next.js/TypeScript app]]></title><description><![CDATA[It's the first day of your new software engineering job, and you're super excited to make your first pull request to the codebase, but before you can do that, you have to get your local environment up and running. This painstaking process can take yo...]]></description><link>https://blackgirlbytes.dev/how-to-set-up-a-dev-container-for-a-nextjstypescript-app</link><guid isPermaLink="true">https://blackgirlbytes.dev/how-to-set-up-a-dev-container-for-a-nextjstypescript-app</guid><category><![CDATA[GitHub]]></category><category><![CDATA[github-codespaces]]></category><category><![CDATA[Next.js]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[devcontainer]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Wed, 17 May 2023 14:32:22 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1684333873571/eefa46ff-d9e9-473f-9209-d05efe3b7bd6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It's the first day of your new software engineering job, and you're super excited to make your first pull request to the codebase, but before you can do that, you have to get your local environment up and running. This painstaking process can take you an entire day or week. You will need accounts with multiple cloud providers and access to environment variables, and you will spend considerable time editing outdated documentation. And now, you've lost the spark to contribute to the team.</p>
<p><strong><em>OR</em></strong></p>
<p>You're looking for an open source project to contribute to. You follow the documentation, but it's outdated and hard to follow, so you abandon your pursuit of contributing.</p>
<p><strong><em>OR</em></strong></p>
<p>You want to try out a new framework and understand how it works behind the scenes, but to do that, you have to <code>npm install</code> 5 million different things, and you're not <em>that</em> interested, so you decide to binge-watch HBO's Succession instead.</p>
<p>These are three very common experiences that happen to software engineers of all levels, whether new to a job or to an open source project. So, what's the solution?</p>
<p>The software engineering industry acknowledges that the time-to-first-pull-request or time-to-first-contribution can be time-consuming and cumbersome. As a result, the industry created many solutions in-browser sandbox solutions like CodeSandbox and Replit. For larger projects, cloud-based development environments like GitPod and GitHub Codespaces streamline onboarding and collaboration. One major hurdle in using tools like GitHub Codespaces or GitPod is the lack of knowledge on how to configure them to automatically run your projects, which is understandable since these concepts are still relatively new in the software engineering industry. Luckily, you have me, and you found this blog post. <strong>Disclaimer</strong>: I work at GitHub as a Developer Advocate. However, there was a part of me that felt a little intimidated by the process of setting up a development container. Like, what even is a development container? Should I just copy and paste one? After taking some time to truly understand devcontainers, they feel more approachable for me.</p>
<p><strong><em>In this blog post, I'll walk you through setting up a development container for a static Next.js/TypeScript web application so that it can automatically run in GitHub Codespaces.</em></strong></p>
<h4 id="heading-my-new-open-source-project">My new open source project</h4>
<p>On a related note, I'm excited to share that I've started maintaining my first open source project, the Open Contributions Project, alongside Josh Goldberg. Our goal is to advocate for and explain corporate contributions to open source. It's a static documentation website built with Next.js and TypeScript. We welcome contributions in design, documentation, and code, particularly from beginners. Check out the <a target="_blank" href="https://github.com/OpenContributionsProject/opencontributionssite">repository</a> below.</p>
<p><div class="embedded-content"><a class="embed-card" data-card-width="600px" data-card-key="2e4d628b39a64b99917c73956a16b477" data-card-controls="0" data-card-theme="light" href="https://github.com/OpenContributionsProject/opencontributionssit"></a></div>]</p>
<p>I set up a development container and enabled GitHub Codespaces to streamline the development process for the Open Contributions Project. If you launch the Open Contributions Project in GitHub Codespaces, it will install the required dependencies, run the project, and launch a browser preview of the project. You can try it out <a target="_blank" href="https://codespaces.new/OpenContributionsProject/opencontributionssite?devcontainer_path=/.devcontainer/basics/devcontainer.json">here</a> or by clicking the button below!</p>
<p><a target="_blank" href="https://codespaces.new/OpenContributionsProject/opencontributionssite?devcontainer_path=/.devcontainer/basics/devcontainer.json"><img src="https://github.com/codespaces/badge.svg" alt="Open in GitHub Codespaces" /></a></p>
<h2 id="heading-what-is-github-codespaces">What is GitHub Codespaces?</h2>
<p>GitHub Codespaces is a cloud-based development environment that's hosted in the cloud. This helps developers onboard faster, code on any device, and code in a consistent environment. The UI for GitHub Codespaces can resemble your favorite IDE – like Visual Studio Code, Visual Studio, Jupyter Notebook, or JetBrains, but it opens in your browser. You can customize your project for GitHub Codespaces by creating config files. These config files create a repeatable codespace configuration for all users of your project. If you don't set up any custom configuration, your project will use the default built-in GitHub Codespaces configuration.</p>
<p>You can learn more about GitHub Codespaces from the following resources:</p>
<ul>
<li><p><a target="_blank" href="https://docs.github.com/en/codespaces">Overview and Getting Started with GitHub Codespaces - GitHub documentation</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2023-05-10-revolutionize-your-open-source-workflows-the-top-3-reasons-why-github-codespaces-is-a-must-have-for-maintainers/">Revolutionize your open source workflows: the top 3 reasons why GitHub Codespaces is a must-have for maintainers</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2023-02-28-10-things-you-didnt-know-you-could-do-with-github-codespaces/">10 Things you didn't know you could with GitHub Codespaces</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2023-02-22-a-beginners-guide-to-learning-to-code-with-github-codespaces/">A beginner's guide to learning to code with GitHub Codepsaces</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2021-12-16-technical-interviews-via-codespaces/">Technical Interviews via Codespaces</a></p>
</li>
</ul>
<h2 id="heading-what-is-a-development-container">What is a development container?</h2>
<p>GitHub Codespaces are built on top of virtual machines that utilize development containers, or dev containers, which are essentially Docker containers that offer a comprehensive development environment. You can configure a dev container to provide a uniform developer experience. You can configure a dev container with these three files: <code>devcontainer.json</code>, <code>Dockerfile</code>, and <code>docker-compose.yml</code>. For a small, static Next.js/Typescript project like ours, we only need the <code>devcontainer.json</code> file.</p>
<p>You can learn more about development containers from the following resources:</p>
<ul>
<li><p><a target="_blank" href="https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers">Introduction to dev containers - GitHub documentation</a></p>
</li>
<li><p><a target="_blank" href="https://containers.dev/implementors/json_reference/">Dev Containers Specification Guide</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/github/why-are-people-developing-inside-containers-38o6">Why are people coding inside containers?</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2023-03-06-how-to-automate-your-dev-environment-with-dev-containers-and-github-codespaces/">How to automate your dev environment with dev containers and GitHub Codespaces</a></p>
</li>
<li><p><a target="_blank" href="https://dev.to/github/chatgpt-meets-github-codespaces-how-im-optimizing-chatgpt-quickstart-plugins-for-remote-development-5bc8">How I used dev containers to enable GitHub Codespaces for ChatGPT</a></p>
</li>
</ul>
<h2 id="heading-understanding-codespace-lifecycle-properties">Understanding Codespace lifecycle properties</h2>
<p>In this guide, I use a few Codespace lifecycle properties, so I figured I would give a brief overview of what they are and why we use them. Codespaces lifecycle properties are special properties that are run automatically at specific points during the creation and management of a Codespace environment. You can use them to perform customized tasks at specific points during the lifecycle of the environment.</p>
<p>Here are some commonly used Codespace lifecycle properties:</p>
<ul>
<li><p><strong>preCreateCommand:</strong> runs before a Codespace is created and is used to set up the environment by installing any required software or dependencies.</p>
</li>
<li><p><strong>onCreateCommand:</strong> runs immediately after the Codespace is created and is used to perform any additional setup tasks that are required.</p>
</li>
<li><p><strong>postCreateCommand:</strong> runs after the environment is created and is used to perform any final configuration tasks.</p>
</li>
<li><p><strong>updateCommand:</strong> updates the environment and is typically used to install any new software or dependencies that have been added since the last time the environment was created</p>
</li>
<li><p><strong>updateContentCommand</strong>: updates the content of the environment and is typically used to update files or data within the environment.</p>
</li>
<li><p><strong>postAttachCommand</strong>: In this context, "attach" means to connect to an existing and already created Codespace. This command runs after a user attaches to the Codespace and is used to perform any tasks that should be executed each time the Codespace is attached, such as starting a development server.</p>
</li>
</ul>
<h2 id="heading-steps-for-building-a-development-container-for-a-nextjstypescript-codebase">Steps for building a development container for a Next.js/TypeScript codebase</h2>
<h3 id="heading-step-1-create-a-codespace-for-your-project">Step 1: Create a Codespace for your project</h3>
<p>Let's open our projects in GitHub Codespaces by choosing "Code"&gt; "Codespaces"&gt; "Create Codespace on [default branch]."</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jiruss0uvf1m9daeqw1o.png" alt="Shows code popover and Codespaces tab with green button that says Create Codespace " /></p>
<h3 id="heading-step-2-add-a-pre-made-dev-container">Step 2: Add a pre-made dev container</h3>
<p>First, open the command palette. We can access the command palette using either of these options:</p>
<ul>
<li><p>Pressing this keyboard shortcut combination Shift+Command+P (Mac) <strong>OR</strong> Ctrl+Shift+P (Windows/Linux)</p>
</li>
<li><p>From the Application Menu, click View &gt; Command Palette</p>
</li>
<li><p>Pressing F1</p>
</li>
</ul>
<p>Then, in the command palette, choose: "Add dev container configuration files."</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/57fv05un5ak2bfj1370v.png" alt="shows command palette with add a dev container option" /></p>
<h3 id="heading-step-3-create-a-new-configuration">​​Step 3: Create a new configuration</h3>
<p>Then, we will see two options:</p>
<ul>
<li><p>Modify your active configuration</p>
</li>
<li><p>Create a new configuration</p>
</li>
</ul>
<p>Since we don't have a configured dev container yet, we want to choose "Create a new configuration."</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a44jv4zo23gmjegwe6q3.png" alt="Shows command palette with create a new configuration option" /></p>
<h3 id="heading-step-4-choose-the-nodejs-and-typescript-template">Step 4: Choose the Node.js and TypeScript template</h3>
<p>This next step leads us to a list of predefined dev containers, so we don't have to start from scratch! Currently, the "Node.js &amp; TypeScript" dev container is the most suitable start for a Next.js/TypeScript project.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f43m8e057802fx9x05xa.png" alt="Shows command palette with node and typescript definition" /></p>
<h3 id="heading-step-5-choose-your-preferred-nodejs-version">Step 5: Choose your preferred Node.js version</h3>
<p>The next screen will prompt us for our preferred Node.js version. I chose 20, but you should choose whatever version works best for your project.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pl4nin5wor03wufhye5w.png" alt="Shows command palette with Node versions" /></p>
<h3 id="heading-step-6-skip-the-features-create-the-dev-container">Step 6: Skip the features! Create the dev container</h3>
<p>The next step is to add features. In our case, we don't need any features, so we can press "OK." Pressing "OK" adds a .devcontainer directory to your project with a devcontainer.json file that we can further customize.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h9zo17fzkr9c4w8dbcn4.png" alt="Shows command palette with 0 selected features" /></p>
<p>Here's what our initial devcontainer.json file should look like:</p>
<pre><code class="lang-json">
​​<span class="hljs-comment">// For format details, see https://aka.ms/devcontainer.json. For config options, see the</span>

<span class="hljs-comment">// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node</span>

{

    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Node.js &amp; TypeScript"</span>,

    <span class="hljs-comment">// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile</span>

    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/typescript-node:0-20"</span>

    <span class="hljs-comment">// Features to add to the dev container. More info: https://containers.dev/features.</span>

    <span class="hljs-comment">// "features": {},</span>

    <span class="hljs-comment">// Use 'forwardPorts' to make a list of ports inside the container available locally.</span>

    <span class="hljs-comment">// "forwardPorts": [],</span>

    <span class="hljs-comment">// Use 'postCreateCommand' to run commands after the container is created.</span>

    <span class="hljs-comment">//"postCreateCommand": "yarn install",</span>

    <span class="hljs-comment">// Configure tool-specific properties.</span>

    <span class="hljs-comment">// "customizations": {},</span>

    <span class="hljs-comment">// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.</span>

    <span class="hljs-comment">// "remoteUser": "root"</span>

}
</code></pre>
<h3 id="heading-step-7-automate-installing-project-dependencies">Step 7: Automate installing project dependencies</h3>
<p>As part of the local setup, I run <code>pnpm install</code> to install my project's dependencies. <code>pnpm</code> is a package manager for Node.js packages. It is designed to be fast, disk space efficient, and feature-rich. It creates a single instance of each package on a disk and uses symlinks to link to the installed packages in other projects.</p>
<p>Your project might use a different command and package manager for installing project dependencies. Perhaps, your project is using yarn or npm, so you don't want to copy me verbatim for this step. Instead, you can use my advice in this step as a guiding example! If you're using <code>npm install</code> or <code>yarn install</code> to install your project dependencies, replace <code>pnpm install</code> with the required command for your project.</p>
<p>Anyways, I wanted to automate this step so that project contributors wouldn't have to manually run <code>pnpm install</code>, so I used my dev container to automate this. In my <code>devcontainer.json</code> file, I added a property called:</p>
<pre><code class="lang-json"><span class="hljs-string">"updateContentCommand"</span>: <span class="hljs-string">"pnpm install"</span>
</code></pre>
<p>This will enable my codespace to install the latest project dependencies. I considered delegating the <code>pnpm install</code> command to a different Codespace lifecycle property, but I wanted the benefits of the <code>updateCommentCommand</code>. The biggest benefit of using <em>this</em> lifecycle property is that instead of installing all dependencies each time the environment is created, it would only install new dependencies that have been added since the last time the environment was created.</p>
<h3 id="heading-step-8-automatically-run-the-local-development-server">Step 8: Automatically run the local development server</h3>
<p>Because my project is static and doesn't have too many complexities, after installing the required dependencies, I need to start my local environment with the command <code>pnpm dev</code>. Again, I don't want project contributors to manually type this in. I want the project up and running when they open my project in GitHub Codespaces, so I automated this portion in my dev container by adding the following lines to my <code>devcontainer.json</code> file:</p>
<pre><code class="lang-json"><span class="hljs-string">"postAttachCommand"</span>: <span class="hljs-string">"pnpm dev"</span>
</code></pre>
<p>This line is saying after EVERYTHING in the codespace is set up, and the user connects to the codespace, start the development server. Please remember that the commands to run your local development server may differ. Maybe you need to use <code>npm run dev</code> or <code>yarn start.</code> Double-check before copying and pasting!</p>
<h3 id="heading-step-9-choose-your-forwarded-port">Step 9: Choose your forwarded port</h3>
<p>Now that we automated running our local development server in the step above, we can now choose a specific port for Codespaces to forward traffic in the container to a port on your local machine. In the example below, I chose port 3000.</p>
<pre><code class="lang-json">    <span class="hljs-string">"forwardPorts"</span>: [<span class="hljs-number">3000</span>]
</code></pre>
<p>As a result, GitHub Codespaces will generate a URL that follows this naming convention:</p>
<p>`https://&lt;your-github-handle&gt;-&lt;a-codespaces-id-which-combines-a-words-and-random-characters&gt;-&lt;your-port-number&gt;.preview.app.github.dev/`</p>
<p>For me, it generated this URL:</p>
<p><a target="_blank" href="https://blackgirlbytes-ubiquitous-couscous-777759vgvpjcrv4q-3000.preview.app.github.dev/`"><code>https://blackgirlbytes-ubiquitous-couscous-777759vgvpjcrv4q-3000.preview.app.github.dev/</code></a></p>
<p>You have the ability to change your port's visibility! To learn more about forwarded ports, check out the following resources:</p>
<ul>
<li><p><a target="_blank" href="https://dev.to/github/share-your-locally-hosted-web-app-using-codespaces-276k">Share your locally hosted web app using Codespaces</a></p>
</li>
<li><p><a target="_blank" href="https://docs.github.com/en/codespaces/developing-in-codespaces/forwarding-ports-in-your-codespace">Forwarding ports in your Codespace - GitHub Documentation</a></p>
</li>
</ul>
<h3 id="heading-step-10-get-a-browser-preview">Step 10: Get a browser preview</h3>
<p>My favorite part of GitHub Codespaces is that you can open a browser preview directly within your codespace by adding the following lines to your devcontainer.json file:</p>
<pre><code class="lang-json">
    <span class="hljs-string">"portsAttributes"</span>: {

        <span class="hljs-attr">"3000"</span>: {

            <span class="hljs-attr">"label"</span>: <span class="hljs-string">"Application"</span>,

            <span class="hljs-attr">"onAutoForward"</span>: <span class="hljs-string">"openPreview"</span>

        }

    }
</code></pre>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l7tb4xahxuez5a2ayp2v.png" alt="Shows Codespace with browser preview" /></p>
<h3 id="heading-step-11-automatically-add-extensions">Step 11: Automatically add extensions</h3>
<p>We can configure a project to automatically install extensions in GitHub Codespaces. We can do this by right-clicking on any extension and selecting "Add to devcontainer.json."</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8toq4fgtjrv3qgot68ia.png" alt="Shows option to add extension to devcontainer" /></p>
<p>I added the following extensions:</p>
<ul>
<li><p>Code spell checker</p>
</li>
<li><p>ES Lint</p>
</li>
<li><p>Markdown-lint</p>
</li>
<li><p>Remote-containers</p>
</li>
</ul>
<p>After this, it should add the following object to our devcontainer.json file:</p>
<pre><code class="lang-json">
<span class="hljs-string">"customizations"</span>: {

        <span class="hljs-attr">"vscode"</span>: {

            <span class="hljs-attr">"extensions"</span>: [

                <span class="hljs-string">"streetsidesoftware.code-spell-checker"</span>,

                <span class="hljs-string">"dbaeumer.vscode-eslint"</span>,

                <span class="hljs-string">"esbenp.prettier-vscode"</span>,

                <span class="hljs-string">"DavidAnson.vscode-markdownlint"</span>,

                <span class="hljs-string">"ms-vscode-remote.remote-containers"</span>

            ]

        }

    }
</code></pre>
<h3 id="heading-step-12-make-it-synchronous">Step 12: Make it synchronous</h3>
<p>Using the <code>waitFor</code> property empowers us to have more control over the Codespace lifecycle and the timing of specific commands. For instance, I used the following configuration in my devcontainer.json file:</p>
<pre><code class="lang-json">
<span class="hljs-string">"waitFor"</span>: <span class="hljs-string">"onCreateCommand"</span>
</code></pre>
<p>This tells the Codespace creation process to wait for the onCreateCommand to complete before moving on to the next step in the Codespaces lifecycle. This ensures the environment is set up before running other commands.</p>
<h4 id="heading-caveat">Caveat</h4>
<p>I actually don't have an onCreateCommand in my <code>devcontainer.json</code> file at all, so it doesn't make sense that I added this line. Perhaps, it might make more sense if I add the line below:</p>
<pre><code class="lang-json">
<span class="hljs-string">"waitFor"</span>: <span class="hljs-string">"updateConentCommand"</span>
</code></pre>
<p>I'm still learning about GitHub Codespaces extensively, so that was a mistake I made that I'd like to rectify.</p>
<h3 id="heading-step-13-the-final-devcontainerjson-file">Step 13: The final devcontainer.json file</h3>
<p>Let's confirm the final result! In my <code>.devcontainer</code> directory, I have a <code>devcontainer.json</code> with the contents below:</p>
<pre><code class="lang-json"><span class="hljs-comment">// For format details, see https://aka.ms/devcontainer.json. For config options, see the</span>
<span class="hljs-comment">// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node</span>
{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Node.js &amp; TypeScript"</span>,
    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/typescript-node:0-18"</span>,
    <span class="hljs-attr">"waitFor"</span>: <span class="hljs-string">"onCreateCommand"</span>,
    <span class="hljs-attr">"updateContentCommand"</span>: <span class="hljs-string">"pnpm install"</span>,
    <span class="hljs-attr">"postAttachCommand"</span>: <span class="hljs-string">"pnpm dev"</span>,
    <span class="hljs-attr">"customizations"</span>: {
        <span class="hljs-attr">"vscode"</span>: {
            <span class="hljs-attr">"extensions"</span>: [
                <span class="hljs-string">"streetsidesoftware.code-spell-checker"</span>,
                <span class="hljs-string">"dbaeumer.vscode-eslint"</span>,
                <span class="hljs-string">"esbenp.prettier-vscode"</span>,
                <span class="hljs-string">"DavidAnson.vscode-markdownlint"</span>,
                <span class="hljs-string">"ms-vscode-remote.remote-containers"</span>
            ]
        }
    },
    <span class="hljs-attr">"portsAttributes"</span>: {
        <span class="hljs-attr">"3000"</span>: {
            <span class="hljs-attr">"label"</span>: <span class="hljs-string">"Application"</span>,
            <span class="hljs-attr">"onAutoForward"</span>: <span class="hljs-string">"openPreview"</span>
        }
    },
    <span class="hljs-attr">"forwardPorts"</span>: [<span class="hljs-number">3000</span>]
}
</code></pre>
<h3 id="heading-step-14-try-it-out">Step 14: Try it out!</h3>
<p>We can test out our changes to ensure that GitHub Codespaces will install the required dependencies, install required extensions, run our local development server, and open a browser preview by fully rebuilding the container.</p>
<p>To rebuild the container, we'll need to access the command palette. We can access the command palette using either of these options:</p>
<ul>
<li><p>Pressing this keyboard shortcut combination Shift+Command+P (Mac) <strong>OR</strong> Ctrl+Shift+P (Windows/Linux)</p>
</li>
<li><p>From the Application Menu, click View &gt; Command Palette</p>
</li>
<li><p>Pressing F1</p>
</li>
</ul>
<p>Then, in the command palette, choose: "Codespaces: Full Rebuild Container."</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/snevdbohyoxjo5gpvzud.png" alt="Shows command palette with option to rebuild container" /></p>
<h3 id="heading-video-walkthrough">Video walkthrough</h3>
<p>I live streamed myself walking through the steps to build a development container and planning this blog post. Check it out!</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://www.youtube.com/watch?v=M42_6q1S3bE">https://www.youtube.com/watch?v=M42_6q1S3bE</a></div>
<p> </p>
<h2 id="heading-share-your-learnings">Share your learnings</h2>
<p>If you've tried out development containers or picked up any cool tips and tricks for using GitHub Codespaces, comment below!</p>
]]></content:encoded></item><item><title><![CDATA[ChatGPT Meets GitHub Codespaces]]></title><description><![CDATA[OpenAI recently launched a beta feature called ChatGPT plugins. Essentially, this feature enables third-party tools to interact with the GPT model. To assist developers in creating their own plugins for ChatGPT, OpenAI introduced a quickstart reposit...]]></description><link>https://blackgirlbytes.dev/chatgpt-meets-github-codespaces</link><guid isPermaLink="true">https://blackgirlbytes.dev/chatgpt-meets-github-codespaces</guid><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[codespaces]]></category><category><![CDATA[chatgpt]]></category><category><![CDATA[Cloud]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Mon, 08 May 2023 21:38:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1683581820110/c8250b95-71f0-48ff-b181-82719632d43f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>OpenAI recently launched a beta feature called ChatGPT plugins. Essentially, this feature enables third-party tools to interact with the GPT model. To assist developers in creating their own plugins for ChatGPT, OpenAI introduced a quickstart repository as a guide. To further enhance accessibility, OpenAI's Developer Advocate, Logan Kilpatrick, contacted technologists who work with browser-based or cloud-based Integrated Development Environments (IDEs). Logan's goal was to enable developers to use the quickstart repository locally or with browser-based IDEs like CodeSandbox and Replit. In doing so, developers could build and experiment with plugins directly in their browsers, eliminating the need to clone the repository. Fortunately, one of the cloud-based environments on the list was GitHub Codespaces. Logan reached out to me about his goal, and I was thrilled to accept the challenge.</p>
<p>I had three main reasons for my excitement about adding GitHub Codespaces to the quickstart repository:</p>
<ul>
<li><p>I would gain access to ChatGPT plugins, which I imagine have a never-ending waitlist.</p>
</li>
<li><p>I would gain experience configuring GitHub Codespaces in unfamiliar environments. My experience with GitHub Codespaces is limited to JavaScript-based projects.</p>
</li>
<li><p>I'm a nerd.</p>
</li>
</ul>
<p>Last week, I officially submitted a pull request to enable GitHub Codespaces for the project. The Codespaces team has already reviewed it, and I'm now waiting for the OpenAI team to do the same. In the meantime, I'm sharing what I've learned throughout this experience in the hope that you can learn more about GitHub Codespaces too!</p>
<h3 id="heading-prerequisites">Prerequisites:</h3>
<p><em>This is not necessarily a tutorial that you should follow step by step, but if you did want to follow it, you would need access to the following tools.</em></p>
<ul>
<li><p>ChatGPT account</p>
</li>
<li><p>ChatGPT plugins</p>
</li>
<li><p>GitHub account</p>
</li>
<li><p>It might be helpful to understand the purpose of GitHub Codespaces. You can learn about it from my previous <a target="_blank" href="https://dev.to/github/why-are-people-developing-inside-containers-38o6">blog post</a>.</p>
</li>
</ul>
<h3 id="heading-a-short-summary-of-github-codespaces">A short summary of GitHub Codespaces</h3>
<p>GitHub Codespaces allows you to code in a container hosted in the cloud. This helps developers onboard faster, code on any device, and code in a consistent environment. The biggest benefit I see for this particular ChatGPT quickstart plugin repository is that developers can try out the plugin functionality without the hassle of cloning the project locally or running any setup scripts. They can try it out without context switching and leaving GitHub. And best of all, they won’t have to do any of the setup. Note: you can open any project in GitHub Codespaces. The UI for GitHub Codespaces can resemble your favorite IDE – like Visual Studio Code or JetBrains, but it’s just in your browser. You can also configure GitHub Codespaces to install all the dependencies and run the project to reduce the time it takes for developers to start working on a project.</p>
<p>Here are the steps I took and the lessons I learned while setting up GitHub Codespaces for this project:</p>
<h2 id="heading-step-1-get-the-project-working-locally">Step 1: Get the project working locally</h2>
<p>The first question I needed to answer before configuring GitHub Codespaces was: <em>how does this project work? What is the end result?</em></p>
<p>I found my answer by following the local setup instructions found in the repository’s <a target="_blank" href="http://README.md">README.md</a>. The instructions were simple: install the required packages and then run the project. Subsequently, the server will run locally on <a target="_blank" href="http://localhost:5003"><code>localhost:5003</code></a>.</p>
<p>In ChatGPT, I chose the ‘develop your own plugin’ option.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/brbc6opkzec09whzvwkv.png" alt="ChatGPT plugin store" /></p>
<p>As instructed, I provided ChatGPT with the local address that the server was running on – <a target="_blank" href="http://localhost:5003">localhost:5003</a>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/euinsd95tjlvjyfpkcim.png" alt="enter your website domain on ChatGPT’s interface" /></p>
<p>After all that, I was able to leverage the plugin to create a simple to do list with ChatGPT.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wwdjyuji5zwxv4u61ox0.png" alt="me creating a to do list with ChatGPT" /></p>
<p>If you want to try it out, check out the README <a target="_blank" href="https://github.com/openai/plugins-quickstart#readme">here</a>.</p>
<p>Throughout this process, I noted that there's no frontend for this project, so I only had one goal—when anyone opens this project in a codespace, the server should run.</p>
<h2 id="heading-step-2-open-the-repository-in-github-codespaces">Step 2: Open the repository in GitHub Codespaces</h2>
<p>This step ensures that any changes I make are actually compatible with GitHub Codespaces. The code from the repository will be accessible in GitHub Codespaces out of the box, but it won't start running my project or installing dependencies without configuration. So, the next step is to add a configuration file called a devcontainer.json.</p>
<h2 id="heading-step-3-add-a-dev-container">Step 3: Add a dev container</h2>
<p>Development containers, fondly known as dev containers, are Docker containers that set up a customized environment for the project. I can use a dev container to automatically:</p>
<ul>
<li><p>Install the necessary extensions</p>
</li>
<li><p>Reference environment variables</p>
</li>
<li><p>Forward ports</p>
</li>
<li><p>Install dependencies</p>
</li>
<li><p>Run my project</p>
</li>
<li><p>Run scripts</p>
</li>
<li><p>And more</p>
</li>
</ul>
<p>You can add a default development container by opening the Visual Studio Code Command Palette. This default configuration file contains the basic items you need to get a project running. To open the Visual Studio Code Command Palette, use the following keyboard shortcuts: (Shift+Command+P / Ctrl+Shift+P). Then, search for the option to "Add dev container configuration files."</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gtr1fl303hn5pamrsl6d.png" alt="Command Palette that says Add Dev container configuration files" /></p>
<p>It will prompt you to specify your project's language because each development container is slightly different depending on the language, framework, version, and other environmental factors. For this case, the project is Python-based, so we would choose Python.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pfge696zp3s3jk7wcpmg.png" alt="Command Palette suggesting a Python 3 devcontainer" /></p>
<p>Unfortunately, I did not follow the advice of adding a development container through the Command Palette. Instead, at the root of my project, I created a folder called .devcontainer. Inside that folder, I created a file called devcontainer.json. I copied and pasted a development container from a past Python project into the devcontainer.json. I did this because the example development container included examples of how to leverage the postAttachCommand and postCreateCommand. However, this was a big mistake that I don't recommend because I ended up copying and pasting different lines that I thought were arbitrary, but they impacted the project, and I had to delete those lines.</p>
<p>My recommendation is to use the command palette to add a barebones development container, and then customize it from there.</p>
<p>Here's what our boilerplate devcontainer.json file could look like:</p>
<p>My recommendation is to use the command palette to add a barebones development container, and then customize it from there.</p>
<p>Here’s what our boilerplate <code>devcontainer.json</code> file could look like:</p>
<pre><code class="lang-json">
<span class="hljs-comment">// For format details, see https://aka.ms/devcontainer.json. For config options, see the</span>

<span class="hljs-comment">// README at: https://github.com/devcontainers/templates/tree/main/src/python</span>

{

  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Python 3"</span>,

  <span class="hljs-comment">// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile</span>

  <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/python:0-3.11-bullseye"</span>,

  <span class="hljs-attr">"features"</span>: {

    <span class="hljs-attr">"ghcr.io/devcontainers-contrib/features/coverage-py:2"</span>: {}

  }

  <span class="hljs-comment">// Features to add to the dev container. More info: https://containers.dev/features.</span>

  <span class="hljs-comment">// "features": {},</span>

  <span class="hljs-comment">// Use 'forwardPorts' to make a list of ports inside the container available locally.</span>

  <span class="hljs-comment">// "forwardPorts": [],</span>

  <span class="hljs-comment">// Use 'postCreateCommand' to run commands after the container is created.</span>

  <span class="hljs-comment">// "postCreateCommand": "pip3 install --user -r requirements.txt",</span>

  <span class="hljs-comment">// Configure tool-specific properties.</span>

  <span class="hljs-comment">// "customizations": {},</span>

  <span class="hljs-comment">// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.</span>

  <span class="hljs-comment">// "remoteUser": "root"</span>

}
</code></pre>
<h2 id="heading-step-4-customize-the-dev-container">Step 4: Customize the dev container</h2>
<p>At this point, the repository now has a development container, but it still doesn’t run or install anything because this development container is just boilerplate, and it has zero knowledge of what my project needs to run automatically.</p>
<h3 id="heading-install-dependencies">Install dependencies</h3>
<p>Based on the local set up, one of the first steps for this project is to install dependencies by running this command:</p>
<p><code>pip install -r requirements.txt</code></p>
<p>I needed to make GitHub Codespaces run this command, so the developer wouldn’t have to manually run it. I added this line to the <code>postCreateCommand</code>. The <code>postCreateCommand</code> is responsible for running commands after the container is created. The line looked like this:</p>
<pre><code class="lang-json">
postCreateCommand: pip install -r requirements.txt
</code></pre>
<p>So now, my development container looked like this:</p>
<pre><code class="lang-json">
<span class="hljs-comment">// For format details, see https://aka.ms/devcontainer.json. For config options, see the</span>

<span class="hljs-comment">// README at: https://github.com/devcontainers/templates/tree/main/src/python</span>

{

  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Python 3"</span>,

  <span class="hljs-comment">// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile</span>

  <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/python:0-3.11-bullseye"</span>,

  <span class="hljs-attr">"features"</span>: {

    <span class="hljs-attr">"ghcr.io/devcontainers-contrib/features/coverage-py:2"</span>: {}

  }

  <span class="hljs-comment">// Features to add to the dev container. More info: https://containers.dev/features.</span>

  <span class="hljs-comment">// "features": {},</span>

  <span class="hljs-comment">// Use 'forwardPorts' to make a list of ports inside the container available locally.</span>

  <span class="hljs-comment">// "forwardPorts": [],</span>

  <span class="hljs-comment">// Use 'postCreateCommand' to run commands after the container is created.</span>

  <span class="hljs-string">"postCreateCommand"</span>: <span class="hljs-string">"pip install -r requirements.txt"</span>,

  <span class="hljs-comment">// Configure tool-specific properties.</span>

  <span class="hljs-comment">// "customizations": {},</span>

  <span class="hljs-comment">// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.</span>

  <span class="hljs-comment">// "remoteUser": "root"</span>

}
</code></pre>
<h3 id="heading-port-forwarding">Port Forwarding</h3>
<p>In the dev container, there's an option to define a list of ports where the container is available locally. From the local setup, I saw that the preferred port is <a target="_blank" href="http://localhost:5003">localhost:5003</a>, so I added that to the array of forwardedPorts in my devcontainer.json file.</p>
<p>Here’s what the line looked like:</p>
<pre><code class="lang-json">
<span class="hljs-string">"forwardPorts"</span>: [<span class="hljs-number">5003</span>],
</code></pre>
<p>Here’s what my <code>devcontainer.json</code> file looked like:</p>
<pre><code class="lang-json">
<span class="hljs-comment">// For format details, see https://aka.ms/devcontainer.json. For config options, see the</span>

<span class="hljs-comment">// README at: https://github.com/devcontainers/templates/tree/main/src/python</span>

{

  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Python 3"</span>,

  <span class="hljs-comment">// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile</span>

  <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/python:0-3.11-bullseye"</span>,

  <span class="hljs-attr">"features"</span>: {

    <span class="hljs-attr">"ghcr.io/devcontainers-contrib/features/coverage-py:2"</span>: {}

  }

  <span class="hljs-comment">// Features to add to the dev container. More info: https://containers.dev/features.</span>

  <span class="hljs-comment">// "features": {},</span>

  <span class="hljs-comment">// Use 'forwardPorts' to make a list of ports inside the container available locally.</span>

  <span class="hljs-string">"forwardPorts"</span>: [<span class="hljs-number">5003</span>],

  <span class="hljs-comment">// Use 'postCreateCommand' to run commands after the container is created.</span>

  <span class="hljs-attr">"postCreateCommand"</span>: <span class="hljs-string">"pip install -r requirements.txt"</span>,

  <span class="hljs-comment">// Configure tool-specific properties.</span>

  <span class="hljs-comment">// "customizations": {},</span>

  <span class="hljs-comment">// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.</span>

  <span class="hljs-comment">// "remoteUser": "root"</span>

}
</code></pre>
<h3 id="heading-run-the-project">Run the project</h3>
<p>To locally run the project, developers have to manually run: python <a target="_blank" href="http://main.py">main.py</a>, but I wanted GitHub Codespaces to do this instead. I used the postAttachCommand property in my devcontainer.json file to run this command.</p>
<p>The postAttachCommand enables scripts to run in the terminal after the client connects to the codespace. Here's the line I added:</p>
<pre><code class="lang-json">
<span class="hljs-string">"postAttachCommand"</span>: “python main.py”
</code></pre>
<p>Here’s what my <code>devcontainer.json</code> file looked like:</p>
<pre><code class="lang-json">
<span class="hljs-comment">// For format details, see https://aka.ms/devcontainer.json. For config options, see the</span>

<span class="hljs-comment">// README at: https://github.com/devcontainers/templates/tree/main/src/python</span>

{

  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Python 3"</span>,

  <span class="hljs-comment">// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile</span>

  <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/python:0-3.11-bullseye"</span>,

  <span class="hljs-attr">"features"</span>: {

    <span class="hljs-attr">"ghcr.io/devcontainers-contrib/features/coverage-py:2"</span>: {}

  }

  <span class="hljs-comment">// Features to add to the dev container. More info: https://containers.dev/features.</span>

  <span class="hljs-comment">// "features": {},</span>

  <span class="hljs-comment">// Use 'forwardPorts' to make a list of ports inside the container available locally.</span>

  <span class="hljs-string">"forwardPorts"</span>: [<span class="hljs-number">5003</span>],

  <span class="hljs-comment">// Use 'postCreateCommand' to run commands after the container is created.</span>

  <span class="hljs-attr">"postCreateCommand"</span>: <span class="hljs-string">"pip install -r requirements.txt"</span>,

  “postAttachCommand”: “python main.py”

  <span class="hljs-comment">// Configure tool-specific properties.</span>

  <span class="hljs-comment">// "customizations": {},</span>

  <span class="hljs-comment">// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.</span>

  <span class="hljs-comment">// "remoteUser": "root"</span>

}
</code></pre>
<h2 id="heading-step-5-test-by-rebuilding-the-container">Step 5: Test by rebuilding the container</h2>
<p>I made all these changes to my development container, but I need to check if it actually works, so I rebuilt my container via the Visual Studio Code command palette and chose the option to "Rebuild container."</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3xy709fxi9z6fbkilnut.png" alt="Command Palette suggesting rebuild container" /></p>
<p>After the rebuild was completed, I saw that the Codespace automatically installed the required packages and ran the server on <a target="_blank" href="http://localhost:5003">localhost:5003</a>. It also forwarded the port for me to a randomly generated URL that looked like something like:</p>
<p><a target="_blank" href="https://USERNAME-CODESPACE-NAME-vrpqrxxrx7x2rxx-5003.preview.app.github.dev"><code>https://USERNAME-CODESPACE-NAME-vrpqrxxrx7x2rxx-5003.preview.app.github.dev</code></a></p>
<p>I copied and pasted the randomly generated URL into ChatGPT, but I received error messages that ChatGPT couldn't find the manifest files nor could it install the plugin.</p>
<h2 id="heading-step-6-debugging">Step 6: Debugging</h2>
<h3 id="heading-port-visibility">Port visibility</h3>
<p>I learned that one reason ChatGPT couldn’t find the manifest was because my forwarded port was private, so ChatGPT didn’t have access to the code. Fortunately, I can manually change the port visibility by right clicking the port and switching the visibility from “private” to “public”.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v7im8g7113kjjb0svb6a.png" alt="shows the option to make your port public" /></p>
<p>I checked to see if there was a way to have GitHub Codespaces set this port to public automatically. However, after I spoke with the GitHub Codespaces, I learned there was no easy way to do this, and it could cause a potential security breach, so I decided users could manually do this.</p>
<h3 id="heading-updating-the-files">Updating the files</h3>
<p>Another issue I came across was that there were two files that specified the URL <a target="_blank" href="http://localhost:5003">localhost:5003</a>. The names of the files were <code>openapi.yaml</code> and <code>.well-known/ai-plugin.json</code>. However, my new URL was different. It now resembled a randomly generated URL that looked like this: <a target="_blank" href="https://USERNAME-CODESPACE-NAME-vrpqrxxrx7x2rxx-5003.preview.app.github.dev%5D(https://USERNAME-CODESPACE-NAME-vrpqrxxrx7x2rxx-5003.preview.app.github.dev)"><code>https://USERNAME-CODESPACE-NAME-vrpqrxxrx7x2rxx-5003.preview.app.github.dev</code></a>.</p>
<p>I felt like I was at an impasse and I had two options:</p>
<ul>
<li><p>I could make developers manually update those files to match their newly generated port. They would just have to follow the directions in the <a target="_blank" href="http://README.md">README.md</a>. My problem with this option is that it makes GitHub Codespaces feel clunky. Users already have to update the port visibility and <em>now</em> they have to update the files. (Boo, tomato, tomato, tomato). I wanted to represent GitHub Codespaces in its best light.</p>
</li>
<li><p>OR I could edit the source code, and replace the words <a target="_blank" href="http://localhost:5003">localhost:5003</a> with something like <code>https://${CODESPACE_NAME}-5003.${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}</code>. However, that would ruin the experience for developers who choose to still develop the plugin locally.</p>
</li>
</ul>
<p>I reached out to the Codespaces team for help. They advised me to write a script that dynamically updates the url in those particular files if the repository is opened in a Codespace. The script I wrote looks like this:</p>
<pre><code class="lang-bash">
<span class="hljs-comment">#!/bin/bash</span>

<span class="hljs-built_in">set</span> -e

<span class="hljs-comment"># Determine the value of SITE_HOST based on whether the project is opened in a Codespace</span>

<span class="hljs-keyword">if</span> [ -n <span class="hljs-string">"<span class="hljs-variable">$CODESPACE_NAME</span>"</span> ]; <span class="hljs-keyword">then</span>

        SITE_HOST=<span class="hljs-string">"https://<span class="hljs-variable">${CODESPACE_NAME}</span>-5003.<span class="hljs-variable">${GITHUB_CODESPACES_PORT_FORWARDING_DOMAIN}</span>"</span>

        <span class="hljs-comment"># Replace "localhost:5003" with the value of SITE_HOST in the ai-plugin.json file</span>

        sed -i <span class="hljs-string">"s#http://localhost:5003#<span class="hljs-variable">${SITE_HOST}</span>#g"</span> .well-known/ai-plugin.json

        <span class="hljs-comment"># Replace "localhost:5003" with the value of SITE_HOST in the openapi.yaml file</span>

        sed -i <span class="hljs-string">"s#http://localhost:5003#<span class="hljs-variable">${SITE_HOST}</span>#g"</span> openapi.yaml

<span class="hljs-keyword">fi</span>
</code></pre>
<p>Instead of having the developer manually run this script, I made my codespace run it automatically by adding the following to my devcontainer.json file:</p>
<pre><code class="lang-json">
<span class="hljs-string">"postAttachCommand"</span>: <span class="hljs-string">".devcontainer/addcodespacename.sh &amp;&amp; python main.py"</span>,
</code></pre>
<p>Now, before the program runs, the codespace will run this shell script and update the files to use the correct URL.</p>
<p>Here’s what my devcontainer.json looked like:</p>
<pre><code class="lang-json">
<span class="hljs-comment">// For format details, see https://aka.ms/devcontainer.json. For config options, see the</span>

<span class="hljs-comment">// README at: https://github.com/devcontainers/templates/tree/main/src/python</span>

{

  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Python 3"</span>,

  <span class="hljs-comment">// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile</span>

  <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/python:0-3.11-bullseye"</span>,

  <span class="hljs-attr">"features"</span>: {

    <span class="hljs-attr">"ghcr.io/devcontainers-contrib/features/coverage-py:2"</span>: {}

  }

  <span class="hljs-comment">// Features to add to the dev container. More info: https://containers.dev/features.</span>

  <span class="hljs-comment">// "features": {},</span>

  <span class="hljs-comment">// Use 'forwardPorts' to make a list of ports inside the container available locally.</span>

  <span class="hljs-string">"forwardPorts"</span>: [<span class="hljs-number">5003</span>],

  <span class="hljs-comment">// Use 'postCreateCommand' to run commands after the container is created.</span>

  <span class="hljs-attr">"postCreateCommand"</span>: <span class="hljs-string">"pip install -r requirements.txt"</span>,

  <span class="hljs-attr">"postAttachCommand"</span>: <span class="hljs-string">".devcontainer/addcodespacename.sh &amp;&amp; python main.py"</span>,

  <span class="hljs-comment">// Configure tool-specific properties.</span>

  <span class="hljs-comment">// "customizations": {},</span>

  <span class="hljs-comment">// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.</span>

  <span class="hljs-comment">// "remoteUser": "root"</span>

}
</code></pre>
<p>I rebuilt the container for testing, and everything worked as expected!</p>
<h2 id="heading-step-7-nice-to-haves">Step 7: Nice-to-haves</h2>
<h3 id="heading-opening-important-files-post-codespace-creation">Opening important files post-Codespace creation</h3>
<p>This is not required, but I thought it would be convenient to have the two most important files opened after the codespace is created. Because this is a new project and just a new concept, I wanted to make it easy for people to navigate the project. And I know there’s a property in a <code>devcontainer.json</code> called <code>openFiles</code> that handles that!</p>
<p>Here are the lines I added:</p>
<pre><code class="lang-json">
    <span class="hljs-string">"customizations"</span>: {

        <span class="hljs-attr">"codespaces"</span>: {

            <span class="hljs-attr">"openFiles"</span>: [

                <span class="hljs-string">".well-known/ai-plugin.json"</span>,

                <span class="hljs-string">"openapi.yaml"</span>

            ]

        }

    }

}
</code></pre>
<p>Here is what my <code>devcontainer.json</code> file looked like at this point:</p>
<pre><code class="lang-json">
<span class="hljs-comment">// For format details, see https://aka.ms/devcontainer.json. For config options, see the</span>

<span class="hljs-comment">// README at: https://github.com/devcontainers/templates/tree/main/src/python</span>

{

  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Python 3"</span>,

  <span class="hljs-comment">// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile</span>

  <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/python:0-3.11-bullseye"</span>,

  <span class="hljs-attr">"features"</span>: {

    <span class="hljs-attr">"ghcr.io/devcontainers-contrib/features/coverage-py:2"</span>: {}

  }

  <span class="hljs-comment">// Features to add to the dev container. More info: https://containers.dev/features.</span>

  <span class="hljs-comment">// "features": {},</span>

  <span class="hljs-comment">// Use 'forwardPorts' to make a list of ports inside the container available locally.</span>

  <span class="hljs-string">"forwardPorts"</span>: [<span class="hljs-number">5003</span>],

  <span class="hljs-comment">// Use 'postCreateCommand' to run commands after the container is created.</span>

  <span class="hljs-attr">"postCreateCommand"</span>: <span class="hljs-string">"pip install -r requirements.txt"</span>,

  <span class="hljs-attr">"postAttachCommand"</span>: <span class="hljs-string">".devcontainer/addcodespacename.sh &amp;&amp; python main.py"</span>,

 <span class="hljs-comment">// Configure tool-specific properties.</span>

  <span class="hljs-attr">"customizations"</span>: {

        <span class="hljs-attr">"codespaces"</span>: {

            <span class="hljs-attr">"openFiles"</span>: [

                <span class="hljs-string">".well-known/ai-plugin.json"</span>,

                <span class="hljs-string">"openapi.yaml"</span>

            ]

        }

    }

}

  <span class="hljs-comment">// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.</span>

  <span class="hljs-comment">// "remoteUser": "root"</span>

}
</code></pre>
<h2 id="heading-step-8-clean-up">Step 8: Clean up</h2>
<p>Everything is working exactly how I wanted, and now I just wanted to clean up any unused properties and confusing comments.</p>
<p>Here’s what my final devcontainer.json file looks like:</p>
<pre><code class="lang-json">
<span class="hljs-comment">// For format details, see https://aka.ms/devcontainer.json.</span>

{

    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"ChatGPT Quickstart Plugins"</span>,

    <span class="hljs-comment">// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile</span>

    <span class="hljs-attr">"image"</span>: <span class="hljs-string">"mcr.microsoft.com/devcontainers/python:0-3.11"</span>,

    <span class="hljs-comment">// Use 'forwardPorts' to make a list of ports inside the container available locally.</span>

    <span class="hljs-attr">"forwardPorts"</span>: [

        <span class="hljs-number">5003</span>

    ],

    <span class="hljs-comment">// Use 'postCreateCommand' to run commands after the container is created.</span>

    <span class="hljs-attr">"postCreateCommand"</span>: <span class="hljs-string">"pip install -r requirements.txt"</span>,

    <span class="hljs-attr">"postAttachCommand"</span>: <span class="hljs-string">".devcontainer/addcodespacename.sh &amp;&amp; python main.py"</span>,

    <span class="hljs-attr">"customizations"</span>: {

        <span class="hljs-attr">"codespaces"</span>: {f

            <span class="hljs-attr">"openFiles"</span>: [

                <span class="hljs-string">".well-known/ai-plugin.json"</span>,

                <span class="hljs-string">"openapi.yaml"</span>

            ]

        }

    }

}
</code></pre>
<h2 id="heading-whats-next">What’s next?</h2>
<p>I’ll wait for the OpenAI team to either approve or suggest changes to my <a target="_blank" href="https://github.com/openai/plugins-quickstart/pull/14">pull request</a>. I’m looking forward to seeing it get merged! I'd love to contribute more dev containers to open source projects for folks who want to improve their projects' onboarding experience and enable them to work on their projects within GitHub Codespaces.</p>
<p><em>If you have questions or any cool things you learned about development containers or GitHub Codespaces, comment below!</em></p>
]]></content:encoded></item><item><title><![CDATA[A Beginner's Guide to Prompt Engineering with GitHub Copilot]]></title><description><![CDATA[When I started using GitHub Copilot and other generative AI tools, I felt frustrated because I wasn't receiving the expected results. How were people feeling so successful with these tools, and why weren't they doing what I wanted? For example, I wou...]]></description><link>https://blackgirlbytes.dev/a-beginners-guide-to-prompt-engineering-with-github-copilot</link><guid isPermaLink="true">https://blackgirlbytes.dev/a-beginners-guide-to-prompt-engineering-with-github-copilot</guid><category><![CDATA[GitHub]]></category><category><![CDATA[#PromptEngineering]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Machine Learning]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Wed, 05 Apr 2023 04:21:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1680667576471/48897c22-cfb9-492e-918e-f26dc453eb03.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I started using GitHub Copilot and other generative AI tools, I felt frustrated because I wasn't receiving the expected results. How were people feeling so successful with these tools, and why weren't they doing what I wanted? For example, I would ask GitHub Copilot to solve a LeetCode problem for me. The GitHub Copilot icon would spin to indicate that it's thinking, and then I would receive an incongruent suggestion or no suggestion at all. I was annoyed, but it turns out – I was using it wrong! After more experimentation, I improved my communication methods with GitHub Copilot by providing context, examples, and clear instructions in the form of comments and code. Later on, I learned that this practice is called prompt engineering. In this blog post, I'll discuss top tips to help you get the most out of GitHub Copilot. </p>
<p>First, let's start with the basics for folks who are unfamiliar with GitHub Copilot or prompt engineering.</p>
<h2 id="heading-what-is-github-copilot">What is GitHub Copilot?</h2>
<p>GitHub Copilot is an AI pair programmer developed by GitHub and GitHub Copilot is powered by OpenAI Codex, a generative pre-trained language model created by OpenAI.that provides contextualized code suggestions based on context from comments and code. To use it, you can install the GitHub Copilot extension available to you in the following Integrated Development Environments (IDEs):</p>
<ul>
<li>Visual Studio</li>
<li>Visual Studio Code</li>
<li>Neovim</li>
<li>JetBrains IDEs (IntelliJ, PyCharm, WebStorm, etc)</li>
</ul>
<h2 id="heading-can-github-copilot-code-on-its-own">Can GitHub Copilot code on its own?</h2>
<p>At GitHub, we use the terms "AI pair programmer," "AI assistant," and "Copilot" to since this tool cannot work without you – the developer! In fact, AI systems can only perform the tasks that developers program them to perform, and they do not possess free will or the ability to make decisions independently. In this case, GitHub Copilot leverages context from the code and comments you write to suggest code instantly! With GitHub Copilot, you can convert comments to code, autofill repetitive code, and show alternative suggestions. </p>
<h2 id="heading-how-does-github-copilot-work-under-the-hood">How does GitHub Copilot work under the hood?</h2>
<p>Under the hood, GitHub Copilot draws context from comments and code, instantly suggesting individual lines and whole functions. OpenAI Codex, a machine-learning model that can translate natural language into code, powers GitHub Copilot</p>
<h2 id="heading-what-is-prompt-engineering">What is prompt engineering?</h2>
<p>Prompt engineering is the practice of giving an AI model specific instructions to produce the results you want. A prompt is a sequence of text or a line of code that can trigger a response from an AI model. You can liken this concept to receiving a prompt for an essay. You can receive a prompt to write an essay about a time you overcame a challenge or a prompt to write about a classic book, such as the Great Gatsby. As a result, you give a response to the prompt based on what you've learned. A large language model or LLM will behave similarly. </p>
<p><strong>Here's another illustration of prompt engineering:</strong> 
When I learned to code, I participated in an activity where I gave a robot instructions on how to make a sandwich. It was a fun, silly activity that taught me that:</p>
<ul>
<li>Computers can only do what you tell them to do</li>
<li>You need to be very specific with your instructions</li>
<li>They're better at taking orders one step at a time</li>
<li>Algorithms are just a series of instructions</li>
</ul>
<p>For example, if I were to tell the "robot" to make a sandwich, I need to tell it:</p>
<ol>
<li>Open the bag of bread</li>
<li>Take the first two slices of bread out of the bag</li>
<li>Lay the slices of bread side by side on the counter</li>
<li>Spread peanut butter on one slice of bread with a butter knife</li>
<li>Et cetera, et cetera, et cetera</li>
</ol>
<p><img src="https://media.giphy.com/media/3o7TKxwP5Xm3HYMcOk/giphy-downsized-large.gif" /></p>
<p>Without those clear instructions, the robot might do something silly, like spread peanut butter on both slices of bread, or it might not do anything at all. The robot doesn't know what a sandwich is, and it doesn't know how to make one. It just knows how to follow instructions. </p>
<p>Similarly, GitHub Copilot needs clear, step-by-step instructions to generate the code that best helps you. </p>
<p>Let's discuss best practices for prompt engineering to give clear instructions to GitHub Copilot and generate your desired results.</p>
<h2 id="heading-best-practices-for-prompt-engineering-with-github-copilot">Best Practices for Prompt Engineering with GitHub Copilot</h2>
<h3 id="heading-provide-high-level-context-followed-by-more-detailed-instructions">Provide high-level context followed by more detailed instructions</h3>
<p>The best technique for me is providing high-level context in a comment at the top of the file, followed by more detailed instructions in the form of comments and code.</p>
<p>For example, if I'm building a to-do application. At the top, I'll write a comment that says, "Build a to-do application using Next.js that allows user to add, edit, and delete to do items." Then on the following lines, I'll write a comment to create the:</p>
<ul>
<li>to-do list component, and I'll let GitHub Copilot generate the component underneath the comment</li>
<li>button component, and I'll let GitHub Copilot generate the component underneath the comment</li>
<li>input component, and I'll let GitHub Copilot generate the component underneath the comment</li>
<li>add function, and I'll let GitHub Copilot generate the function underneath the comment</li>
<li>edit function, and I'll let GitHub Copilot generate the function underneath the comment</li>
<li>delete function, and I'll let GitHub Copilot generate the function underneath the comment</li>
<li>etcetra, etcetera, etcetera... </li>
</ul>
<p><strong>Here's an example of me using this technique to build a house with p5.js:</strong></p>
<p>In the following GIF, I write a comment at the top describing at a high-level what I want p5.js to draw. I want to draw a white house with a brown roof, a red door, and a red chimney. Then, I write a comment for each element of the house, and I let GitHub Copilot generate the code for each element.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y1dqqnba10i2ltlzcq2d.gif" alt="p5js" /></p>
<h3 id="heading-provide-specific-details">Provide specific details</h3>
<p>When you provide specific details, GitHub Copilot will be able to generate more accurate code suggestions. For example, if you want GitHub Copilot to retrieve data from an API, you need to tell it what type of data you want to retrieve, how to process the data, and what API endpoint you're hoping to hit.</p>
<p>Here's an example of a non-specific comment (prompt) where GitHub Copilot will be less likely to generate a useful suggestion:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Get data from API</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getData</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-comment">//code goes here</span>
}
</code></pre>
<p>In the example above, GitHub Copilot didn't generate anything for me besides the name of the function and the opening and closing brackets.</p>
<p>Here's an example of a specific comment (prompt) where GitHub Copilot will be more likely to generate a useful suggestion:</p>
<pre><code class="lang-js"><span class="hljs-comment">// Pass in user ids and retrieve user data from jsonplaceholder.typicode.com API, then return it as a JSON object</span>
<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getUserData</span>(<span class="hljs-params">userId</span>) </span>{
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">`https://jsonplaceholder.typicode.com/users/<span class="hljs-subst">${userId}</span>`</span>);
    <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
    <span class="hljs-keyword">return</span> data;
}
</code></pre>
<h3 id="heading-provide-examples">Provide examples</h3>
<p>In addition to telling GitHub Copilot what you want it to do, you can also show it what you want it to do with examples in your preferred coding style. While GitHub Copilot is using an AI model that is already trained on a large amount of data, providing examples to GitHub Copilot help it understand the context and constraints of a particular code snippet. Showing AI models examples of what you want them to do is a common practice in machine learning.</p>
<p>Here are a few approaches engineers use to train AI models:</p>
<ul>
<li>Zero-shot learning</li>
<li>One-shot learning</li>
<li>Few-shot learning</li>
</ul>
<p>I asked ChatGPT to explain the difference between these methods to me like I was 5 years old, and here’s what it gave me:</p>
<h4 id="heading-zero-shot-learning">Zero-shot learning</h4>
<p>This is like when you see a new toy you've never seen before, but you know what it is because it looks like other toys you've seen. For example, if you've seen many different kinds of stuffed animals, you might be able to recognize a new one even if you've never seen that exact one before. Similarly, a computer can learn to recognize new things by using what it knows about similar things to make educated guesses about the new thing.</p>
<h4 id="heading-one-shot-learning">One-shot learning</h4>
<p>This is like when you see a new toy for the first time, and your mom or dad tells you what it's called and what it does. After hearing about it just once, you remember what it is and can recognize it the next time you see it. A computer can learn to recognize new things in the same way by being shown just a few examples and learning from them.</p>
<h4 id="heading-few-shot-learning">Few-shot learning</h4>
<p>Few-shot learning is like learning to do something new by seeing only a few examples. For example, let's say you want to learn how to draw a cat, but you've only seen a few pictures of cats before. With few-shot learning, you can still learn how to draw a cat even if you haven't seen many cats before. It's like a magic power that helps you learn new things quickly, even if you don't have a lot of examples to learn from!</p>
<p>Here's what happened when I showed GitHub Copilot examples vs. when I didn't show it examples:</p>
<h4 id="heading-no-example">No example</h4>
<pre><code class="lang-python"><span class="hljs-comment"># Create a list of the first 10 prime numbers</span>
primes = []

<span class="hljs-keyword">for</span> num <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>, <span class="hljs-number">30</span>):
    <span class="hljs-keyword">if</span> all(num % i != <span class="hljs-number">0</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>, num)):
        primes.append(num)
print(primes)
</code></pre>
<p>In the code snippet above, GitHub Copilot will accurately return the first 10 numbers, however it's inefficient because it will loop through all 29 numbers between 2 and 30. We can get more efficient results by providing an specific example of what we want GitHub Copilot to do.</p>
<h4 id="heading-with-example">With example</h4>
<pre><code class="lang-python"><span class="hljs-comment"># Create a list of the first 10 prime numbers</span>
<span class="hljs-comment"># Example: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]</span>
primes = []

<span class="hljs-keyword">for</span> num <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>, <span class="hljs-number">30</span>):
    <span class="hljs-keyword">if</span> all(num % i != <span class="hljs-number">0</span> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">2</span>, num)):
        primes.append(num)
    <span class="hljs-keyword">if</span> len(primes) == <span class="hljs-number">10</span>:
        <span class="hljs-keyword">break</span>
print(primes)
</code></pre>
<p>In the above code snippet, GitHub Copilot will return the first ten prime numbers and stop when it's found all 10. My goal was to get accurate but fast results, and GitHub Copilot successfully achieved that after I nudged it in the right direction.</p>
<h2 id="heading-additional-tips">Additional tips</h2>
<h3 id="heading-iterate-your-prompts">Iterate your prompts</h3>
<p>If your initial prompt elicits the desired response, delete the generated code suggestion, edit your comment with more details and examples, and try again! It's a learning process for you and GitHub Copilot. The more you use it, the better you'll get at communicating with GitHub Copilot. </p>
<h3 id="heading-keep-a-tab-opened-of-relevant-files-in-your-ide">Keep a tab opened of relevant files in your IDE</h3>
<p>Currently, GitHub Copilot does not have the ability to gain context for your entire codebase. However, it can read your current file and any files that are opened in your IDE. I've found it helpful to keep an open tab of relevant files that I want GitHub Copilot to reference. For example, if I'm writing a function that uses a variable from another file, I'll keep that file open in my IDE. This will help GitHub Copilot provide more accurate suggestions.  </p>
<h3 id="heading-give-your-ai-assistant-an-identity">Give your AI assistant an identity</h3>
<p>I received this advice from <a target="_blank" href="https://twitter.com/_LeilahSimone">Leilah Simone</a>, a Developer Advocate at BitRise. I've yet to try this with GitHub Copilot, but it was helpful advice. It helps to control the type of response the user will receive. In Leila's case, she requests that ChatGPT behave as a senior iOS engineer. She says, "It's helped her reduce syntax and linting issues." </p>
<h3 id="heading-use-predictable-patterns">Use predictable patterns</h3>
<p>As we saw in the many examples above, GitHub Copilot will follow patterns in your code. AI enthusiast and Developer Content Creator, <a target="_blank" href="https://twitter.com/ykdojo">YK aka CS Dojo</a>, shares how he uses this to his advantage:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/ykdojo/status/1640629300595671040?s=20">https://twitter.com/ykdojo/status/1640629300595671040?s=20</a></div>
<p>%</p>
<h3 id="heading-use-consistent-specific-naming-conventions-for-variables-and-functions-that-describe-their-purpose">Use consistent, specific naming conventions for variables and functions that describe their purpose</h3>
<p>When declaring variables or functions, use names specific to the variable's purpose. This will help GitHub Copilot understand the context of the variable and generate more relevant suggestions. For example, instead of using a generic variable name like "value," use a more specific name like "input_string" or "output_file."</p>
<p>GitHub Copilot will also use the naming conventions you use in your code. For example, if you use camelCase for variables, GitHub Copilot will suggest camelCase variables. If you use snake_case for variables, GitHub Copilot will suggest snake_case variables. </p>
<h3 id="heading-use-good-coding-practices">Use good coding practices</h3>
<p>While GitHub Copilot can be a powerful tool for generating code suggestions, it's important to remember that it's not a replacement for your own programming skills and expertise. AI models are only as good as the data they have been trained on, Therefore, it's important to use these tools as aids and not rely on them entirely. I encourage every user of GitHub Copilot to:</p>
<ul>
<li>Review code</li>
<li>Run unit tests, integration tests, and any other programatic forms of testing code</li>
<li>Manually test code to ensure it's working as intended</li>
<li>And to use good coding practices because GitHub Copilot will follow your coding style and patterns as a guide for its suggestions.</li>
</ul>
<h2 id="heading-beyond-your-editor">Beyond your editor</h2>
<p>Currently, GitHub Copilot is an extension that is available in the most popular IDEs. There's also GitHub Copilot Labs, a separate experimental extension available with GitHub Copilot access. Copilot Labs can help you translate, debug, test, document, and refactor code. Additionally, we recently launched Copilot X, a suite of features that improve developer productivity outside of the IDE. Copilot X includes:</p>
<ul>
<li><a target="_blank" href="https://githubnext.com/projects/copilot-for-docs">Copilot for Docs</a> - saves developers from scouring reams of documentation.</li>
<li><a target="_blank" href="https://githubnext.com/projects/copilot-for-pull-requests/">Copilot for Pull Requests</a> - helps you write better PR descriptions and to help your team review and merge PRs faster/</li>
<li><a target="_blank" href="https://github.com/github-copilot/chat_waitlist_signup/join">Copilot Chat</a> - a ChatGPT-like experience in your editor with GitHub Copilot chat.</li>
<li><a target="_blank" href="https://githubnext.com/projects/copilot-cli/">Copilot for CLI</a> - helps you remember shell commands and flags to run commands in your terminal faster.  </li>
<li><a target="_blank" href="https://githubnext.com/projects/copilot-voice/">Copilot Voice</a> - write and edit code, navigate the codebase, and control Visual Studio Code with your voice.</li>
</ul>
<p>Copilot X features/products are currently in technical preview. If you'd like access to one of the features above, sign up for the waitlist at https://github.com/features/preview/copilot-x.</p>
<h2 id="heading-start-practicing-prompt-engineering-with-github-copilot">Start practicing prompt engineering with GitHub Copilot</h2>
<p>The best way to learn how to use GitHub Copilot optimally is to start using it. You can sign up for access to GitHub Copilot <a target="_blank" href="https://github.com/features/copilot">here</a>.</p>
<p>If you're a business leader and you'd like to give your entire team access to GitHub Copilot, sign up for GitHub Copilot for Business <a target="_blank" href="https://github.com/github-copilot/business_signup/choose_business_type">here</a>.</p>
<h2 id="heading-lets-keep-learning-together">Let's keep learning together</h2>
<p>Thanks for reading this blog post. I'd love to hear from you! I'm still learning more about artificial intelligence, GitHub Copilot, and prompt engineering. If you're a GitHub Copilot fan and have learned how to use it to improve your developer workflow, share some of your tips in the comments below!</p>
<p>For similar content, follow GitHub and me on DEV.to! Also, check out other resources to learn more about prompt engineering:</p>
<ul>
<li><a target="_blank" href="https://microsoft.github.io/prompt-engineering/">How to get Codex to produce the code you want</a></li>
<li><a target="_blank" href="https://platform.openai.com/docs/guides/completion/prompt-design">Prompt Design</a> from OpenAI</li>
<li><a target="_blank" href="https://youtu.be/q1rvp0k6MTs">Prompt Engineering 101: Introduction to Codex</a></li>
<li><a target="_blank" href="https://github.com/dair-ai/Prompt-Engineering-Guide">Prompt Engineering Guide</a> by Elvis Saravia</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[How to build a rock, paper, scissors game with GitHub Copilot]]></title><description><![CDATA[In this tutorial, we will build a rock, paper, scissors game with GitHub Copilot. We will also explore GitHub Copilot, a cloud-based AI tool that assists users of various editors in suggesting lines of code and whole functions instantly. We will disc...]]></description><link>https://blackgirlbytes.dev/how-to-build-a-rock-paper-scissors-game-with-github-copilot</link><guid isPermaLink="true">https://blackgirlbytes.dev/how-to-build-a-rock-paper-scissors-game-with-github-copilot</guid><category><![CDATA[GitHub]]></category><category><![CDATA[github copilot]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Python]]></category><category><![CDATA[General Programming]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Sat, 04 Mar 2023 03:17:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1677899788631/a5a3f925-9c55-4f38-a9ad-ca32b8de5895.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this tutorial, we will build a rock, paper, scissors game with GitHub Copilot. We will also explore GitHub Copilot, a cloud-based AI tool that assists users of various editors in suggesting lines of code and whole functions instantly. We will discuss how Copilot has redefined productivity for millions of developers, and the benefits it provides. This tutorial includes the use of CodeTour, a VS Code extension, that allows developers to create and follow a guided walkthrough of a codebase. Let's get started!</p>
<h2 id="heading-what-is-github-copilot">What is GitHub Copilot?</h2>
<p>GitHub Copilot has helped redefine productivity for millions of developers by introducing them to the magic of AI assistance. GitHub Copilot is a cloud-based artificial intelligence tool developed by GitHub and OpenAI to assist users of Visual Studio, Visual Studio Code, Neovim, and JetBrains by suggesting lines of code and whole functions instantly. With Copilot, you can write a regular expression or interact with an API for the first time without leaving your editor.</p>
<h2 id="heading-why-i-love-github-copilot">Why I love GitHub Copilot</h2>
<p>GitHub Copilot boosts productivity because it helps developers spend more time thinking about the theory they are building than about the code itself.</p>
<p>However, beyond productivity, GitHub Copilot helps provide me with psychological safety. Psychological safety refers to the belief that you can speak up, ask questions, make mistakes, and contribute without fear of punishment or humiliation. When employees feel safe to learn, ask questions, contribute, and lead, it boosts the team’s and individual’s overall confidence, morale, and performance.</p>
<p>Unfortunately, the reality is psychological safety is not always common at work. When I’m feeling uncertain about asking for help, or I’m not even sure how to word my questions, I can use GitHub Copilot to help me:</p>
<ul>
<li><p>Brainstorm ideas when I reach a mental block</p>
</li>
<li><p>Jog my memory</p>
</li>
<li><p>Retain focus</p>
</li>
<li><p>Determine if I’m going in the right direction</p>
</li>
</ul>
<h2 id="heading-why-would-i-build-a-rock-paper-scissors-game">Why would I build a rock, paper, scissors game?</h2>
<ul>
<li><p>I did this for fun</p>
</li>
<li><p>I did this to build my Python skills. I’m a baby Pythonista. For the past 5 years, I’ve been writing different forms of JavaScript on the frontend and backend, but ever since I started using GitHub Copilot, I’ve taken up an interest in Python. And I want to continue to read, type, and navigate code written in Python. It’s a less verbose language than JavaScript, so it feels easy for me to learn.</p>
</li>
<li><p>I wanted to create a short, fun activity to help folks learn how to leverage GitHub Copilot because it’s not always obvious how to get started. Hint: Provide as much context as possible through comments and lines of code.</p>
</li>
<li><p>I remember building a rock, paper, scissors game when I was in a coding bootcamp back in 2018. At the time, the logic seemed so difficult. I’m hoping this can be a helpful tool for developers who are learning to code.</p>
</li>
<li><p>I want to continue to creatively use GitHub Copilot for different situations to understand its limitations and strengths.</p>
</li>
</ul>
<h2 id="heading-to-complete-this-tutorial-you-will-need">To complete this tutorial, you will need:</h2>
<ul>
<li><p>Access to <a target="_blank" href="https://github.com/features/copilot">GitHub Copilot</a></p>
</li>
<li><p>Open this <a target="_blank" href="https://github.com/blackgirlbytes/rock-paper-scissors-copilot/">repository</a></p>
</li>
</ul>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/blackgirlbytes/rock-paper-scissors-copilot">https://github.com/blackgirlbytes/rock-paper-scissors-copilot</a></div>
<p> </p>
<h2 id="heading-how-does-this-work">How does this work?</h2>
<p>The CodeTour prompts developers to write comments and lines of code that trigger GitHub Copilot to generate code to create a rock, paper, scissors game.</p>
<h2 id="heading-what-is-codetour">What is CodeTour?</h2>
<p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=vsls-contrib.codetour">CodeTour</a> is a VS Code extension developed by my amazing coworker, <a target="_blank" href="https://github.com/lostintangent">Jonathan Carter</a>! It allows developers to create and follow a guided walkthrough of a codebase.</p>
<h2 id="heading-what-you-will-find-in-this-repository">What you will find in this repository</h2>
<p>In this <a target="_blank" href="https://github.com/blackgirlbytes/rock-paper-scissors-copilot/">repository</a>, you will find:</p>
<ul>
<li><p>a <a target="_blank" href="http://main.py"><code>main.py</code></a> file with no contents</p>
</li>
<li><p>a devcontainer that installs CodeTour and GitHub Copilot when the Codespace is created</p>
</li>
<li><p>a CodeTour to guide the developer through using GitHub Copilot to develop a rock, paper, scissors game.</p>
</li>
</ul>
<h2 id="heading-how-to-use-the-guided-codetour">How to use the guided CodeTour</h2>
<p>Navigate to this <a target="_blank" href="https://github.com/blackgirlbytes/rock-paper-scissors-copilot/">repository</a> that I created. Then follow the instructions below:</p>
<h4 id="heading-step-1">Step 1</h4>
<p>Choose 'Use this template', and 'Open in a codespace'</p>
<p><img src="https://user-images.githubusercontent.com/22990146/222702705-3b6a58e5-bde4-4197-8372-056629d87006.png" alt="Open in a codespace image" /></p>
<h4 id="heading-step-2">Step 2</h4>
<p>Choose the “Explorer Icon” on the left sidebar of your editor.</p>
<p><img src="https://user-images.githubusercontent.com/22990146/222706773-ad2fcb4f-5346-4bcc-995f-88c1ceec8083.png" alt="Highlighting the Explorer Icon" /></p>
<h4 id="heading-step-3">Step 3</h4>
<p>Toggle the CodeTour panel</p>
<p><img src="https://user-images.githubusercontent.com/22990146/222707067-f03533f9-3625-4597-a201-1d17b76f112a.png" alt="Highlighting the Code Tour panel" /></p>
<h4 id="heading-step-4">Step 4</h4>
<p>Press the “Play button” to start the tour.</p>
<p><img src="https://user-images.githubusercontent.com/22990146/222708745-53e644aa-dc2b-44d0-8484-ac335847e14d.png" alt="Highlighting the Play button" /></p>
<h4 id="heading-step-5">Step 5</h4>
<p>Your CodeTour will begin! Follow the CodeTour’s steps to learn how to use GitHub Copilot.</p>
<p><img src="https://user-images.githubusercontent.com/22990146/222709106-ebdfe7c2-e198-4e76-8be4-cdd592453b6a.png" alt="Highlighting the start of a CodeTour" /></p>
<h2 id="heading-your-codetour-will-take-you-through-the-following-steps">Your CodeTour will take you through the following steps</h2>
<h4 id="heading-step-1-1">Step 1</h4>
<p>Introduction: Hi there! this is a guided tour to help you learn GitHub Copilot. We will build a rock, paper, scissors game with Python.</p>
<h4 id="heading-step-2-1">Step 2</h4>
<p>Let's give GitHub Copilot some context about what we're building. Write this comment <code># Write a rock, paper, scissors, game</code> at the top of your <a target="_blank" href="http://main.py">main.py</a> file.</p>
<p><img src="https://user-images.githubusercontent.com/22990146/222714683-d065c102-9b0c-4645-83d6-dfcf732d3b20.png" alt="Write a rock paper scissors game comment" /></p>
<p>Now, let's prompt Copilot to import the random module. Write this comment <code># import random module</code> on the next line. Press enter to create a new line and accept Copilot's suggestion.</p>
<p><img src="https://user-images.githubusercontent.com/22990146/222715309-72f40d08-e94f-438a-9719-cf0d14a2aebb.png" alt="Screen Shot 2023-03-03 at 6 58 46 AM" /></p>
<h4 id="heading-step-3-1">Step 3</h4>
<p>Now, let's prompt Copilot to create a main function that handles the logic of the game with a comment that says <code># define main function that handles all the logic</code>. Press enter to create a new line and accept Copilot's suggestion.</p>
<p><img src="https://user-images.githubusercontent.com/22990146/222715649-84631082-4771-4b5b-9236-9b396a7b313e.png" alt="define main function" /></p>
<h4 id="heading-step-4-1">Step 4</h4>
<p>Now, let's prompt Copilot to call the main function. Write this comment <code># call main function</code> on the next line. Press enter to create a new line and accept Copilot's suggestion.</p>
<p><img src="https://user-images.githubusercontent.com/22990146/222715869-176895c5-26bb-43a7-adb1-fe579064f689.png" alt="Call main function" /></p>
<h4 id="heading-step-5-1">Step 5</h4>
<p>Try it out! Let's run the code to see if it works. In your terminal, run <code>python3</code> <a target="_blank" href="http://main.py"><code>main.py</code></a>. It should start the rock, paper, scissors game. Mission complete! You've used GitHub Copilot to create a rock, paper, scissors game in Python!</p>
<p><img src="https://user-images.githubusercontent.com/22990146/222713921-70e04ad7-6522-4b28-8eea-819da728c3d0.png" alt="Playing the game in the terminal" /></p>
<h2 id="heading-do-you-have-feedback">Do you have feedback?</h2>
<p>Feel free to create an issue in the <a target="_blank" href="https://github.com/blackgirlbytes/rock-paper-scissors-copilot/">repo</a> or comment below!! There’s definitely room for improvement, as this is my first time using CodeTour to guide people through GitHub Copilot.</p>
<p>Follow GitHub and me for similar content about GitHub!</p>
]]></content:encoded></item><item><title><![CDATA[Securely store environment variables with GitHub Codespaces]]></title><description><![CDATA[As a developer advocate, I make a lot of demo projects to illustrate my talks or content. Also, as a chaotic person, I don’t do the best job at securely storing my environment variables during my demos. On more than one occasion, I’ve revealed my env...]]></description><link>https://blackgirlbytes.dev/securely-store-environment-variables-with-github-codespaces</link><guid isPermaLink="true">https://blackgirlbytes.dev/securely-store-environment-variables-with-github-codespaces</guid><category><![CDATA[GitHub]]></category><category><![CDATA[codespaces]]></category><category><![CDATA[github-codespaces]]></category><category><![CDATA[Cloud]]></category><category><![CDATA[Security]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Tue, 21 Feb 2023 16:45:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1676997910528/5128fbde-a6d8-4df2-8fb6-1853727c1d84.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As a developer advocate, I make a lot of demo projects to illustrate my talks or content. Also, as a chaotic person, I don’t do the best job at securely storing my environment variables during my demos. On more than one occasion, I’ve revealed my environment variables during a stream or a conference talk. Fortunately, developer friends like <a target="_blank" href="https://twitter.com/hi__mayank">Mayank</a> and <a target="_blank" href="https://twitter.com/nickytonline">Nick</a> introduced me to Cloak, a VS Code extension that hides the values of your environment variables if you accidentally share your screen.</p>
<p>I recently developed a small app that lives on the GitHub domain. Developing the application reminded me of all the struggles I used to have as a software engineer. (I don’t miss the stress of coding on a deadline). One of the struggles I encountered was sharing my environment variables with collaborators. I wanted my teammates to try out the app locally, so they could contribute code or review the user experience, but I wasn’t sure how to tell them to set up their environment variables securely.</p>
<ul>
<li><p>Do I share the environment variables in Slack? Nope, that is unsafe.</p>
</li>
<li><p>Do I share the variables in a password manager? Sure, but now some of the values are ill-formatted, i.e., RSA keys.</p>
</li>
</ul>
<p>Additional mishaps I’ve experienced in the past:</p>
<ul>
<li><p>I forgot to add my environment files to my .gitignore file, so I accidentally pushed my environment variables files to my repository.</p>
</li>
<li><p>I accidentally deleted my .env file and then had to generate new API tokens and secrets.</p>
</li>
</ul>
<p>I’m sure there are many solutions for securely storing environment variables in sandbox applications, but GitHub Codespaces worked best for me!</p>
<h2 id="heading-benefits-of-using-github-codespaces-for-environment-variables">Benefits of using GitHub Codespaces for environment variables</h2>
<p>The experience was seamless with GitHub Codespaces because it allowed repository collaborators to go to my repository, open the Codespace, and locally run the code. They didn’t have to fill in the values, so I didn’t have to share the secrets explicitly. Behind the scenes, GitHub Codespaces pulled the values from a store within the repository’s settings called Codespaces Secrets.</p>
<h2 id="heading-how-to-store-your-secrets-in-github-codespaces">How to store your secrets in GitHub Codespaces</h2>
<p>To illustrate this example, we will use the NASA API because it’s generally accessible to most developers.</p>
<h3 id="heading-step-1-generate-a-nasa-api-key">Step 1: Generate a NASA API key</h3>
<p>Fill out the form on <a target="_blank" href="https://api.nasa.gov/">https://api.nasa.gov/</a> to request an API key. You should receive the API key in your email. (Save this key because we will use it in step 5).</p>
<h3 id="heading-step-2-use-the-react-codespaces-template">Step 2: Use the React Codespaces template</h3>
<p><a target="_blank" href="https://docs.github.com/en/codespaces/getting-started/quickstart"><em>Quickstart templates</em></a> <em>include boilerplate code for some of the most common application frameworks, including Next.js, React.js, Django, Express, Ruby on Rails, Preact, Flask, and Jupyter Notebook. Templates provide developers with a sandbox to build, test, and debug applications in a codespace. This means you don’t have to start from scratch with coding. We already have a working project that you can enhance into the project you’re envisioning. You can use templates to understand how developers structure their projects written in various programming languages. And you can use it to understand how different files communicate with each other.</em></p>
<p><em>For example, I’ve always wanted to learn more about artificial intelligence and machine learning, but I had no clue where to start. I used a Jupyter Notebooks template to</em> <a target="_blank" href="https://dev.to/github/generate-ai-art-with-github-codespaces-59fc"><em>generate AI images</em></a><em>. The template already had all the tools I needed; I just had to change a few lines of code.</em></p>
<p>For this tutorial, we’ll navigate to <a target="_blank" href="https://github.com/codespaces/templates">https://github.com/codespaces/templates</a> and choose the React template.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u3j8107v51exma21ev1j.png" alt="List of Codespaces templates the react template is circled" /></p>
<h3 id="heading-step-3-wait-for-your-codespace-to-load">Step 3: Wait for your Codespace to load</h3>
<p>Once our codespace is fully loaded, you will see a live preview of your web app on a tab titled "Simple Browser." (If you don’t see the “Simple Browser” tab yet, give it a few minutes to load). It should look like the image below:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jt5mkd0shj34ib88ezin.png" alt="A codespace with that shows a file with code and another tab that shows the browser" /></p>
<h3 id="heading-step-4-publish-your-codespace">Step 4: Publish your Codespace</h3>
<p>We’re not done yet. Our main goal is to store and reference environment variables in a Codespace. However, we can only do this if our Codespace lives in a repository. To do this, we need to publish our Codespace. Take the following steps to publish the current Codespace:</p>
<ol>
<li><p>In a <strong>new tab</strong>, navigate to <a target="_blank" href="https://github.com/codespaces">https://github.com/codespaces</a>. Don’t worry about leaving the tab or window because Codespaces will save your changes.</p>
</li>
<li><p>Scroll down to the bottom of the page, and you will see the Codespace you created. It might have a silly name. GitHub Codespace automatically generates names for each Codespace as a form of identification. My Codespace is named “ubiquitous acorn.”</p>
</li>
</ol>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uoirm0z5urlx8i9n0esq.png" alt="listed codespace" /></p>
<ol>
<li>Click the three dots on the right-hand side and choose the option “Publish to new repository.”</li>
</ol>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/87exz0glrwes0ypsizzs.png" alt="Highlighting publish to new repository button" /></p>
<ol>
<li>Here, you can give your project a more identifiable name, make the project public, and view your repository with the button “See repository.”</li>
</ol>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k7ars2mfudycsuntfqxi.png" alt="Highlighting button that says see repository" /></p>
<ol>
<li>This will lead you to your repository on GitHub. It will show the different files within the project, too. You can share the link to your repository for other developers to collaborate with you or explore your codebase!</li>
</ol>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aa21viooxp1n72pk65es.png" alt="View of a repository with files in it" /></p>
<h3 id="heading-step-5-store-your-environment-variables">Step 5: Store your environment variables</h3>
<p>In your new repository, navigate to Settings &gt; Secrets and variables &gt; Codespaces. You can also find the correct page by navigating to a URL that looks like this: ​​<a target="_blank" href="https://github.com/REPLACE_WITH_GITHUB_OWNER/REPLACE_WITH_GITHUB_REPO/settings/secrets/codespaces"><code>https://github.com/REPLACE_WITH_GITHUB_OWNER/REPLACE_WITH_GITHUB_REPO/settings/secrets/codespaces</code></a></p>
<p>The page you land on should look like the image below:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6z2j9eda2uiu6o7d4dy7.png" alt="View of Codespace secrets store" /></p>
<p>Let’s create two repository secrets:</p>
<ul>
<li><p><code>REACT_APP_NASA_ENDPOINT=</code><a target="_blank" href="https://api.nasa.gov/"><code>https://api.nasa.gov/</code></a></p>
</li>
<li><p><code>REACT_APP_NASA_API_KEY= This is where you will add your NASA API key</code></p>
</li>
</ul>
<p>Now, we can refer to these variables in our codebase using the convention: <code>process.env.{ENVIRONMENT_VARIABLE_NAME}</code></p>
<h3 id="heading-step-6-reload-your-codespace">Step 6: Reload your Codespace</h3>
<p>Once you add the new API keys, your Codespace should “automagically” recognize that you added new secrets to your Codespace. If so, a notification will pop up in your Codespace that says, “Your codespace secrets have changed. Reload to apply.”</p>
<p>Press the “Reload to apply” button for the changes to take effect.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j8en61dbq89mfpvua6ov.png" alt="Reload to apply button" /></p>
<h3 id="heading-step-7-install-axios">Step 7: Install axios</h3>
<p>Axios is the npm package we’ll use to make calls to the NASA API. Run this command in your Codespace’s terminal to install axios:</p>
<p><code>npm install --save axios</code></p>
<h3 id="heading-step-8-create-a-new-file">Step 8: Create a new file</h3>
<p>(I used Wayne Fornworth’s <a target="_blank" href="https://medium.com/swlh/react-nasa-api-app-5340d0faf00c">blog post</a> on Medium for this step. I’ve used the NASA API in the past, but I felt a little lazy while building this out. Thank you, Wayne, for your blog post! )</p>
<p>Create a file in your src directory called, <code>HttpClient.js</code> then add the following lines of code to that file:</p>
<p>(Note: Lines 2 and 3 refer to the secrets we created by using <code>process.env.{ENVIRONMENT_VARIABLE_NAME}</code> )</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>

<span class="hljs-keyword">const</span> nasaEndpoint = process.env.REACT_APP_NASA_ENDPOINT
<span class="hljs-keyword">const</span> nasaApiKey = process.env.REACT_APP_NASA_API_KEY

axios.interceptors.request.use(
  <span class="hljs-function"><span class="hljs-params">config</span> =&gt;</span> {
    config.params = config.params ? config.params : {}
    <span class="hljs-keyword">const</span> configUrl = config.url
    <span class="hljs-keyword">if</span> (configUrl.includes(nasaEndpoint)) {
      config.params[<span class="hljs-string">"api_key"</span>] = nasaApiKey
    }

    <span class="hljs-keyword">return</span> config
  },
  <span class="hljs-function"><span class="hljs-params">error</span> =&gt;</span> {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.reject(error)
  }
)

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  getApod() {
    <span class="hljs-keyword">return</span> axios.get(<span class="hljs-string">`<span class="hljs-subst">${nasaEndpoint}</span>planetary/apod`</span>)
  },
}
</code></pre>
<h3 id="heading-step-9-update-your-appjs-file">Step 9: Update your App.js file</h3>
<p>Delete the current contents of your <code>src/App.js file</code> and replace it with the following lines of code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> React, { useState, useEffect } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> HttpClient <span class="hljs-keyword">from</span> <span class="hljs-string">"./HttpClient"</span>

<span class="hljs-keyword">const</span> App = <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-keyword">const</span> [apod, setApod] = useState({})

  useEffect(<span class="hljs-function">() =&gt;</span> {
    HttpClient.getApod().then(<span class="hljs-function"><span class="hljs-params">apodData</span> =&gt;</span> {
      setApod(apodData.data)
    })
  }, [])

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">maxWidth:</span> <span class="hljs-attr">900</span>, <span class="hljs-attr">padding:</span> <span class="hljs-attr">30</span> }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>NASA API<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">h2</span>&gt;</span>Astronomy Picture of the Day<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
      {apod &amp;&amp; (
        <span class="hljs-tag">&lt;<span class="hljs-name">article</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">header</span>&gt;</span>
            {apod.title} - <span class="hljs-tag">&lt;<span class="hljs-name">i</span>&gt;</span>{apod.date}<span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">header</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">{apod.url}</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">"APOD"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"800"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"auto"</span> /&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>{apod.explanation}<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">pre</span>
            <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span>
              <span class="hljs-attr">overflowX:</span> "<span class="hljs-attr">auto</span>",
              <span class="hljs-attr">whiteSpace:</span> "<span class="hljs-attr">pre-wrap</span>",
              <span class="hljs-attr">wordWrap:</span> "<span class="hljs-attr">break-word</span>",
            }}
          &gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">hr</span> /&gt;</span>
            {JSON.stringify(apod, null, 2)}
          <span class="hljs-tag">&lt;/<span class="hljs-name">pre</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">article</span>&gt;</span>
      )}
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App
</code></pre>
<h3 id="heading-step-10-check-out-your-creation">Step 10: Check out your creation</h3>
<p>If successful, your simple browser tab should render an image similar to the one below:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ps5mv0u0e7jafhwdldxu.png" alt="web browser page with the NASA picture of the day" /></p>
<h3 id="heading-step-11-make-it-accessible-to-others">Step 11: Make it accessible to others!</h3>
<p>Anyone can open your Codespace, but the environment variables will not work for everyone. For folks to see the same results (as in, for the API call to work), you’ll need to add the users as repository collaborators. If they are not repository collaborators, they will say page with a broken image instead. Check out the <a target="_blank" href="https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-personal-account-on-github/managing-access-to-your-personal-repositories/inviting-collaborators-to-a-personal-repository">GitHub documentation</a> to learn how to add collaborators to your repository.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/85i9h5sl3hz6hkjufqux.png" alt="Collaborators tab for the repository" /></p>
<h3 id="heading-things-to-remember">Things to remember</h3>
<ul>
<li><p>This is an API call for the NASA Astronomy Picture of the Day, so the image may vary depending on the day that you make this API call. The picture in the image above is for the date .</p>
</li>
<li><p>Now, if someone with repository collaborator access opens your repository in a Codespace, they can get the same results without filling in environment variables because you already stored the correct values in your repository’s Codespaces secrets.</p>
</li>
<li><p>Take a look at my <a target="_blank" href="https://github.com/blackgirlbytes/nasa-api-storing-env-vars">repository</a> to double check your code. Please remember that if you open this repository in a Codespace, you will see a broken web page because you’re not a collaborator of the repository.</p>
</li>
<li><p><strong>This method works best for local development within a Codespace. If you deploy the code to another environment, you’ll need to define the environment variables using the suggested method of your server provider.</strong></p>
</li>
<li><p>You can use secrets in a codespace after the codespace is built and running. For example, a secret can be used:</p>
<ul>
<li><p>When launching an application from the integrated terminal or ssh session.</p>
</li>
<li><p>Within a dev container lifecycle script that is run after the codespace is running. For more information about dev container lifecycle scripts, see the documentation on the Development Containers website: <a target="_blank" href="https://containers.dev/implementors/json_reference/#lifecycle-scripts">Specification</a>.</p>
</li>
</ul>
</li>
<li><p>Codespace secrets cannot be used:</p>
<ul>
<li><p>During codespace build time (that is, within a Dockerfile or custom entry point).</p>
</li>
<li><p>Within a dev container feature. For more information, see the features property in the dev <a target="_blank" href="https://containers.dev/implementors/json_reference/#general-properties">containers specification</a> on the Development Containers website.</p>
</li>
</ul>
</li>
</ul>
<p><em>Hope this helps! If you liked this post, follow</em> <a target="_blank" href="https://dev.to/github"><em>GitHub</em></a> <em>and</em> <a target="_blank" href="https://dev.to/blackgirlbytes"><em>me</em></a> <em>for more content!</em></p>
]]></content:encoded></item><item><title><![CDATA[Could GitHub Copilot be a valuable investment for my team?]]></title><description><![CDATA[GitHub recently launched Copilot for Business, which enables companies to purchase and manage licenses for their entire team. If you're considering investing in GitHub Copilot, here's what you need to know.
Short answer: Yes, GitHub Copilot could be ...]]></description><link>https://blackgirlbytes.dev/could-github-copilot-be-a-valuable-investment-for-my-team</link><guid isPermaLink="true">https://blackgirlbytes.dev/could-github-copilot-be-a-valuable-investment-for-my-team</guid><category><![CDATA[GitHub]]></category><category><![CDATA[github copilot]]></category><category><![CDATA[Artificial Intelligence]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[copilot for business]]></category><dc:creator><![CDATA[Rizel Scarlett]]></dc:creator><pubDate>Tue, 21 Feb 2023 16:43:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1676075159000/a637c537-df06-40a4-86a9-eab73233278a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>GitHub recently launched <a target="_blank" href="https://github.blog/2022-12-07-github-copilot-is-generally-available-for-businesses/">Copilot for Business</a>, which enables companies to purchase and manage licenses for their entire team. If you're considering investing in <a target="_blank" href="https://github.com/features/copilot">GitHub Copilot</a>, here's what you need to know.</p>
<p><strong>Short answer:</strong> Yes, GitHub Copilot could be a valuable investment for your team.</p>
<p><strong>Long answer:</strong> It depends on your team's specific needs.</p>
<p>I’ll start by admitting that I am biased. I work at GitHub, and I love Copilot. GitHub Copilot helped me rediscover the joy of coding. I used to love coding. Then, I experienced burnout and imposter syndrome, and I struggled with opening my code editor. However, besides those two factors, I think GitHub Copilot solves a shared problem for developers and business stakeholders: speed.</p>
<h2 id="heading-the-problem-with-speed-in-software-development">The problem with speed in software development</h2>
<p>Businesses need to make money to survive, pay their employees, and continue paying for the technology that supports their applications. Investors expect a return on investment, and customers expect features that meet their needs. In an ideal world, software developers would have the time and resources to write, test, refactor, and deploy code at their own pace. But the reality is that businesses need features delivered quickly. This can lead to pressure on software developers to move faster, but to the non-developers it can feel like software developers aren’t moving fast enough.</p>
<h2 id="heading-why-are-software-engineers-taking-so-long-to-code">Why are software engineers taking so long to code?</h2>
<p>Coding is hard. Software developers face numerous challenges, such as:</p>
<ul>
<li><p>Estimating the time it will take to complete a task</p>
</li>
<li><p>Envisioning all the problems they may encounter while coding</p>
</li>
<li><p>Being asked to complete a task quickly without understanding the complexity involved</p>
</li>
</ul>
<p>Many times in my career, non-developers like salespeople or product managers have told me, “Here’s the feature we want, but it shouldn’t take you too long.” <em>Spoiler alert: I hate to admit it, but it always takes me longer than expected.</em> Sometimes, it may seem like I just have to update one word or change one picture. However, the request might mean I have to venture into an unfamiliar part of the codebase, learn a new tool, or make a change that could potentially disrupt the entire system. I come from the startup world where we’ve adopted the “Move fast and break things” motto, so my software development process often looks like this:</p>
<ul>
<li><p>Researching possibilities</p>
</li>
<li><p>Designing the feature</p>
</li>
<li><p>Reading documentation</p>
</li>
<li><p>Starting to code while referring to documentation</p>
</li>
<li><p>Realizing that the initial plan won't work and starting over</p>
</li>
<li><p>Adding workarounds to meet the deadline</p>
</li>
<li><p>Rushed testing and deployment</p>
</li>
<li><p>Fixing bugs after the code breaks in production</p>
</li>
</ul>
<p>This cycle of coding, testing, and fixing can lead to burnout and decreased motivation to continue building skills and contributing to the company's success.</p>
<h2 id="heading-what-do-software-developers-want">What do software developers want?</h2>
<p>Software developers want to feel valued and have the opportunity to continue building their skills. Improving skills can mean watching educational content, building side projects, attending conferences, and more. However, with a heavy workload, finding time to do anything outside of work-related tasks can be challenging. (Yes, many companies provide 10% learning time as a benefit, but it feels like a formality. It’s hard to use this benefit when the engineer’s learning time is not accounted for during the sprint.)</p>
<p>When I’m unable to build my skills, and I feel like there aren’t enough hours in a day, I start fantasizing about working at a different company. <em>Is there a company where coding doesn’t feel stressful, and I’ll feel motivated to learn, blog, build my career, and still maintain a healthy work-life balance?</em></p>
<h2 id="heading-enter-github-copilot">Enter GitHub Copilot</h2>
<p>GitHub Copilot helps software developers write code faster by reducing the time spent sifting through documentation, writing boilerplate code, and trying to remember syntax. With GitHub Copilot, software developers can have more time to focus on their passion for coding, which helps businesses retain investors, customers, and most importantly, software developers. (Yes, you can always replace software developers, but software developers with legacy knowledge of the codebase are invaluable to a company’s success.)</p>
<h2 id="heading-examples-of-github-copilots-positive-impact-on-developers">Examples of GitHub Copilot’s positive impact on developers</h2>
<h3 id="heading-less-time-reading-documentation">Less time reading documentation</h3>
<p>In the example below, <a target="_blank" href="https://twitter.com/chris__sev">Chris Sev</a> explains that instead of spending too much time reading documentation and context-switching, GitHub Copilot led him in the right direction.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/chris__sev/status/1623452869516042241?s=20">https://twitter.com/chris__sev/status/1623452869516042241?s=20</a></div>
<p> </p>
<h3 id="heading-less-time-writing-boilerplate-code">Less time writing boilerplate code</h3>
<p>In the example below, <a target="_blank" href="https://twitter.com/kelseyhightower">Kelsey Hightower</a> used GitHub Copilot to handle writing boilerplate code.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/kelseyhightower/status/1617684526448402434">https://twitter.com/kelseyhightower/status/1617684526448402434</a></div>
<p> </p>
<h3 id="heading-less-time-recalling-syntax">Less time recalling syntax</h3>
<p>We all forget syntax sometimes. Memorizing code is not the best use of anyone’s type. In the example below, GitHub Copilot helps <a target="_blank" href="https://twitter.com/lisa_reiber">Lisa Reiber</a> focus on the logic rather than the syntax.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://twitter.com/lisa_reiber/status/1621529827416375296">https://twitter.com/lisa_reiber/status/1621529827416375296</a></div>
<p> </p>
<h3 id="heading-bonus-writing-code-is-more-accessible">Bonus: Writing code is more accessible</h3>
<p>As an industry, we’re learning to prioritize accessibility for the user. But, what about the developer? The <a target="_blank" href="https://githubnext.com/">GitHub Next</a> team is making coding more accessible for developers of all backgrounds with the following experimental features:</p>
<ul>
<li><p><a target="_blank" href="https://githubnext.com/projects/hey-github/">Hey, GitHub</a> - a voice-activated AI programmer that allows you to code hands-free</p>
</li>
<li><p><a target="_blank" href="https://githubnext.com/projects/copilot-cli/">GitHub Copilot CLI</a> - GitHub Copilot assistance in the terminal</p>
</li>
<li><p><a target="_blank" href="https://githubnext.com/projects/copilot-labs/">GitHub Copilot Labs</a> - provides an explanation of code snippets in your codebase</p>
</li>
</ul>
<p>As someone who struggles with impostor syndrome and anxiety (as many developers do), GitHub Copilot gives me an extra boost of confidence and reassurance that I’m going in the right direction.</p>
<p>Additionally, I’ve noticed that GitHub Copilot can understand other spoken languages. Code is American-English centric, which can be a barrier to non-English speaking software engineers. If you write a comment in a non-native language like Spanish or German, GitHub Copilot can still suggest code to help developers build applications.</p>
<h2 id="heading-will-copilot-steal-my-companys-code">Will Copilot steal my company's code?</h2>
<p>With Copilot for Business, GitHub won’t retain code snippets, store, or share your code regardless if the data is from public repositories, private repositories, non-GitHub repositories, or local files.</p>
<p>Additionally, GitHub built a <a target="_blank" href="https://docs.github.com/en/copilot/configuring-github-copilot/configuring-github-copilot-settings-on-githubcom">filter</a> to help detect and suppress GitHub Copilot suggestions that contain code that matches public code on GitHub.</p>
<p>For more information on privacy and fairness around GitHub Copilot, check out the <a target="_blank" href="https://github.com/features/copilot">features</a> page and scroll down to the FAQ section.</p>
<h2 id="heading-learn-more">Learn more</h2>
<p>Whether or not GitHub Copilot is a valuable investment for your team depends on your team's specific needs. However, it’s worth considering.</p>
<p>You can learn more about how GitHub Copilot increases developer happiness and productivity by checking out the following posts:</p>
<ul>
<li><p><a target="_blank" href="https://github.blog/2021-06-30-github-copilot-research-recitation/">GitHub Copilot Research Recitation</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2022-07-14-research-how-github-copilot-helps-improve-developer-productivity/">How GitHub Copilot helps improve developer productivity</a></p>
</li>
<li><p><a target="_blank" href="https://github.blog/2022-09-14-8-things-you-didnt-know-you-could-do-with-github-copilot/">8 things you didn’t know you could do with GitHub Copilot</a></p>
</li>
</ul>
]]></content:encoded></item></channel></rss>