<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Victoria Drake - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Victoria Drake - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 14 May 2026 04:32:28 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/author/victoriadrake/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Future-Proof Your Software Engineering Career for the Age of AGI ]]>
                </title>
                <description>
                    <![CDATA[ In the viral essay The Decade Ahead, Leopold Aschenbrenner predicts that Artificial General Intelligence (AGI) will be a reality in only a few years. But what exactly is AGI, and how does it differ from the AI we have today? AGI refers to a type of a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-future-proof-your-software-engineering-career-for-the-age-of-agi/</link>
                <guid isPermaLink="false">66c914aff938d5f8e0587406</guid>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Career ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Fri, 23 Aug 2024 23:01:03 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724267267326/85a8c7ec-bc36-4d93-9ba1-b5410859d2a4.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the viral essay <em>The Decade Ahead</em>, Leopold Aschenbrenner predicts that Artificial General Intelligence (AGI) will be a reality in only a few years. But what exactly is AGI, and how does it differ from the AI we have today?</p>
<p>AGI refers to a type of artificial intelligence that has the ability to understand, learn, and apply knowledge across a wide range of tasks at a level comparable to, or even beyond, human intelligence.</p>
<p>Unlike narrow AI, which excels at specific tasks (like image recognition or playing chess), AGI would be able to perform any cognitive task that a human can, adapt to new situations, and improve its capabilities over time without human intervention.</p>
<p>The emergence of AGI would fundamentally change how we think about and interact with technology. For engineers, it means preparing for a world where intelligent systems can perform tasks autonomously, requiring new skills and approaches to software development.</p>
<p>Here are some key areas of work you can focus on now to help prepare you for the AGI era.</p>
<h2 id="heading-1-mastering-machine-learning-and-deep-learning">1. Mastering Machine Learning and Deep Learning</h2>
<p>Engineers with expertise in these fields will be at the forefront of AGI development. Machine learning and deep learning are the building blocks of AGI, as they enable systems to learn from data, identify patterns, and make decisions.</p>
<p>To prepare for AGI, you need to go beyond the basics of supervised learning and explore more advanced areas like reinforcement learning, where agents learn by interacting with their environment, and unsupervised learning, which allows systems to find hidden patterns in data without explicit guidance. Neural networks, particularly deep neural networks, will play a critical role in enabling AGI to generalize across tasks.</p>
<p>Why should you learn these skills? AGI will require systems that can adapt and improve autonomously. Mastering these skills will help you understand how to create models that can handle complex, unstructured data and make decisions in real-time, which is essential for AGI.</p>
<h3 id="heading-how-to-prepare">How to prepare</h3>
<ul>
<li><p><strong>Take courses:</strong> Consider taking advanced courses on platforms like freeCodeCamp, Coursera, edX, or Udacity that focus on <a target="_blank" href="https://www.freecodecamp.org/news/intro-to-advanced-actor-critic-methods-reinforcement-learning-course/">reinforcement learning</a>, <a target="_blank" href="https://www.freecodecamp.org/news/self-driving-car-javascript/">neural networks</a>, and <a target="_blank" href="https://www.freecodecamp.org/news/deep-learning-course-math-and-applications/">deep learning</a>.</p>
</li>
<li><p><strong>Build projects:</strong> Build your own machine learning models and experiment with different types of data. Participating in Kaggle competitions can also help you hone your skills.</p>
</li>
<li><p><strong>Job titles to watch:</strong> Machine Learning Engineer, AI Research Scientist.</p>
</li>
</ul>
<h2 id="heading-2-software-engineering-with-a-focus-on-ai-integration">2. Software Engineering with a Focus on AI Integration</h2>
<p>Traditional software engineering roles will evolve to integrate AI components seamlessly. This means developing frameworks that allow AGI to be incorporated into existing systems or creating entirely new systems designed around AGI capabilities.</p>
<p>What does this look like? Engineers might develop APIs that allow AGI to communicate with other software, create microservices that enable modular AGI deployment, or design platforms that facilitate continuous learning for AGI systems.</p>
<p>For example, integrating AGI into a customer service platform could involve building an interface where AGI handles complex queries while human agents focus on more nuanced tasks.</p>
<h3 id="heading-how-to-prepare-1">How to prepare</h3>
<ul>
<li><p><strong>Study:</strong> Learn how to design and implement AI components in software through courses and hands-on experience. Understanding cloud-based AI services like AWS SageMaker or Google AI Platform will also be beneficial.</p>
</li>
<li><p><strong>Practice:</strong> Work on projects where you integrate AI models into existing applications, such as adding a chatbot to a web service or incorporating predictive analytics into a mobile app.</p>
</li>
<li><p><strong>Job titles to watch:</strong> Full Stack Developer with AI specialization, AI Software Engineer.</p>
</li>
</ul>
<h2 id="heading-3-navigating-ethics-and-ai-governance">3. Navigating Ethics and AI Governance</h2>
<p>As AGI could pose significant ethical and governance challenges, roles focusing on the ethical implications, policy-making, and regulatory compliance will be crucial. This includes ensuring AGI systems operate within legal and ethical frameworks. Public as well as private sector experience will be valuable.</p>
<p>Key ethical concerns include issues like accuracy, accountability, and transparency. You can benefit from developing skills in critical thinking and understanding how to interpret data and statistics. These skills can be helpful when collaborating with policymakers.</p>
<h3 id="heading-how-to-learn">How to learn</h3>
<ul>
<li><p><strong>Read up:</strong> Explore literature on how policy is formed at the institutional and governmental level.</p>
</li>
<li><p><strong>Take courses:</strong> Consider taking courses on statistics and ethics to grow a deeper understanding of model results. Here's one on the <a target="_blank" href="https://www.freecodecamp.org/news/the-ethics-of-ai-and-ml/">ethics of AI and ML</a> for starters.</p>
</li>
<li><p><strong>Job titles to watch:</strong> AI Ethics Analyst, Policy Advisor for AI, Compliance Officer for AI Systems.</p>
</li>
</ul>
<h2 id="heading-4-evolving-human-computer-interaction-hci">4. Evolving Human-Computer Interaction (HCI)</h2>
<p>HCI will quickly transform into Human-AI Interaction Design. As AGI systems become more prevalent, they will need to interact with humans in intuitive and seamless ways. Companies will need interfaces where humans can interact with AGI systems effectively, built by engineers who understand cognitive psychology and UX/UI design for AI systems.</p>
<p>Engineers will need to design interfaces where AGI can explain its decisions, ask for clarification when needed, and understand human emotions and context.</p>
<p>For example, AGI in healthcare might need to provide doctors with explanations of its diagnoses while considering the doctor's expertise and the patient's emotions. Building skills in designing intuitive interfaces and interactions between humans and intelligent systems will help you to be highly successful in AGI integration.</p>
<h3 id="heading-how-to-prepare-2">How to prepare</h3>
<ul>
<li><p><strong>Take courses:</strong> Study HCI and UX design with a focus on AI systems. Platforms like Interaction Design Foundation and Coursera offer relevant courses.</p>
</li>
<li><p><strong>Build projects:</strong> Experiment with designing user interfaces for AI-powered applications. This could include developing conversational agents or creating dashboards that visualize AI decision-making processes.</p>
</li>
<li><p><strong>Job titles to watch:</strong> Interaction Designer for AI, User Experience Researcher for AI Systems.</p>
</li>
</ul>
<h2 id="heading-5-enhancing-autonomous-systems-and-robotics">5. Enhancing Autonomous Systems and Robotics</h2>
<p>If AGI leads to more autonomous robots, engineers who can design, build, and program robots with AGI capabilities will be in demand. This includes understanding how AGI can enhance robotic functionality.</p>
<p>AGI has the potential to revolutionize autonomous systems and robotics by enabling machines to learn and adapt in real-time. This could lead to more advanced self-driving cars, drones, and robots that can perform complex tasks without human intervention.</p>
<p>AGI could allow robots to understand and navigate unstructured environments, learn from experience, and collaborate with humans more effectively. For example, an AGI-powered robot could assist in disaster relief by autonomously adapting to changing conditions and coordinating with human teams.</p>
<p>Working on autonomous systems, whether in robotics, self-driving vehicles, or drones, can provide practical experience with highly independent systems. These skills will be transferrable to managing and optimizing AGI-based autonomous agents.</p>
<h3 id="heading-how-to-prepare-3">How to prepare</h3>
<ul>
<li><p><strong>Take courses:</strong> Take robotics courses that cover autonomous systems, <a target="_blank" href="https://www.freecodecamp.org/news/how-to-use-tensorflow-for-computer-vision/">computer vision</a>, and AI integration.</p>
</li>
<li><p><strong>Build projects:</strong> Work on robotics projects, such as building an autonomous vehicle or programming a robot to perform complex tasks.</p>
</li>
<li><p><strong>Job titles to watch:</strong> Robotics Engineer, Automation Specialist.</p>
</li>
</ul>
<h2 id="heading-6-pioneering-hardware-development-for-agi">6. Pioneering Hardware Development for AGI</h2>
<p>We'll need engineers working on specialized hardware that can support AGI. Technologies like neuromorphic computing chips or quantum computing might be necessary for the computational power AGI would require.</p>
<p>Neuromorphic computing involves designing chips that replicate the structure and function of the human brain's neurons and synapses. These chips could enable more efficient and powerful AI systems by processing information in ways that are closer to how the human brain works. Also, quantum computing could provide the processing power needed for AGI's complex calculations.</p>
<h3 id="heading-how-to-prepare-4">How to prepare</h3>
<ul>
<li><p><strong>Study:</strong> Learn about neuromorphic computing and quantum computing through specialized courses and research papers. Staying updated with developments from companies like IBM and Intel, which are working on neuromorphic chips, can also be helpful.</p>
</li>
<li><p><strong>Build projects:</strong> Experiment with hardware design, such as working with FPGAs (Field Programmable Gate Arrays) or exploring quantum computing platforms like IBM Q.</p>
</li>
<li><p><strong>Job titles to watch:</strong> Hardware Engineer for AI, Quantum Computing Engineer.</p>
</li>
</ul>
<h2 id="heading-7-securing-the-future-cybersecurity-for-agi">7. Securing the Future: Cybersecurity for AGI</h2>
<p>AGI systems will introduce new security challenges. Engineers with expertise in cybersecurity will be in high demand to protect AGI systems from national security threats, ensure data privacy, and secure AI-driven decision-making processes against manipulation. There are also concerns about data privacy, as AGI systems will likely handle sensitive information across various domains.</p>
<h3 id="heading-how-to-prepare-5">How to prepare</h3>
<ul>
<li><p><strong>Take courses:</strong> Take cybersecurity courses focused on AI and machine learning security. Platforms like freeCodeCamp, Cybrary, and Coursera offer relevant courses. <a target="_blank" href="https://www.freecodecamp.org/news/ai-and-cybersecurity-handbook/">Here's a handbook</a> that has some helpful insights, too.</p>
</li>
<li><p><strong>Practice:</strong> Engage in cybersecurity challenges, such as Capture the Flag (CTF) competitions, to develop hands-on skills in securing computing systems.</p>
</li>
<li><p><strong>Job titles to watch:</strong> AI Security Specialist, Cybersecurity Analyst for AI.</p>
</li>
</ul>
<h2 id="heading-8-data-engineering-fueling-agi-with-information">8. Data Engineering: Fueling AGI with Information</h2>
<p>Handling large-scale data systems will be critical for AGI, as it will require vast amounts of data to learn and operate effectively. Data engineers will play a crucial role in building and maintaining the infrastructure that feeds AGI with the information it needs.</p>
<p>Data engineers will need expertise in big data technologies, such as Hadoop and Spark, and real-time data processing systems, like Apache Kafka. They will also need to ensure data quality and integrity, as AGI systems will rely heavily on accurate and comprehensive data to function effectively.</p>
<p>How will data engineers work with AGI systems? Data engineers will design data pipelines that can handle the immense scale of data AGI requires. This includes everything from data ingestion, storage, processing, and ensuring that the data is of high quality and usable for AGI models. They'll also need to implement systems for continuous data updates, enabling AGI to learn and adapt in real-time.</p>
<h3 id="heading-how-to-prepare-6">How to prepare</h3>
<ul>
<li><p><strong>Take courses:</strong> Take courses on big data technologies, data pipeline architecture, and real-time data processing. Platforms like freeCodeCamp, Udemy, and Coursera offer courses on tools like <a target="_blank" href="https://www.freecodecamp.org/news/apache-kafka-handbook/">Apache Kafka</a>, Spark, and Hadoop.</p>
</li>
<li><p><strong>Projects:</strong> Work on projects that involve large-scale data processing and pipeline development. Contributing to open-source big data projects can also be a great way to gain experience.</p>
</li>
<li><p><strong>Job titles to watch:</strong> Data Engineer, Big Data Architect.</p>
</li>
</ul>
<h2 id="heading-9-building-infrastructure-for-agi">9. Building Infrastructure for AGI</h2>
<p>AGI will require robust and scalable infrastructure on a never-before-seen scale. Engineers with experience in cloud computing, distributed systems, and infrastructure as code (IaC) will be crucial in building the systems that support AGI.</p>
<p>AGI systems will likely operate on a global scale, requiring vast amounts of computational power and data storage. Engineers will need to design cloud-based infrastructure that can scale dynamically, handle high volumes of data, and ensure low latency for real-time processing. They will also need to consider the security and reliability of these systems.</p>
<h3 id="heading-how-to-prepare-7">How to prepare</h3>
<ul>
<li><p><strong>Take courses:</strong> Study <a target="_blank" href="https://www.freecodecamp.org/news/search?query=aws">cloud computing platforms</a> like AWS, Google Cloud, or Microsoft Azure. Learning about distributed systems and IaC tools like <a target="_blank" href="https://www.freecodecamp.org/news/learn-terraform-and-aws-by-building-a-dev-environment/">Terraform</a> and Ansible will also be beneficial.</p>
</li>
<li><p><strong>Obtain certifications:</strong> Earning certifications in cloud architecture (like the AWS Certified Solutions Architect) can help solidify your knowledge. freeCodeCamp has many free courses to help you study for AWS certs – <a target="_blank" href="https://www.freecodecamp.org/news/ultimate-aws-certified-developer-associate-dva-c02-course-from-andrew-brown/">like this one</a>.</p>
</li>
<li><p><strong>Build projects:</strong> Work on setting up and managing cloud infrastructure for applications, experimenting with scalability and load balancing.</p>
</li>
<li><p><strong>Job titles to watch:</strong> Cloud Infrastructure Engineer, Systems Architect for AI.</p>
</li>
</ul>
<h2 id="heading-10-cross-disciplinary-collaboration-in-the-agi-era">10. Cross-Disciplinary Collaboration in the AGI Era</h2>
<p>Working in roles that involve cross-disciplinary collaboration, such as roles in research or innovation labs, can provide engineers with the ability to think broadly and integrate knowledge from various fields. Knowledge in other fields can give you the ability to engineer products that help people in a niche you care about.</p>
<p>Combining skills from fields such as biology (for bioinformatics or synthetic biology with AGI) and psychology (for understanding human-AI interaction) will be vital in the AGI era. Engineers who can think broadly and collaborate across disciplines will be better equipped to tackle complex problems that require diverse perspectives. For instance, combining AGI with neuroscience could advance brain-computer interfaces.</p>
<h3 id="heading-how-to-prepare-8">How to prepare</h3>
<ul>
<li><p><strong>Networking:</strong> Engage with professionals from different fields by attending interdisciplinary conferences and joining relevant online communities.</p>
</li>
<li><p><strong>Take courses:</strong> Take courses or workshops in complementary fields, such as biology, psychology, or environmental science, to broaden your understanding. Here's a <a target="_blank" href="https://www.freecodecamp.org/news/python-for-bioinformatics-use-machine-learning-and-data-analysis-for-drug-discovery/">course on bioinformatics</a> if you're curious.</p>
</li>
<li><p><strong>Build projects:</strong> Collaborate on interdisciplinary projects, such as developing AI models that incorporate insights from other domains.</p>
</li>
<li><p><strong>Job titles to watch:</strong> Bioinformatics Engineer, Environmental Data Scientist.</p>
</li>
</ul>
<h2 id="heading-11-education-and-training-for-an-agi-ready-workforce">11. Education and Training for an AGI-Ready Workforce</h2>
<p>As AGI transforms industries, there will be a growing need for educational programs that teach engineers how to work with AGI systems.</p>
<p>Education and training programs should cover a range of topics, from yet-undeveloped AGI techniques, safety protocols, policy-making, to interdisciplinary collaboration. Preparation for creating or leading education in AGI means becoming a continuous learner yourself. Also, training should emphasize lifelong learning, as AGI technology will continue to evolve rapidly.</p>
<h3 id="heading-how-to-prepare-9">How to prepare</h3>
<ul>
<li><p><strong>Create content:</strong> If you're an educator, consider developing courses or workshops focused on AGI-related topics. Collaborate with industry experts to ensure the content is relevant and up-to-date.</p>
</li>
<li><p><strong>Enroll in programs:</strong> Participate in advanced AI or AGI training programs, either through universities or industry-led initiatives. Stay updated with emerging trends by attending seminars and conferences.</p>
</li>
<li><p><strong>Job titles to watch:</strong> AI Curriculum Developer, Training Specialist for AI Technologies.</p>
</li>
</ul>
<h2 id="heading-12-shaping-regulations-in-an-agi-driven-world">12. Shaping Regulations in an AGI-Driven World</h2>
<p>Engineers working on regulatory technology (RegTech) will gain insight into compliance and governance, which will be critical as AGI evolves within legal frameworks. Understanding how to navigate and shape regulations will be vital.</p>
<p>Regulations could cover areas such as data privacy, transparency, accountability, and the use of AGI in various industries. Engineers working in this field will need to collaborate with policymakers, legal experts, and industry leaders to develop guidelines that balance innovation with responsibility.</p>
<h3 id="heading-how-to-prepare-10">How to prepare</h3>
<ul>
<li><p><strong>Study:</strong> Stay informed about current AI regulations and legal frameworks. If you're interested, consider pursuing a certification or degree in law or public policy with a focus on AI governance.</p>
</li>
<li><p><strong>Networking:</strong> Join industry groups like IEEE or think tanks that focus on AI policy and ethics. Engaging in discussions with policymakers can provide valuable insights into the regulatory landscape.</p>
</li>
<li><p><strong>Job titles to watch:</strong> Regulatory Engineer, Compliance Specialist for AI.</p>
</li>
</ul>
<h2 id="heading-13-research-and-development-rampd-in-agi-related-areas">13. Research and Development (R&amp;D) in AGI-related Areas</h2>
<p>Finally, engineers who are involved in cutting-edge research in AGI, cognitive computing, or advanced AI labs will be directly contributing to and understanding the frontiers of AGI technology, giving them a head start in a world where AGI is a reality. These roles offer the opportunity to shape the future of AGI and explore new possibilities in artificial intelligence.</p>
<p>Get involved in R&amp;D by joining research institutions, universities, or tech companies that focus on AGI development. Contributing to open-source AI projects or publishing papers on AGI-related topics can also help you establish yourself in the field.</p>
<h3 id="heading-how-to-prepare-11">How to prepare</h3>
<ul>
<li><p><strong>Research:</strong> Stay updated with the latest advancements in AGI by reading academic papers, attending conferences, and following thought leaders in the field.</p>
</li>
<li><p><strong>Collaborate:</strong> Work with academic or industry researchers on AGI projects. Participating in hackathons or research competitions can also provide hands-on experience.</p>
</li>
<li><p><strong>Job titles to watch:</strong> AGI Research Scientist, Cognitive Computing Engineer.</p>
</li>
</ul>
<h2 id="heading-future-job-titles">Future Job Titles</h2>
<p>The transition to an AGI world will likely see a blend of these roles, where engineers might need to be polymaths, understanding not just one but multiple areas of technology and science. It's important to grow your technical skills, but also practice adaptability and continuous learning.</p>
<p><strong>Be on the lookout for roles that might not directly mention AGI but are foundational in AI, machine learning, and related technologies.</strong> As you choose your next role, think ahead to how you can tailor your focus and future-proof your work for the AGI era.</p>
<h3 id="heading-actionable-steps">Actionable steps</h3>
<ul>
<li><p><strong>Learn continuously:</strong> Make lifelong learning a priority by regularly updating your skills and knowledge through courses, certifications, and hands-on projects.</p>
</li>
<li><p><strong>Network:</strong> Build relationships with professionals in various fields to stay informed about emerging trends and opportunities.</p>
</li>
<li><p><strong>Adapt:</strong> Stay flexible and open to new challenges, as the AGI era will require engineers to adapt to rapidly changing technologies and environments.</p>
</li>
</ul>
<p>Be on the lookout for roles that might not directly mention AGI but are foundational in AI, machine learning, and related technologies. As you choose your next role, think ahead to how you can tailor your focus and future-proof your work for the AGI era.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Become a Software Developer ]]>
                </title>
                <description>
                    <![CDATA[ As a Director of Engineering, I’m a software developer who hires and leads other software developers. It’s not surprising then that I get asked this question a lot, in various forms: How do I become a software developer? What language or framework s... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-become-a-software-developer/</link>
                <guid isPermaLink="false">66bd8f3bffb0fc5947cc912d</guid>
                
                    <category>
                        <![CDATA[ learning to code ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Wed, 06 Jan 2021 00:26:24 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/01/hard-stuff-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>As a Director of Engineering, I’m a software developer who hires and leads other software developers. It’s not surprising then that I get asked this question a lot, in various forms:</p>
<ul>
<li><em>How do I become a software developer?</em></li>
<li><em>What language or framework should I learn first?</em></li>
<li><em>Where do I start?</em></li>
</ul>
<p>While I’m certain there’s no one right answer for everyone, I’m also certain that the world needs more software developers and systems thinkers.</p>
<p>The best thing I can do to help you lead yourself, learn to code, and become a software developer is to share the most efficient parts of how I did it myself. This is the article I wish I had read when I started coding.</p>
<h2 id="heading-depth-of-knowledge-matters">Depth of knowledge matters</h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/depth.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Software is exceedingly complex. Like a good novel that you wish you’d never finish reading, there’s always more to discover and learn. </p>
<p>If you don’t want to miss the best parts, don’t be satisfied with surface-level explanations. Always go deeper! Ask why, why, and why again until you get to the fundamentals. Soon enough, you’ll start to see patterns.</p>
<p>By digging deeper, you’ll begin to understand the fundamentals of how things connect, what makes things “fast,” and facets of software operation that you probably can’t even imagine exist. It’s like peeking behind the curtain and seeing a whole world of systems and processes that most people are never aware of.</p>
<p>Going in-depth can expand your mind and your capacity for learning. Keep asking why. Follow every link. Let your curiosity guide you.</p>
<h2 id="heading-hard-stuff-matters">Hard stuff matters</h2>
<p>Giving yourself the chance to be delighted through discovery doesn’t come for free. It takes a lot of hard work to read and compress complicated ideas into your meat brain.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/hard-stuff.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>It’s important not to gloss over the hard stuff. In fact, if something seems too hard to understand, you might benefit from doing it first. You might have to get creative to find ways to explain things to yourself, but when you succeed, it makes everything else easier later on.</p>
<p>Analogies are helpful for understanding hard concepts, but they’ll only help you start to understand concepts at a surface level. Remember to go in-depth. Don’t stop at the analogy.</p>
<h2 id="heading-writing-matters">Writing matters</h2>
<p>Write right away. Create a habit of explaining everything you learn to yourself in long-form writing. Better than bullet points, writing with a conversational tone engages parts of your brain that help you to process and remember new information. It’s why humans like and remember stories, and it’s a superpower you get for free.</p>
<p>Start by writing for yourself. Write about what interests you. Try something new, even if it seems rudimentary, and write in-depth about what you learn. (<a target="_blank" href="https://victoria.dev/blog/iteration-in-python-for-list-and-map/">One of my most popular posts</a> is about iteration in Python. When I first wrote it, I considered myself a complete beginner.)</p>
<p>If you want to go a step further, share your writing with the world. Learn in public, <a target="_blank" href="https://victoria.dev">like I do</a>. I often get questions like, “how do I choose a theme for my blog?” or “what platform should I use?” or “what popular language/framework/topic should I focus on?” My answer is: don’t worry about it.</p>
<p>Don’t fret too much about your blog theme or platform. Pick the easiest option for you to get started with for now. All of that will change and improve as you learn, practice, and find your focus. Just start writing, ideally, yesterday.</p>
<p>Write for yourself by explaining what you’re doing, as if it were past-you teaching future-you — because it is. You will be your first reader, and the first judge of how useful your blog can be. Seek to impress yourself!</p>
<h2 id="heading-the-language-framework-or-version-doesnt-matter">The language, framework, or version doesn’t matter</h2>
<p>Why pigeonhole your abilities before you even start? Pick any software language, framework, or technology that seems to make sense to you when you first read it. Start there.</p>
<p>Remember that it’s important to dig deep and understand the fundamentals. Basic concepts of software transcend languages. </p>
<p>Whichever first language you choose, understand functions, variables, return values, iteration, and how immutability works. You’ll find that learning these concepts will make it easier to recognize them in your second language, and learn that too.</p>
<h2 id="heading-your-portfolio-doesnt-matter">Your portfolio doesn’t matter</h2>
<p>If your first objective is to build a portfolio, you may be trying to run before you walk. Building a portfolio to showcase to potential employers is a great goal, but a terrible first step.</p>
<p>If you think of creating a polished portfolio as a first step, you’re liable to spend too much time making it pretty and presentable before focusing on the content. As someone who hires software developers, I can tell you wholeheartedly that I’d rather see clean and well-written code than a flashy front page.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/01/temp-portfolio.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Don’t confuse building a portfolio with building projects. Absolutely build projects, right from the beginning. There’s no better way to see the practical application of what you’re learning. Just treat them as first drafts, as training ground, and don’t worry about packaging them up for professional consumption.</p>
<p>By allowing yourself to build some draft projects first, you allow yourself the breathing room to learn from them. Focus on iteration, on making one small thing better each time, and you’ll build a portfolio without even realizing it.</p>
<h2 id="heading-focus-on-what-matters">Focus on what matters</h2>
<p>Don’t follow this advice blindly – rather, incorporate it into your own systems. Experiment, make it work better than when you found it, then pay it forward by writing down what you’ve learned for someone else to read!</p>
<p>Here are my favorite books for reading or listening to if you want to cultivate a learning mindset. See <a target="_blank" href="https://victoria.dev/bookshelf/">non-coding books for coders</a>.</p>
<p>If this article benefits you in some way, I encourage you to write about it! The process of learning how to learn is never finished. You can be the next iteration.</p>
<p>If you enjoyed this post, I'd love to know. Join the thousands of people who learn along with me on <a target="_blank" href="https://victoria.dev/">victoria.dev</a>! Visit and subscribe for more about building your coding skill stack.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Write Good Documentation ]]>
                </title>
                <description>
                    <![CDATA[ In this article, I'll discuss the secret to never forgetting how your project works, in three steps. If you’ve ever half-written a software project before taking a few days off, this is the article you’ll discover you needed when you reopen that IDE.... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-write-good-documentation/</link>
                <guid isPermaLink="false">66bd8f5bc89bd16700302df8</guid>
                
                    <category>
                        <![CDATA[ docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Infrastructure as code ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Mon, 21 Dec 2020 21:00:58 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/12/cover-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, I'll discuss the secret to never forgetting how your project works, in three steps.</p>
<p>If you’ve ever half-written a software project before taking a few days off, this is the article you’ll discover you needed when you reopen that IDE.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/12/friday-monday.png" alt="Your project on Friday (a finished puzzle) vs Monday (a pile of puzzle pieces) comic" width="600" height="400" loading="lazy">
<em>Don't worry, it'll all come together by Friday again... (Comic by author)</em></p>
<p>In the technology teams I lead, we make a constant effort to document all the things. Documentation lives alongside the code as an equal player. </p>
<p>This helps ensure that no one needs to make assumptions about how something works, or is calling lengthy meetings to gain working knowledge of a feature. Good documentation saves us a lot of time and hassle.</p>
<p>That said, and contrary to popular belief, the most valuable software documentation is not primarily written for other people. As I said in this well-received tweet:</p>
<blockquote>
<p>The secret to good documentation is to write it while you're writing the code. You are your first audience. Explain what you're doing to yourself. Future you will thank you!</p>
<p>— Victoria Drake <a target="_blank" href="https://twitter.com/victoriadotdev/status/1331262801797652483?ref_src=twsrc%5Etfw">November 24, 2020</a></p>
</blockquote>
<p>Here are three concrete steps you can take to write good documentation before it’s too late.</p>
<h2 id="heading-1-start-with-accurate-notes">1. Start with accurate notes</h2>
<p>As you work out ideas in code, ensure you don’t soon forget important details by starting with accurate notes. While you will want to explain things to yourself in long-form later, short-form notes will suffice to capture details without interrupting your coding session flow.</p>
<p>Keep a document open alongside your code and write down things like commands, decisions, and sources you use. This can include:</p>
<ul>
<li>Terminal commands you typed in</li>
<li>Why you chose a particular method over another</li>
<li>Links you visited for help or _cough_copy-paste<em>cough</em> inspiration</li>
<li>The order in which you did things</li>
</ul>
<p>Don’t worry about full sentences at this point. Just ensure you accurately capture context, relevant code snippets, and helpful URLs. It can also be helpful to turn on any auto-save option available.</p>
<h2 id="heading-2-explain-decisions-in-long-form">2. Explain decisions in long form</h2>
<p>The ideal time to tackle this step is when you take a break from coding, but before you completely go out to lunch on whatever it is you’re working on at the moment. </p>
<p>You want to ensure that context, ideas, and decisions are all still fresh in your mind when you explain them to yourself.</p>
<p>Go over the short-form notes you took and start expanding them into conversational writing. Be your own rubber duck. Describe what you’re doing as if you were teaching it to someone else. You might cover topics such as:</p>
<ul>
<li>Quirky-looking decisions: “I would normally do it this way, but I chose to do something different because…”</li>
<li>Challenges you ran into and how you overcame them</li>
<li>Architectural decisions that support your project goals</li>
</ul>
<p>Stick to the main points. Long-form writing doesn’t mean you’ll be paid by the word! Just use full sentences, and write as if explaining your project to a colleague. You’re explaining to future you, after all.</p>
<h2 id="heading-3-dont-neglect-prerequisite-knowledge">3. Don’t neglect prerequisite knowledge</h2>
<p>This step is best done after a long lunch break, or even the next day (but probably not two). Re-read your document and fill in any blanks that become apparent after putting some distance between yourself and the project.</p>
<p>Take extra care to fill in or at least link to prerequisite knowledge, especially if you frequently use different languages or tools. Even an action as small as pasting in a link to the API documentation you used can save hours of future searching.</p>
<p>Write down or link to READMEs, installation steps, and relevant support issues. For frequently performed command-line actions, you can use a <a target="_blank" href="https://victoria.dev/blog/how-to-create-a-self-documenting-makefile/">self-documenting Makefile</a> to avoid having to <code>man</code> common tasks each time you come back to a project.</p>
<p>It’s easy to forget supporting details after even just a short break from your project. Capture anything you found helpful this time around.</p>
<h2 id="heading-document-all-the-things">Document all the things!</h2>
<p>The next time you catch yourself thinking, “I’m sure I’ll remember this part, no need to write it down,” just recall this emoji: 🤦‍♀️</p>
<p>Software projects are made up of a lot more than just their code. To best set up your future self for success, document all the things! Whether it’s a process you’ve established, Infrastructure as Code, or a fleeting future roadmap idea — write it down! Future you will thank you for it.</p>
<p>If you enjoyed this post, I'd love to know. Join the thousands of people who learn along with me on <a target="_blank" href="https://victoria.dev/">victoria.dev</a>! Visit and subscribe for more about building your coding skill stack.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How a Single Priority Can Make Your Tech Team More Productive ]]>
                </title>
                <description>
                    <![CDATA[ Stop giving your development team too many things to do first. Whether you’re leading a team of people or leading yourself, it’s important to take account of all the important things that need doing in your organization. And to realize that this does... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-a-single-priority-makes-your-tech-team-more-productive/</link>
                <guid isPermaLink="false">66bd8f2cffb0fc5947cc9125</guid>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ teamwork ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Thu, 17 Dec 2020 17:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/12/task-selection.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Stop giving your development team too many things to do first.</p>
<p>Whether you’re leading a team of people or leading yourself, it’s important to take account of all the important things that need doing in your organization. And to realize that this does not mean that everything can be equally important.</p>
<p>Logically, everything can’t be. Tasks are typically interdependent, and there’s always one task on which another depends. Tasks can be time-sensitive. Certain tasks might block a logical path towards a goal.</p>
<p>It’s the duty of a leader to make hard calls and decide which tasks are most important out of everything that needs doing. This necessitates comparing one to another, which is much easier to do with a centralized to-do list.</p>
<p>Here’s how this one simple change to your perspective on to-do lists can help to build happier and more productive teams.</p>
<h2 id="heading-keep-a-central-prioritized-to-do-list">Keep a central prioritized to-do list</h2>
<p><img src="https://victoria.dev/blog/how-a-single-priority-makes-your-tech-team-more-productive/prioritize.png" alt="A cartoon of a stick figure swinging on a rope ro plant a post-it note" width="600" height="400" loading="lazy"></p>
<p>Avoid working in silos. A single centralized list can make it easier for you and your team members to see what’s being worked on. With all tasks out in the open, it’s easier for people to spot opportunities for helping each other out and where they can contribute.</p>
<p>Encouraging a culture of openness can help people feel more comfortable asking questions, asking for help, and proposing ideas and improvements. Tracking work in the open also means that no one is left wondering what status a task is currently in.</p>
<p>For team leaders, a single list makes it easier to compare and prioritize tasks. This benefits team members by providing a completely unambiguous and transparent accounting of what needs doing next. Whichever task is most important, for the whole organization, is on top.</p>
<h2 id="heading-priorities-with-autonomy">Priorities with autonomy</h2>
<p>A single priority doesn’t necessarily pigeonhole someone into doing a task they don’t feel cut out for. Each member of your team has different strengths, skill sets, and diverse ways of thinking. You can take full advantage of this by encouraging autonomy in task selection.</p>
<p><img src="https://victoria.dev/blog/how-a-single-priority-makes-your-tech-team-more-productive/task-selection.png" alt="A cartoon of a stick figure climbing a ladder to reach a post-it note" width="600" height="400" loading="lazy"></p>
<p>Have people choose whichever task is nearest to the top that they’d like to tackle. They might pick the highest priority task that’s in their wheelhouse, or experiment with a higher one that’s in a domain they’d like to improve their skills at.</p>
<p>Embrace opportunities for cross-training. If tasks high up on the list fall in a category that only one or a few people on your team are experts in, have your experts partner up with another team member who’s taking on the task. </p>
<p>By pooling your resources to cross-train across domains, you multiply the capabilities of each team member and your team as a result.</p>
<p>When a task is especially time-sensitive, have several team members swarm on it and distribute the work according to their interests or strengths.</p>
<h2 id="heading-make-yourself-redundant">Make yourself redundant</h2>
<p>Working off a single prioritized to-do list works best when your team members can take on tasks as independently as possible. This is especially important in remote teams where people work asynchronously.</p>
<p>If you’re a leader and find that your team members frequently ask you what they should do next, you could be making your team dependent on you. Ask yourself if you’re unnecessarily gatekeeping information that would let your team be more autonomous.</p>
<p>A team that overly depends on their leader is not an efficient one. Individual people, such as yourself, don’t scale. Don’t become a bottleneck to your team’s productivity. </p>
<p>A successful leader should be able to take several days off on short notice without productivity grinding to a halt.</p>
<p><img src="https://victoria.dev/blog/how-a-single-priority-makes-your-tech-team-more-productive/add-resources.png" alt="A cartoon of a stick figure carrying books to a wall of post-it notes" width="600" height="400" loading="lazy"></p>
<p>To support your team’s ability to work without you, make your team, product, and company goals <em>painfully</em> available. </p>
<p>Put them where people hang out – your team’s message board, chat channel, or document repository, for example. No one should be at a loss when asked what the team wants to achieve next, and why.</p>
<p>Make any applicable resources, style guides, product documents, or links to external documentation painfully available as well. </p>
<p>If your team makes a decision about how something should be done, write it down. Don’t rely on yours or anyone else’s meat brain to remember an important decision, nor make yourself the only resource for recalling it.</p>
<p>Make yourself redundant when it comes to day-to-day work. Doing so empowers your team members to do work without you, think through solutions on their own, and propose paths of action that you probably wouldn’t have thought of yourself.</p>
<h2 id="heading-build-happier-and-more-productive-teams">Build happier and more productive teams</h2>
<p>From first-hand experience as both a team member and leader, I’ve seen how encouraging a culture of openness, cross-training, and autonomy makes for happier team members and more productive teams. </p>
<p>A single prioritized to-do list, coupled with available documentation and resources, opens the gates to let your technical team be maximally productive.</p>
<p>By removing bottlenecks, you allow people to make more decisions on their own and take ownership of their work. That’s a technical team I’d be proud to lead.</p>
<p>If you enjoyed this post, I'd love to know. Join the thousands of people who learn along with me on <a target="_blank" href="https://victoria.dev/">victoria.dev</a>! Visit or <a target="_blank" href="https://victoria.dev/index.xml">subscribe via RSS</a> for more about building happy and productive technical teams.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Responsive Pages and Color Themes with Minimal CSS ]]>
                </title>
                <description>
                    <![CDATA[ Want to build a responsive website with color themes? Start at the root. If you happen to drop by my website, you may notice I’ve spruced it up a bit. Victoria.dev can now better respond to your devices and preferences. Most modern devices and web br... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/responsive-pages-and-color-themes-with-minimal-css/</link>
                <guid isPermaLink="false">66bd8f74abf0ccf74f1ce995</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ responsive design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Wed, 16 Dec 2020 17:51:58 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/12/root.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Want to build a responsive website with color themes? Start at the root.</p>
<p>If you happen to drop by my website, you may notice I’ve spruced it up a bit. <a target="_blank" href="https://victoria.dev/">Victoria.dev</a> can now better respond to your devices and preferences.</p>
<p>Most modern devices and web browsers allow users to choose either a light or dark theme for the user interface. With <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries">CSS media queries</a>, you can have your own website's styles change to match this user setting!</p>
<p>Media queries are also a common way to have elements on web pages change to suit different screen sizes. This is an especially powerful tool when combined with <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/--*">custom properties</a> set on the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/:root">root element</a>.</p>
<p>Here's how to use CSS media queries and custom properties to improve your visitor's browsing experience with just a few lines of CSS.</p>
<h2 id="heading-how-to-cater-to-peoples-color-preferences">How to Cater to People's Color Preferences</h2>
<p>The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme"><code>prefers-color-scheme</code> media feature</a> can be queried to serve up your user’s color scheme of choice. The <code>light</code> option is the go-to version if no active preference is set, and it has <a target="_blank" href="https://caniuse.com/mdn-css_at-rules_media_prefers-color-scheme">decent support across modern browsers</a>.</p>
<p>Additionally, users reading on certain devices can also set light and dark color themes based on a schedule. For example, my phone uses light colors throughout its UI during the daytime, and dark colors at night. You can make your website follow suit.</p>
<p>Avoid repeating a lot of CSS by setting custom properties for your color themes on your <code>:root</code> pseudo-class. Create a version for each theme you wish to support. Here’s a quick example you can build on:</p>
<pre><code class="lang-css"><span class="hljs-selector-pseudo">:root</span> {
    <span class="hljs-attribute">color-scheme</span>: light dark;
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-color-scheme:</span> light) {
    <span class="hljs-selector-pseudo">:root</span> {
        <span class="hljs-attribute">--text-primary</span>: <span class="hljs-number">#24292e</span>;
        <span class="hljs-attribute">--background</span>: white;
        <span class="hljs-attribute">--shadow</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.15</span>) <span class="hljs-number">0px</span> <span class="hljs-number">2px</span> <span class="hljs-number">5px</span> <span class="hljs-number">0px</span>;
    }
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">prefers-color-scheme:</span> dark) {
    <span class="hljs-selector-pseudo">:root</span> {
        <span class="hljs-attribute">--text-primary</span>: white;
        <span class="hljs-attribute">--background</span>: <span class="hljs-number">#24292e</span>;
        <span class="hljs-attribute">--shadow</span>: <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.35</span>) <span class="hljs-number">0px</span> <span class="hljs-number">2px</span> <span class="hljs-number">5px</span> <span class="hljs-number">0px</span>;
    }
}
</code></pre>
<p>As you can see, you can use custom properties to set all kinds of values. To use these as variables with other CSS elements, use the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/var()"><code>var()</code></a> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/var()">function</a>:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">header</span> {
    <span class="hljs-attribute">color</span>: <span class="hljs-built_in">var</span>(--text-primary);
    <span class="hljs-attribute">background-color</span>: <span class="hljs-built_in">var</span>(--background);
    <span class="hljs-attribute">box-shadow</span>: <span class="hljs-built_in">var</span>(--shadow);
}
</code></pre>
<p>In this quick example, the <code>header</code> element will now display your user’s preferred colors according to their browser settings.</p>
<p>Preferred color schemes are set by the user in different ways, depending on the browser. Here are a couple examples.</p>
<h3 id="heading-light-and-dark-mode-in-firefox">Light and Dark Mode in Firefox</h3>
<p>You can test out <code>light</code> and <code>dark</code> modes in Firefox by typing <code>about:config</code> into the address bar. Accept the warning if it pops up, then type <code>ui.systemUsesDarkTheme</code> into the search.</p>
<p>Choose a <code>Number</code> value for the setting, then input a <code>1</code> for dark or <code>0</code> for light.</p>
<p><img src="https://victoria.dev/blog/responsive-pages-and-color-themes-with-minimal-css/firefox-theme-setting.png" alt="A screenshot of setting the color theme in Firefox" width="600" height="400" loading="lazy"></p>
<h3 id="heading-light-and-dark-mode-in-brave">Light and Dark Mode in Brave</h3>
<p>If you’re using Brave, find color theme settings in <strong>Settings</strong> &gt; <strong>Appearance</strong> &gt; <strong>Brave colors</strong>.</p>
<p><img src="https://victoria.dev/blog/responsive-pages-and-color-themes-with-minimal-css/brave-settings.png" alt="A screenshot of setting the color theme in Brave" width="600" height="400" loading="lazy"></p>
<h2 id="heading-how-to-use-variable-scaling">How to Use Variable Scaling</h2>
<p>You can also use a custom property to effortlessly adjust the size of text or other elements depending on your user’s screen size. The <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/width"><code>width</code> media feature</a> tests the width of the viewport. </p>
<p>While <code>width: _px</code> will match an exact size, you can also use <code>min</code> and <code>max</code> to create ranges.</p>
<p>Query with <code>min-width: _px</code> to match anything over <code>_</code> pixels, and <code>max-width: _px</code> to match anything up to <code>_</code> pixels.</p>
<p>Use these queries to set a custom property on the <code>:root</code> to create a ratio:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@media</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">360px</span>) {
    <span class="hljs-selector-pseudo">:root</span> {
        <span class="hljs-attribute">--scale</span>: <span class="hljs-number">0.8</span>;
    }
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">768px</span>) {
    <span class="hljs-selector-pseudo">:root</span> {
        <span class="hljs-attribute">--scale</span>: <span class="hljs-number">1</span>;
    }
}

<span class="hljs-keyword">@media</span> (<span class="hljs-attribute">min-width:</span> <span class="hljs-number">1024px</span>) {
    <span class="hljs-selector-pseudo">:root</span> {
        <span class="hljs-attribute">--scale</span>: <span class="hljs-number">1.2</span>;
    }
}
</code></pre>
<p>Then make an element responsive by using the <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/calc()"><code>calc()</code></a> <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/calc()">function</a>. Here are a few examples:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">42px</span> * var(--scale));
}

<span class="hljs-selector-tag">h2</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">26px</span> * var(--scale));
}

<span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">width</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">200px</span> * var(--scale));
}
</code></pre>
<p>In this example, multiplying an initial value by your <code>--scale</code> custom property allows the size of headings and images to magically adjust to your user’s device width.</p>
<p>The relative unit <code>rem</code> will have a similar effect. You can use it to define sizes for elements relative to the font size declared at the root element.</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">h1</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">5rem</span> * var(--scale));
}

<span class="hljs-selector-tag">h2</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">1.5rem</span> * var(--scale));
}

<span class="hljs-selector-tag">p</span> {
    <span class="hljs-attribute">font-size</span>: <span class="hljs-built_in">calc</span>(<span class="hljs-number">1rem</span> * var(--scale));
}
</code></pre>
<p>Of course, you can also multiply two custom properties. For example, setting the <code>--max-img</code> as a custom property on the <code>:root</code> can help to save you time later on by not having to update a pixel value in multiple places:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">img</span> {
    <span class="hljs-attribute">max-width</span>: <span class="hljs-built_in">calc</span>(var(--max-img) * <span class="hljs-built_in">var</span>(--scale));
}
</code></pre>
<h2 id="heading-raise-your-responsiveness-game">Raise your responsiveness game</h2>
<p>Try out these easy wins for a website that caters to your visitor’s devices and preferences. I’ve put them to good use now on <a target="_blank" href="https://victoria.dev/">victoria.dev</a>. I invite you to <a target="_blank" href="https://victoria.dev/contact">let me know how you like it!</a></p>
<p>If you enjoyed this post, there's a lot more where it came from. Subscribe on <a target="_blank" href="https://victoria.dev">victoria.dev</a> to see new articles first.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is the TCP/IP Model? Layers and Protocols Explained ]]>
                </title>
                <description>
                    <![CDATA[ A significant part of the process of creating something is the ability to imagine things that do not yet exist.  This skill was instrumental to the creation of the Internet. If no one had imagined the underlying technology that most now take for gran... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-tcp-ip-layers-and-protocols-explained/</link>
                <guid isPermaLink="false">66bd8f96ff5a6ee84df6b849</guid>
                
                    <category>
                        <![CDATA[ internet ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Mon, 30 Nov 2020 23:25:48 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/11/cover-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>A significant part of the process of creating something is the ability to imagine things that do not yet exist. </p>
<p>This skill was instrumental to the creation of the Internet. If no one had imagined the underlying technology that most now take for granted every day, there would be no cat memes.</p>
<p>To make the Internet possible, two things that needed imagining were <em>layers</em> and <em>protocols.</em> </p>
<p>Layers are conceptual divides that group similar functions together. The word “protocol,” means “the way we’ve agreed to do things around here,” more or less. </p>
<p>In short, both layers and protocols can be explained to a five-year-old as “ideas that people agreed sounded good, and then they wrote them down so that other people could do things with the same ideas.”</p>
<p>The Internet Protocol Suite is described in terms of layers and protocols. Collectively, the suite refers to the communication protocols that enable our endless scrolling. </p>
<p>It’s often called by its foundational protocols: the Transmission Control Protocol (TCP) and the Internet Protocol (IP). Lumped together as TCP/IP, these protocols describe how data on the Internet is packaged, addressed, sent, and received.</p>
<p>Here’s why the Internet Protocol Suite, or TCP/IP, is an imaginary rainbow layer cake.</p>
<h2 id="heading-layers-are-imaginary"><strong>Layers are imaginary</strong></h2>
<p>If you consider the general nature of a rainbow layer sponge cake, it’s mostly made up of soft, melt-in-your mouth vanilla-y goodness. This goodness is in itself comprised of something along the lines of eggs, butter, flour, and sweetener.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/free-cake.png" alt="Cartoon of a slice of rainbow layer cake, reads “Yay! Free cake!&quot;" width="600" height="400" loading="lazy"></p>
<p>There isn’t much to distinguish one layer of a rainbow sponge cake from another. Often, the only difference between layers is the food-coloring and a bit of frosting. When you think about it, it’s all cake from top to bottom. The rainbow layers are only there because the baker thought they ought to be.</p>
<p>Similar to cake ingredients, layers in the context of computer networking are mostly composed of protocols, algorithms, and configurations, with some data sprinkled in. </p>
<p>It can be easier to talk about computer networking if its many functions are split up into groups, so certain people came up with descriptions of layers, which we call network models. TCP/IP is just one network model among others. In this sense, layers are concepts, not things.</p>
<p>Some of the people in question are part of the Internet Engineering Task Force (IETF). They created the <a target="_blank" href="https://tools.ietf.org/html/rfc1122">RFC-1122</a> publication, discussing the Internet’s communications layers. Half of a whole, the standard:</p>
<blockquote>
<p>…covers the communications protocol layers: link layer, IP layer, and transport layer; its companion <a target="_blank" href="https://tools.ietf.org/html/rfc1123">RFC-1123</a> covers the application and support protocols.</p>
</blockquote>
<p>The layers described by RFC-1122 and RFC-1123 each encapsulate protocols that satisfy the layer’s functionality. Let’s look at each of these communications layers and see how TCP and IP stack up in this model of the Internet layer cake.</p>
<h2 id="heading-link-layer-protocols"><strong>Link layer protocols</strong></h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/link.png" alt="Link cake layer cartoon" width="600" height="400" loading="lazy"></p>
<p>The <a target="_blank" href="https://tools.ietf.org/html/rfc1122#page-21">link layer</a> is the most basic, or lowest-level, classification of communication protocol. It deals with sending information between hosts on the same local network, and translating data from the higher layers to the physical layer. </p>
<p>Protocols in the link layer describe how data interacts with the transmission medium, such as electronic signals sent over specific hardware. Unlike other layers, link layer protocols are dependent on the hardware being used.</p>
<h2 id="heading-internet-layer-protocols"><strong>Internet layer protocols</strong></h2>
<p>Protocols in the <a target="_blank" href="https://tools.ietf.org/html/rfc1122#page-27">Internet layer</a> describe how data is sent and received over the Internet. The process involves packaging data into packets, addressing and transmitting packets, and receiving incoming packets of data.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/internet.png" alt="Internet cake layer cartoon" width="600" height="400" loading="lazy"></p>
<p>The most widely known protocol in this layer gives TCP/IP its last two letters. IP is a connectionless protocol, meaning that it provides no guarantee that packets are sent or received in the right order, along the same path, or even in their entirety. </p>
<p>Reliability is handled by other protocols in the suite, such as in the transport layer.</p>
<p>There are currently two versions of IP in use: IPv4, and IPv6. Both versions describe how devices on the Internet are assigned IP addresses, which are used when navigating to cat memes. </p>
<p>IPv4 is more widely used, but has only <a target="_blank" href="https://tools.ietf.org/html/rfc791#section-2.3">32 bits for addressing</a>, allowing for about 4.3 billion (ca. 4.3×10<sup>9</sup>) possible addresses. These are running out, and IPv4 will eventually suffer from address exhaustion as more and more people use more devices on the Internet.</p>
<p>The successor version IPv6 aims to solve address exhaustion by <a target="_blank" href="https://tools.ietf.org/html/rfc8200#section-1">using 128 bits for addresses</a>. This provides, um, a <em>lot</em> more address possibilities (ca. 3.4×10<sup>38</sup>).</p>
<h2 id="heading-transport-layer-protocols"><strong>Transport layer protocols</strong></h2>
<p>In May 1974, Vint Cerf and Bob Kahn (collectively often called “the fathers of the Internet”) published a paper entitled <a target="_blank" href="https://web.archive.org/web/20160304150203/http://ece.ut.ac.ir/Classpages/F84/PrincipleofNetworkDesign/Papers/CK74.pdf">A Protocol for Packet Network Intercommunication</a>. </p>
<p>This paper contained the first description of a Transmission Control Program, a concept encompassing what would eventually be known as the Transmission Control Protocol (TCP) and User Datagram Protocol (UDP). (I had the pleasure of meeting Vint and can personally confirm that yes, he does look exactly like The Architect in the Matrix movies.)</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/transport.png" alt="Transport cake layer cartoon" width="600" height="400" loading="lazy"></p>
<p>The <a target="_blank" href="https://tools.ietf.org/html/rfc1122#page-77">transport layer</a> presently encapsulates TCP and UDP. Like IP, UDP is connectionless and can be used to prioritize time over reliability. </p>
<p>TCP, on the other hand, is a connection-oriented transport layer protocol that prioritizes reliability over latency, or time. TCP describes transferring data in the same order as it was sent, retransmitting lost packets, and controls affecting the rate of data transmission.</p>
<h2 id="heading-application-layer-protocols"><strong>Application layer protocols</strong></h2>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/application.png" alt="Application cake layer cartoon" width="600" height="400" loading="lazy"></p>
<p>The application layer describes the protocols that software applications interact with most often. The specification includes descriptions of the remote login protocol <a target="_blank" href="https://tools.ietf.org/html/rfc1123#section-3">Telnet</a>, the <a target="_blank" href="https://tools.ietf.org/html/rfc1123#section-4">File Transfer Protocol (FTP)</a>, and the <a target="_blank" href="https://tools.ietf.org/html/rfc1123#section-5">Simple Mail Transfer Protocol (SMTP)</a>.</p>
<p>Also included in the application layer are the Hypertext Transfer Protocol (HTTP) and its successor, Hypertext Transfer Protocol Secure (HTTPS). </p>
<p>HTTPS is secured by Transport Layer Security, or TLS, which can be said to be the top-most layer of the networking model described by the Internet protocol suite. </p>
<p>If you’d like to further understand TLS and how this protocol secures your cat meme viewing, I invite you <a target="_blank" href="https://victoria.dev/blog/tls">read my article about TLS and cryptography</a>.</p>
<h2 id="heading-the-internet-cake-is-still-baking"><strong>The Internet cake is still baking</strong></h2>
<p>Like a still-rising sponge cake, descriptions of layers, better protocols, and new models are being developed every day. The Internet, or whatever it will become in the future, is still in the process of being imagined.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/11/cake.png" alt="Cartoon of the full Internet layer cake, topped with Nyan Cat memes" width="600" height="400" loading="lazy"></p>
<p>If you enjoyed learning from this post, there’s a lot more where this came from! I write about computing, cybersecurity, and building great technical teams. Join the thousands of people who learn from my articles on <a target="_blank" href="https://victoria.dev">victoria.dev</a>! Visit and subscribe by email or RSS to see new articles first.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build Your Own Serverless Subscriber List with Go and AWS ]]>
                </title>
                <description>
                    <![CDATA[ In this article, I'll share how I lovingly built a subscription sign up flow with email confirmation that doesn’t suck. You can do it, too.  If you want to see it in action, you can now subscribe to my email list on victoria.dev. Now, I'll show you h... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-your-own-serverless-subscriber-list-with-go-and-aws/</link>
                <guid isPermaLink="false">66bd8f1827629f4c5e1893a2</guid>
                
                    <category>
                        <![CDATA[ AWS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ email ]]>
                    </category>
                
                    <category>
                        <![CDATA[ golang ]]>
                    </category>
                
                    <category>
                        <![CDATA[ serverless ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Mon, 16 Nov 2020 19:37:12 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/11/envelope.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, I'll share how I lovingly built a subscription sign up flow with email confirmation that doesn’t suck. You can do it, too. </p>
<p>If you want to see it in action, you can now subscribe to my email list on <a target="_blank" href="https://victoria.dev/">victoria.dev</a>.</p>
<p>Now, I'll show you how I built it.</p>
<h2 id="heading-introducing-simple-subscribe"><strong>Introducing Simple Subscribe</strong></h2>
<p>If you’re interested in managing your own mailing list or newsletter, you can set up Simple Subscribe on your own AWS resources to collect email addresses. </p>
<p>This open source API is written in Go, and runs on AWS Lambda. Visitors to your site can sign up to your list, which is stored in a DynamoDB table, ready to be queried or exported at your leisure.</p>
<p>When someone signs up, they’ll receive an email asking them to confirm their subscription. This is sometimes called “double opt-in,” although I prefer the term “verified.” </p>
<p>Simple Subscribe works on serverless infrastructure and uses an AWS Lambda to handle subscription, confirmation, and unsubscribe requests.</p>
<p>You can find the <a target="_blank" href="https://github.com/victoriadrake/simple-subscribe">Simple Subscribe project, with its fully open-source code, on GitHub</a>. I encourage you to pull up the code and follow along! </p>
<p>In this post I’ll share each build step, the thought process behind the API’s single-responsibility functions, and security considerations for an AWS project like this one.</p>
<h2 id="heading-how-to-build-a-verified-subscription-flow"><strong>How to build a verified subscription flow</strong></h2>
<p>A non-verified email sign up process is straightforward. Someone puts their email into a box on your website, then that email goes into your database. </p>
<p>However, if I’ve taught you anything about <a target="_blank" href="https://victoria.dev/blog/sql-injection-and-xss-what-white-hat-hackers-know-about-trusting-user-input/">not trusting user input</a>, the very idea of a non-verified sign up process should raise your hackles. Spam may be great when fried in a sandwich, but it's no fun when it’s running up your AWS bill.</p>
<p>While you can use a strategy like a CAPTCHA or puzzle for is-it-a-human verification, these can create enough friction to turn away your potential subscribers. </p>
<p>Instead, a confirmation email can help to ensure both address correctness and user sentience.</p>
<p>To build a subscription flow with email confirmation, create single-responsibility functions that satisfy each logical step. Those are:</p>
<ol>
<li>Accept an email address and record it.</li>
<li>Generate a token associated with that email address and record it.</li>
<li>Send a confirmation email to that email address with the token.</li>
<li>Accept a verification request that has both the email address and token.</li>
</ol>
<p>To achieve each of these goals, Simple Subscribe uses the <a target="_blank" href="https://docs.aws.amazon.com/sdk-for-go/api/">official AWS SDK for Go</a> to interact with DynamoDB and SES.</p>
<p>At each stage, consider what the data looks like and how you store it. This can help to handle conundrums like, “What happens if someone tries to subscribe twice?” or even <a target="_blank" href="https://victoria.dev/blog/if-you-want-to-build-a-treehouse-start-at-the-bottom/">threat-modeling</a> such as, “What if someone subscribes with an email they don’t own?”</p>
<p>Ready? Let’s break down each step and see how the magic happens.</p>
<h3 id="heading-subscribing"><strong>Subscribing</strong></h3>
<p>The subscription process begins with a humble web form, like the one on my site’s main page. A form input with attributes <code>type="email" required</code> helps with validation, <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/email#Validation">thanks to the browser</a>. When submitted, the form sends a GET request to the Simple Subscribe subscription endpoint.</p>
<p>Simple Subscribe receives a GET request to this endpoint with a query string containing the intended subscriber’s email. It then generates an <code>id</code> value and adds both <code>email</code> and <code>id</code> to your DynamoDB table.</p>
<p>The table item now looks like:</p>
<table><thead><tr><th>email</th><th>confirm</th><th>id</th><th>timestamp</th></tr></thead><tbody><tr><td><code>subscriber@example.com</code></td><td><em>false</em></td><td><code>uuid-xxxxx</code></td><td>2020-11-01 00:27:39</td></tr></tbody></table>

<p>The <code>confirm</code> column, which holds a boolean, indicates that the item is a subscription request that has not yet been confirmed. To verify an email address in the database, you’ll need to find the correct item and change <code>confirm</code> to <code>true</code>.</p>
<p>As you work with your data, consider the goal of each manipulation and how you might compare an incoming request to existing data.</p>
<p>For example, if someone made a subsequent subscription request for the same email address, how would you handle it? </p>
<p>You might say, “Create a new line item with a new <code>id</code>." However, this might not be the best strategy when your serverless application database is paid for by request volume.</p>
<p>Since <a target="_blank" href="https://aws.amazon.com/dynamodb/pricing/">DynamoDB Pricing</a> depends on how much data you read and write to your tables, it’s advantageous to avoid piling on excess data.</p>
<p>With that in mind, it would be prudent to handle subscription requests for the same email by performing an update instead of adding a new line. </p>
<p>Simple Subscribe actually uses the same function to either add or update a database item. This is typically referred to as, “update or insert.”</p>
<p>In a database like SQLite this is accomplished with the <a target="_blank" href="https://www.sqlite.org/lang_UPSERT.html">UPSERT syntax</a>. In the case of DynamoDB, you use an update operation. For the <a target="_blank" href="https://docs.aws.amazon.com/sdk-for-go/api/service/dynamodb/">Go SDK</a>, its syntax is <code>UpdateItem</code>.</p>
<p>When a duplicate subscription request is received, the database item is matched on the <code>email</code> only. If an existing line item is found, its <code>id</code> and <code>timestamp</code> are overridden, which updates the existing database record and avoids flooding your table with duplicate requests.</p>
<h3 id="heading-how-to-verify-email-addresses"><strong>How to verify email addresses</strong></h3>
<p>After submitting the form, the intended subscriber then receives an email from SES containing a link. This link is built using the <code>email</code> and <code>id</code> from the table, and takes the format:</p>
<pre><code class="lang-url">&lt;BASE_URL&gt;&lt;VERIFY_PATH&gt;/?email=subscriber@example.com&amp;id=uuid-xxxxx
</code></pre>
<p>In this set up, the <code>id</code> is a UUID that acts as a secret token. It provides an identifier that you can match that is sufficiently complex and hard to guess. This approach deters people from subscribing with email addresses they don’t control.</p>
<p>Visiting the link sends a request to your verification endpoint with the <code>email</code> and <code>id</code> in the query string. </p>
<p>This time, it’s important to compare both the incoming <code>email</code> and <code>id</code> values to the database record. This verifies that the recipient of the confirmation email is initiating the request.</p>
<p>The verification endpoint ensures that these values match an item in your database, then performs another update operation to set <code>confirm</code> to <code>true</code>, and update the timestamp. The item now looks like:</p>
<table><thead><tr><th>email</th><th>confirm</th><th>id</th><th>timestamp</th></tr></thead><tbody><tr><td><code>subscriber@example.com</code></td><td><em>true</em></td><td><code>uuid-xxxxx</code></td><td>2020-11-01 00:37:39</td></tr></tbody></table>

<h3 id="heading-how-to-query-for-emails"><strong>How to query for emails</strong></h3>
<p>You can now query your table to build your email list. Depending on your email sending solution, you might do this manually, with another Lambda, or even from the command line.</p>
<p>Since data for requested subscriptions (where <code>confirm</code> is <code>false</code>) is stored in the table alongside confirmed subscriptions, it’s important to differentiate this data when querying for email addresses to send to. You’ll want to ensure you only return emails where <code>confirm</code> is <code>true</code>.</p>
<h2 id="heading-how-to-provide-unsubscribe-links"><strong>How to provide unsubscribe links</strong></h2>
<p>Similar to verifying an email address, Simple Subscribe uses <code>email</code> and <code>id</code> as arguments to the function that deletes an item from your DynamoDB table in order to unsubscribe an email address. </p>
<p>To allow people to remove themselves from your list, you’ll need to provide a URL in each email you send that includes their <code>email</code> and <code>id</code> as a query string to the unsubscribe endpoint. It would look something like:</p>
<pre><code class="lang-url">&lt;BASE_URL&gt;&lt;UNSUBSCRIBE_PATH&gt;/?email=subscriber@example.com&amp;id=uuid-xxxxx
</code></pre>
<p>When the link is clicked, the query string is passed to the unsubscribe endpoint. If the provided <code>email</code> and <code>id</code> match a database item, that item will be deleted.</p>
<p>Proving a method for your subscribers to automatically remove themselves from your list, without any human intervention necessary, is part of an ethical and respectful philosophy towards handling the data that’s been entrusted to you.</p>
<h2 id="heading-how-to-care-for-your-data">How to care for your data</h2>
<p>Once you decide to accept other people’s data, it becomes your responsibility to care for it. This is applicable to everything you build. For Simple Subscribe, it means maintaining the security of your database, and periodically pruning your table.</p>
<p>In order to avoid retaining email addresses where <code>confirm</code> is <code>false</code> past a certain time frame, it would be a good idea to set up a cleaning function that runs on a regular schedule. This can be achieved manually, with an AWS Lambda function, or using the command line.</p>
<p>To clean up, find database items where <code>confirm</code> is <code>false</code> and <code>timestamp</code> is older than a particular point in time. Depending on your use case and request volumes, the frequency at which you choose to clean up will vary.</p>
<p>Also depending on your use case, you may wish to keep backups of your data. If you are particularly concerned about data integrity, you can explore <a target="_blank" href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/backuprestore_HowItWorks.html">On-Demand Backup</a> or <a target="_blank" href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/PointInTimeRecovery.html">Point-in-Time Recovery</a> for DynamoDB.</p>
<h2 id="heading-build-your-independent-subscriber-base">Build your independent subscriber base</h2>
<p>Building your own subscriber list can be an empowering endeavor! Whether you intend to start a newsletter, send out notifications for new content, or want to create a community around your work, there’s nothing more personal or direct than an email from me to you.</p>
<p>I encourage you to start building your subscriber base with Simple Subscribe today. Like most of my work, it’s open source and free for your personal use. Dive into the code at <a target="_blank" href="https://github.com/victoriadrake/simple-subscribe">the GitHub repository</a> or learn more at <a target="_blank" href="https://simplesubscribe.org/">SimpleSubscribe.org</a>.</p>
<p>If you enjoyed this post, I'd love to know. Join the thousands of people who learn along with me on <a target="_blank" href="https://victoria.dev/">victoria.dev</a>. Visit or <a target="_blank" href="https://victoria.dev/index.xml">subscribe via RSS</a> for more projects like this one.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ WPA Key, WPA2, WPA3, and WEP Key: Wi-Fi Security Explained ]]>
                </title>
                <description>
                    <![CDATA[ Setting up new Wi-Fi? Picking the type of password you need can seem like an arbitrary choice. After all, WEP, WPA, WPA2, and WPA3 all have mostly the same letters in them. A password is a password, so what’s the difference? About 60 seconds to billi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/wifi-security-explained/</link>
                <guid isPermaLink="false">66bd8f9f621c718d60a3103d</guid>
                
                    <category>
                        <![CDATA[ Application Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ information security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ wifi ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Wed, 21 Oct 2020 00:43:34 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/10/cover-4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Setting up new Wi-Fi? Picking the type of password you need can seem like an arbitrary choice. After all, WEP, WPA, WPA2, and WPA3 all have mostly the same letters in them.</p>
<p>A password is a password, so what’s the difference? About 60 seconds to billions of years, as it turns out.</p>
<p>All Wi-Fi encryption is not created equal. Let’s explore what makes these four acronyms so different, and how you can best protect your home and organization Wi-Fi.</p>
<h2 id="heading-wired-equivalent-privacy-wep">Wired Equivalent Privacy (WEP)</h2>
<p>In the beginning, there was WEP.</p>
<p><img src="https://victoria.dev/blog/wpa-key-wpa2-wpa3-and-wep-key-wi-fi-security-explained/wep.png" alt="WEP illustration" width="600" height="400" loading="lazy"></p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Wired_Equivalent_Privacy">Wired Equivalent Privacy</a> is a deprecated security algorithm from 1997 that was intended to provide equivalent security to a wired connection. “Deprecated” means, “Let’s not do that anymore.”</p>
<p>Even when it was first introduced, it was known not to be as strong as it could have been, for two reasons:</p>
<ul>
<li>its underlying encryption mechanism, and </li>
<li>World War II.</li>
</ul>
<p>During World War II, the impact of code breaking (or cryptanalysis) was <a target="_blank" href="https://en.wikipedia.org/wiki/History_of_cryptography#World_War_II_cryptography">huge</a>. Governments reacted by attempting to keep their best secret-sauce recipes at home. </p>
<p>Around the time of WEP, <a target="_blank" href="https://en.wikipedia.org/wiki/Export_of_cryptography_from_the_United_States">U.S. Government restrictions on the export of cryptographic technology</a> caused access point manufacturers to limit their devices to 64-bit encryption. Though this was later lifted to 128-bit, even this form of encryption offered a very limited possible <a target="_blank" href="https://en.wikipedia.org/wiki/Key_size">key size</a>.</p>
<p>This proved problematic for WEP. The small key size resulted in being easier to <a target="_blank" href="https://en.wikipedia.org/wiki/Brute-force_attack">brute-force</a>, especially when that key doesn’t often change.</p>
<p>WEP’s underlying encryption mechanism is the <a target="_blank" href="https://en.wikipedia.org/wiki/RC4">RC4 stream cipher</a>. This cipher gained popularity due to its speed and simplicity, but that came at a cost. </p>
<p>It’s not the most robust algorithm. WEP employs a single shared key among its users that must be manually entered on an access point device. (When’s the last time you changed your Wi-Fi  password? Right.) </p>
<p>WEP didn’t help matters either by simply concatenating the key with the initialization vector – which is to say, it sort of mashed its secret-sauce bits together and hoped for the best.</p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Initialization_vector">Initialization Vector (IV)</a>: fixed-size input to a <a target="_blank" href="https://en.wikipedia.org/wiki/Cryptographic_primitive">low-level cryptographic algorithm</a>, usually random.</p>
<p>Combined with the use of RC4, this left WEP particularly susceptible to <a target="_blank" href="https://en.wikipedia.org/wiki/Related-key_attack">related-key attack</a>. In the case of 128-bit WEP, your Wi-Fi password can be cracked by publicly-available tools in a matter of around <a target="_blank" href="https://shawnhogan.com/2006/08/how-to-crack-128-bit-wireless-networks.html">60 seconds</a> to <a target="_blank" href="https://www.networkcomputing.com/wireless-infrastructure/fbi-teaches-lesson-how-break-wi-fi-networks">three minutes</a>.</p>
<p>While some devices came to offer 152-bit or 256-bit WEP variants, this failed to solve the fundamental problems of WEP’s underlying encryption mechanism.</p>
<p>So, yeah. Let’s not do that anymore.</p>
<h2 id="heading-wi-fi-protected-access-wpa">Wi-Fi Protected Access (WPA)</h2>
<p><img src="https://victoria.dev/blog/wpa-key-wpa2-wpa3-and-wep-key-wi-fi-security-explained/wpa.png" alt="WPA illustration" width="600" height="400" loading="lazy"></p>
<p>A new, interim standard sought to temporarily “patch” the problem of WEP’s (lack of) security. The name <a target="_blank" href="https://en.wikipedia.org/wiki/Wi-Fi_Protected_Access">Wi-Fi Protected Access (WPA)</a> certainly <em>sounds</em> more secure, so that’s a good start. However, WPA first started out with another, more descriptive name.</p>
<p>Ratified in a <a target="_blank" href="https://en.wikipedia.org/wiki/IEEE_802.11i-2004">2004 IEEE standard</a>, <a target="_blank" href="https://en.wikipedia.org/wiki/Temporal_Key_Integrity_Protocol#Beck-Tews_attack">Temporal Key Integrity Protocol (TKIP)</a> uses a dynamically-generated, per-packet key. Each packet sent has a unique temporal 128-bit key, (See? Descriptive!) that solves the susceptibility to related-key attacks brought on by WEP’s shared key mashing.</p>
<p>TKIP also implements other measures, such as a <a target="_blank" href="https://en.wikipedia.org/wiki/Message_authentication_code">message authentication code (MAC)</a>. Sometimes known as a checksum, a MAC provides a cryptographic way to verify that messages haven’t been changed. </p>
<p>In TKIP, an invalid MAC can also trigger rekeying of the session key. If the access point receives an invalid MAC twice within a minute, the attempted intrusion can be countered by changing the key an attacker is trying to crack.</p>
<p>Unfortunately, in order to preserve compatibility with the existing hardware that WPA was meant to “patch,” TKIP retained the use of the same underlying encryption mechanism as WEP – the RC4 stream cipher. </p>
<p>While it certainly improved on the weaknesses of WEP, TKIP eventually proved vulnerable to new attacks that <a target="_blank" href="https://en.wikipedia.org/wiki/Temporal_Key_Integrity_Protocol#Security">extended previous attacks on WEP</a>. </p>
<p>These attacks take a little longer to execute by comparison: for example, <a target="_blank" href="http://dl.aircrack-ng.org/breakingwepandwpa.pdf">twelve minutes</a> in the case of one, and <a target="_blank" href="https://www.rc4nomore.com/">52 hours</a> in another. This is more than sufficient, however, to deem TKIP no longer secure.</p>
<p>WPA, or TKIP, has since been deprecated as well. So let’s also not do that anymore.</p>
<p>Which brings us to…</p>
<h2 id="heading-wi-fi-protected-access-ii-wpa2">Wi-Fi Protected Access II (WPA2)</h2>
<p><img src="https://victoria.dev/blog/wpa-key-wpa2-wpa3-and-wep-key-wi-fi-security-explained/wpa2.png" alt="WPA2 illustration" width="600" height="400" loading="lazy"></p>
<p>Rather than spend the effort to come up with an entirely new name, the improved <a target="_blank" href="https://en.wikipedia.org/wiki/Wi-Fi_Protected_Access#WPA2">Wi-Fi Protected Access II (WPA2)</a> standard instead focuses on using a new underlying cipher. </p>
<p>Instead of  the RC4 stream cipher, WPA2 employs a block cipher called <a target="_blank" href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard">Advanced Encryption Standard (AES)</a> to form the basis of its encryption protocol. </p>
<p>The protocol itself, abbreviated <a target="_blank" href="https://en.wikipedia.org/wiki/CCMP_(cryptography)">CCMP</a>, draws most of its security from the length of its rather long name (I’m kidding): Counter Mode Cipher Block Chaining Message Authentication Code Protocol, which shortens to Counter Mode CBC-MAC Protocol, or CCM mode Protocol, or CCMP. ?</p>
<p><a target="_blank" href="https://en.wikipedia.org/wiki/CCM_mode">CCM mode</a> is essentially a combination of a few good ideas. It provides data confidentiality through <a target="_blank" href="https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29">CTR mode, or counter mode</a>. To vastly oversimplify, this adds complexity to plaintext data by encrypting the successive values of a count sequence that does not repeat. </p>
<p>CCM also integrates <a target="_blank" href="https://en.wikipedia.org/wiki/CBC-MAC">CBC-MAC</a>, a block cipher method for constructing a MAC.</p>
<p>AES itself is on good footing. The AES specification was established in 2001 by the U.S. National Institute of Standards and Technology (NIST). They made their choice after a five-year competitive selection process during which fifteen proposals for algorithm designs were evaluated. </p>
<p>As a result of this process, a family of ciphers called Rijndael (Dutch) was selected, and a subset of these became AES. </p>
<p>For the better part of two decades, AES has been used to protect every-day Internet traffic as well as <a target="_blank" href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard#Security">certain levels of classified information in the U.S. Government</a>.</p>
<p>While <a target="_blank" href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard#Known_attacks">possible attacks on AES</a> have been described, none have yet been proven to be practical in real-world use. The fastest <a target="_blank" href="https://web.archive.org/web/20141230025103/http://research.microsoft.com/en-us/projects/cryptanalysis/aesbc.pdf">attack on AES</a> in public knowledge is a <a target="_blank" href="https://en.wikipedia.org/wiki/Key-recovery_attack">key-recovery attack</a> that improved on brute-forcing AES by a factor of about four. How long would it take? Some <a target="_blank" href="https://web.archive.org/web/20150108165723/https://blog.agilebits.com/2011/08/18/aes-encryption-isnt-cracked/">billions of years</a>.</p>
<h2 id="heading-wi-fi-protected-access-iii-wpa3">Wi-Fi Protected Access III (WPA3)</h2>
<p><img src="https://victoria.dev/blog/wpa-key-wpa2-wpa3-and-wep-key-wi-fi-security-explained/wpa3.png" alt="WPA3 illustration" width="600" height="400" loading="lazy"></p>
<p>The next installment of the WPA trilogy has been <a target="_blank" href="https://www.wi-fi.org/download.php?file=/sites/default/files/private/Certification_Overview_v5.2_0.pdf">required for new devices</a> since July 1, 2020. Expected to further enhance the security of WPA2, the <a target="_blank" href="https://www.wi-fi.org/news-events/newsroom/wi-fi-alliance-introduces-wi-fi-certified-wpa3-security">WPA3 standard</a> seeks to improve password security by being more resilient to word list or <a target="_blank" href="https://en.wikipedia.org/wiki/Dictionary_attack">dictionary attacks</a>.</p>
<p>Unlike its predecessors, WPA3 will also offer <a target="_blank" href="https://en.wikipedia.org/wiki/Forward_secrecy">forward secrecy</a>. This adds the considerable benefit of protecting previously exchanged information even if a long-term secret key is compromised. </p>
<p>Forward secrecy is already provided by protocols like TLS by using asymmetric keys to establish shared keys. You can learn <a target="_blank" href="https://www.freecodecamp.org/news/what-is-tls-transport-layer-security-encryption-explained-in-plain-english/">more about TLS in this post</a>.</p>
<p>As WPA2 has not been deprecated, so both WPA2 and WPA3 remain your top choices for Wi-Fi security.</p>
<h2 id="heading-if-the-other-ones-are-no-good-why-are-they-still-around">If the other ones are no good, why are they still around?</h2>
<p>You may be wondering why your access point even allows you to choose an option other than WPA2 or WPA3. The likely reason is that you’re using legacy hardware, which is what tech people call your mom’s router.</p>
<p>Since the deprecation of WEP and WPA occurred rather recently, it’s possible in large organizations as well as your parent’s house to find older hardware that still uses these protocols. Even newer hardware may have a business need to support these older protocols.</p>
<p>While I may be able to convince you to invest in a shiny new top-of-the-line Wi-Fi appliance, most organizations are a different story. Unfortunately, many just aren’t yet cognizant of the important role cybersecurity plays in meeting customer needs and boosting that bottom line. </p>
<p>Additionally, switching to newer protocols may require new internal hardware or firmware upgrades. Especially on complex systems in large organizations, upgrading devices can be financially or strategically difficult.</p>
<h2 id="heading-boost-your-wi-fi-security">Boost your Wi-Fi security</h2>
<p>If it’s an option, choose WPA2 or WPA3. Cybersecurity is a field that evolves by the day, and getting stuck in the past can have dire consequences.</p>
<p>If you can’t use WPA2 or WPA3, do the best you can to take additional security measures. </p>
<p>The best bang for your buck is to use a Virtual Private Network (VPN). Using a VPN is a good idea no matter which type of Wi-Fi encryption you have. On open Wi-Fi (coffee shops) and using WEP, it’s plain irresponsible to go without a VPN. </p>
<p>It's kind of like shouting out your bank details as you order your second cappuccino.</p>
<p><img src="https://victoria.dev/blog/wpa-key-wpa2-wpa3-and-wep-key-wi-fi-security-explained/cafewifi.png" alt="A cartoon of shouting out your bank details at a coffeeshop." width="600" height="400" loading="lazy"></p>
<p>Choose a VPN provider that offers a feature like a kill switch that blocks your network traffic if your VPN becomes disconnected. This prevents you from accidentally transmitting information on an insecure connection like open Wi-Fi or WEP. I wrote more about my top three considerations for <a target="_blank" href="https://victoria.dev/blog/vpn">choosing my VPN in this post</a>.</p>
<p>When possible, ensure you only connect to known networks that you or your organization control. </p>
<p>Many cybersecurity attacks are executed when victims connect to an imitation public Wi-Fi access point, also called an evil twin attack, or Wi-Fi phishing. </p>
<p>These fake hotspots are easily created using publicly accessible programs and tools. A VPN can help mitigate damage from these attacks as well, but it’s always better not to take the risk. </p>
<p>If you travel often, consider purchasing a portable hotspot that uses a cellular data plan, or using data SIM cards for all your devices.</p>
<h2 id="heading-much-more-than-just-acronyms">Much more than just acronyms</h2>
<p>WEP, WPA, WPA2, and WPA3 mean a lot more than a bunch of similar letters – in some cases, it’s a difference of billions of years minus about 60 seconds.</p>
<p>On more of a now-ish timescale, I hope I’ve taught you something new about the security of your Wi-Fi and how you can improve it!</p>
<p>If you enjoyed this post, I'd love to know. Join the thousands of people who learn along with me on <a target="_blank" href="https://victoria.dev/">victoria.dev</a>! Visit or <a target="_blank" href="https://victoria.dev/index.xml">subscribe via RSS</a> for more programming, cybersecurity, and cartoon dad jokes.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Django Test Suite Introduction – How to Increase Your Confidence as a Python Developer ]]>
                </title>
                <description>
                    <![CDATA[ Some developers regard writing tests as a lame checkbox task – but nothing could be farther from the truth. Done correctly, tests are one of your application’s most valuable assets. The Django framework in particular offers your team the opportunity ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/increase-developer-confidence-with-a-great-django-test-suite/</link>
                <guid isPermaLink="false">66bd8f641753e79ad3537321</guid>
                
                    <category>
                        <![CDATA[ Django ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Testing ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Mon, 05 Oct 2020 21:18:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/10/cover.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Some developers regard writing tests as a lame checkbox task – but nothing could be farther from the truth. Done correctly, tests are one of your application’s most valuable assets.</p>
<p>The Django framework in particular offers your team the opportunity to create an efficient testing practice, based on the Python standard library <code>unittest</code>. </p>
<p>Proper tests in Django are fast to write, faster to run, and can offer you a seamless continuous integration solution for taking the pulse of your developing application.</p>
<p>With comprehensive tests, developers have higher confidence when pushing changes. I’ve seen firsthand in my own teams that good tests can boost development velocity as a direct result of a better developer experience.</p>
<p>In this article, I’ll share my own experiences in building useful tests for Django applications, from the basics to the best possible execution. If you're using Django or building with it in your organization, you might like to read my <a target="_blank" href="https://victoria.dev/series/django/">Django series on Victoria.dev.</a></p>
<h2 id="heading-what-to-test">What to test</h2>
<p>Tests are extremely important. Far beyond simply letting you know if a function works, tests can form the basis of your team’s understanding of how your application is <em>intended</em> to work.</p>
<p>Here’s the main goal: if you hit your head and forgot everything about how your application works tomorrow, you should be able to regain most of your understanding by reading and running the tests you write today.</p>
<p>Here are some questions that may be helpful to ask as you decide what to test:</p>
<ul>
<li>What is your customer supposed to be able to do?</li>
<li>What is your customer <em>not</em> supposed to be able to do?</li>
<li>What should this method, view, or logical flow achieve?</li>
<li>When, how, or where is this feature supposed to execute?</li>
</ul>
<p>Tests that make sense for your application can help build developer confidence. </p>
<p>With these sensible safeguards in place, developers make improvements more readily, and feel confident introducing innovative solutions to product needs. The result is an application that comes together faster, and features that are shipped often and with confidence.</p>
<p><img src="https://victoria.dev/blog/increase-developer-confidence-with-a-great-django-test-suite/pbj-tests.png" alt="A cartoon for peanut butter and jelly sandwich tests" width="600" height="400" loading="lazy">
<em>A cartoon created by a programmer and a mathematician, if you couldn't tell.</em></p>
<h2 id="heading-where-to-put-tests">Where to put tests</h2>
<p>If you only have a few tests, you may organize your test files similarly to <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/django-admin/#startapp">Django’s default app template</a> by putting them all in a file called <code>tests.py</code>. This straightforward approach is best for smaller applications.</p>
<p>As your application grows, you may like to split your tests into different files, or test modules. One method is to use a directory to organize your files, such as <code>projectroot/app/tests/</code>. The name of each test file within that directory should begin with <code>test</code>, for example, <code>test_models.py</code>.</p>
<p>Besides being aptly named, Django will find these files using <a target="_blank" href="https://docs.python.org/3/library/unittest.html#unittest-test-discovery">built-in test discovery</a> based on the <code>unittest</code> module. All files in your application with names that begin with <code>test</code> will be collected into a test suite.</p>
<p>This convenient test discovery allows you to place test files anywhere that makes sense for your application. As long as they’re correctly named, Django’s test utility can find and run them.</p>
<h2 id="heading-how-to-document-a-test">How to document a test</h2>
<p>Use <a target="_blank" href="https://www.python.org/dev/peps/pep-0257/">docstrings</a> to explain what a test is intended to verify at a high level. For example:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_create_user</span>(<span class="hljs-params">self</span>):</span>
    <span class="hljs-string">"""Creating a new user object should also create an associated profile object"""</span>
    <span class="hljs-comment"># ...</span>
</code></pre>
<p>These docstrings help you quickly understand what a test is supposed to be doing. Besides navigating the codebase, this helps to make it obvious when a test doesn’t verify what the docstring says it should.</p>
<p>Docstrings are also shown when the tests are being run, which can be helpful for logging and debugging.</p>
<h2 id="heading-what-a-test-needs-to-work">What a test needs to work</h2>
<p>Django tests can be quickly set up using data created in the <a target="_blank" href="https://docs.djangoproject.com/en/3.1/topics/testing/tools/#django.test.TestCase.setUpTestData"><code>setUpTestData()</code> method</a>. You can use various approaches to create your test data, such as utilizing external files, or even hard-coding silly phrases or the names of your staff. </p>
<p>Personally, I much prefer to use a fake-data-generation library, such as <a target="_blank" href="https://github.com/joke2k/faker/"><code>faker</code></a>.</p>
<p>The proper set up of arbitrary testing data can help you ensure that you’re testing your application functionality instead of accidentally testing test data. Because generators like <code>faker</code> add some degree of unexpectedness to your inputs, it can be more representative of real-world use.</p>
<p>Here is an example set up for a test:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.test <span class="hljs-keyword">import</span> TestCase
<span class="hljs-keyword">from</span> faker <span class="hljs-keyword">import</span> Faker

<span class="hljs-keyword">from</span> app.models <span class="hljs-keyword">import</span> MyModel, AnotherModel

fake = Faker()


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyModelTest</span>(<span class="hljs-params">TestCase</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">setUpTestData</span>(<span class="hljs-params">cls</span>):</span>
        <span class="hljs-string">"""Quickly set up data for the whole TestCase"""</span>
        cls.user_first = fake.first_name()
        cls.user_last = fake.last_name()

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_create_models</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-string">"""Creating a MyModel object should also create AnotherModel object"""</span>
        <span class="hljs-comment"># In test methods, use the variables created above</span>
        test_object = MyModel.objects.create(
            first_name=self.user_first,
            last_name=self.user_last,
            <span class="hljs-comment"># ...</span>
        )
        another_model = AnotherModel.objects.get(my_model=test_object)
        self.assertEqual(another_model.first_name, self.user_first)
        <span class="hljs-comment"># ...</span>
</code></pre>
<p>Tests pass or fail based on the outcome of the assertion methods. You can use <a target="_blank" href="https://docs.python.org/3/library/unittest.html#assert-methods">Python’s <code>unittest</code> methods</a>, and <a target="_blank" href="https://docs.djangoproject.com/en/3.1/topics/testing/tools/#assertions">Django’s assertion methods</a>.</p>
<p>For further guidance on writing tests, see <a target="_blank" href="https://docs.djangoproject.com/en/3.1/topics/testing/">Testing in Django</a>.</p>
<h2 id="heading-best-possible-execution-for-running-your-tests">Best possible execution for running your tests</h2>
<p>Django’s test suite is manually run with:</p>
<pre><code class="lang-shell">./manage.py test
</code></pre>
<p>I rarely run my Django tests this way.</p>
<p>The best, or most efficient, testing practice is one that occurs without you or your developers ever thinking, “I need to run the tests first.” </p>
<p>The beauty of Django’s near-effortless test suite set up is that it can be seamlessly run as a part of regular developer activities. This could be in a pre-commit hook, or in a continuous integration or deployment workflow.</p>
<p>I’ve previously written about how to use pre-commit hooks to <a target="_blank" href="https://victoria.dev/blog/technical-ergonomics-for-the-efficient-developer/">improve your developer ergonomics</a> and save your team some brainpower. Django’s speedy tests can be run this way, and they become especially efficient if you can <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/django-admin/#cmdoption-test-parallel">run tests in parallel</a>.</p>
<p>Tests that run as part of a CI/CD workflow, for example, <a target="_blank" href="https://victoria.dev/blog/django-project-best-practices-to-keep-your-developers-happy/#continuous-testing-with-github-actions">on pull requests with GitHub Actions</a>, require no regular effort from your developers to remember to run tests at all. I’m not sure how plainly I can put it – this one’s literally a no-brainer.</p>
<h2 id="heading-testing-your-way-to-a-great-django-application">Testing your way to a great Django application</h2>
<p>Tests are extremely important, and under-appreciated. They can catch logical errors in your application. They can help explain and validate how concepts and features of your product actually function. Best of all, tests can boost developer confidence and development velocity as a result.</p>
<p>The best tests are ones that are relevant, help to explain and define your application, and are run continuously without a second thought. I hope I’ve now shown you how testing in Django can help you to achieve these goals for your team!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Django Project Best Practices That'll Keep Your Developers Happy ]]>
                </title>
                <description>
                    <![CDATA[ Do you want your team to enjoy your development workflow? Do you think building software should be fun and existentially fulfilling? If so, this is the post for you. I’ve been developing with Django for years, and I’ve never been happier with my Djan... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/django-project-best-practices-for-happy-developers/</link>
                <guid isPermaLink="false">66bd8f236d46d5e73b73e907</guid>
                
                    <category>
                        <![CDATA[ best practices ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Django ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Thu, 24 Sep 2020 16:24:57 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/cover-4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Do you want your team to <em>enjoy</em> your development workflow? Do you think building software should be <em>fun and existentially fulfilling?</em> If so, this is the post for you.</p>
<p>I’ve been developing with Django for years, and I’ve never been happier with my Django project set up than I am right now. </p>
<p>In this article, I'll explain how I make a day of developing with Django the most relaxing and enjoyable development experience possible for myself and my engineering team.</p>
<h2 id="heading-a-custom-cli-tool-for-your-django-project">A custom CLI tool for your Django project</h2>
<p>Instead of typing:</p>
<pre><code class="lang-sh">python3 -m venv env
<span class="hljs-built_in">source</span> env/bin/activate
pip install -r requirements.txt
python3 manage.py makemigrations
python3 manage.py migrate
python3 manage.py collectstatic
python3 manage.py runserver
</code></pre>
<p>Wouldn’t it be much nicer to type:</p>
<pre><code class="lang-sh">make start
</code></pre>
<p>…and have all that happen for you? I think so! </p>
<p>We can do that with a self-documenting Makefile. Here’s one I frequently use when developing my Django applications, like <a target="_blank" href="https://applybyapi.com/">ApplyByAPI.com</a>:</p>
<pre><code class="lang-makefile">SHELL := /bin/bash

<span class="hljs-keyword">include</span> .env

<span class="hljs-meta"><span class="hljs-meta-keyword">.PHONY</span>: help</span>
<span class="hljs-section">help: ## Show this help</span>
    @egrep -h '\s<span class="hljs-comment">##\s' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'</span>

<span class="hljs-meta"><span class="hljs-meta-keyword">.PHONY</span>: venv</span>
<span class="hljs-section">venv: ## Make a new virtual environment</span>
    python3 -m venv <span class="hljs-variable">$(VENV)</span> &amp;&amp; source <span class="hljs-variable">$(BIN)</span>/activate

<span class="hljs-meta"><span class="hljs-meta-keyword">.PHONY</span>: install</span>
<span class="hljs-section">install: venv ## Make venv and install requirements</span>
    <span class="hljs-variable">$(BIN)</span>/pip install -r requirements.txt

<span class="hljs-section">migrate: ## Make and run migrations</span>
    <span class="hljs-variable">$(PYTHON)</span> manage.py makemigrations
    <span class="hljs-variable">$(PYTHON)</span> manage.py migrate

<span class="hljs-section">db-up: ## Pull and start the Docker Postgres container in the background</span>
    docker pull postgres
    docker-compose up -d

<span class="hljs-section">db-shell: ## Access the Postgres Docker database interactively with psql</span>
    docker exec -it container_name psql -d <span class="hljs-variable">$(DBNAME)</span>

<span class="hljs-meta"><span class="hljs-meta-keyword">.PHONY</span>: test</span>
<span class="hljs-section">test: ## Run tests</span>
    <span class="hljs-variable">$(PYTHON)</span> <span class="hljs-variable">$(APP_DIR)</span>/manage.py test application --verbosity=0 --parallel --failfast

<span class="hljs-meta"><span class="hljs-meta-keyword">.PHONY</span>: run</span>
<span class="hljs-section">run: ## Run the Django server</span>
    <span class="hljs-variable">$(PYTHON)</span> <span class="hljs-variable">$(APP_DIR)</span>/manage.py runserver

<span class="hljs-section">start: install migrate run ## Install requirements, apply migrations, then start development server</span>
</code></pre>
<p>You’ll notice the presence of the line <code>include .env</code> above. This ensures <code>make</code> has access to environment variables stored in a file called <code>.env</code>. </p>
<p>This allows Make to utilize these variables in its commands, for example, the name of my virtual environment, or to pass in <code>$(DBNAME)</code> to <code>psql</code>.</p>
<p>What’s with that weird “<code>##</code>” comment syntax? A Makefile like this gives you a handy suite of command-line aliases you can check in to your Django project. It’s very useful so long as you’re able to remember what all those aliases are. </p>
<p>The <code>help</code> command above, which runs by default, prints a helpful list of available commands when you run <code>make</code> or <code>make help</code>:</p>
<pre><code class="lang-text">help                 Show this help
venv                 Make a new virtual environment
install              Make venv and install requirements
migrate              Make and run migrations
db-up                Pull and start the Docker Postgres container in the background
db-shell             Access the Postgres Docker database interactively with psql
test                 Run tests
run                  Run the Django server
start                Install requirements, apply migrations, then start development server
</code></pre>
<p>All the usual Django commands are covered, and we’ve got a <code>test</code> command that runs our tests with the options we prefer. Brilliant.</p>
<p>You can read my full <a target="_blank" href="https://victoria.dev/blog/how-to-create-a-self-documenting-makefile/">post about self-documenting Makefiles here</a>, which also includes an example Makefile using <code>pipenv</code>.</p>
<h2 id="heading-save-your-brainpower-with-pre-commit-hooks">Save your brainpower with pre-commit hooks</h2>
<p>I previously wrote about some <a target="_blank" href="https://victoria.dev/blog/technical-ergonomics-for-the-efficient-developer/">technical ergonomics</a> that can make it a lot easier for teams to develop great software. </p>
<p>One area that’s a no-brainer is using pre-commit hooks to lint code prior to checking it in. </p>
<p>This helps maintain the quality of the code your developers check in. But most importantly, it ensures that no one on your team is spending time trying to remember if it should be single or double quotes or where to put a line break.</p>
<p>The confusingly-named <a target="_blank" href="https://pre-commit.com/">pre-commit framework</a> is an otherwise fantastic way to keep hooks (which are not included in cloned repositories) consistent across local environments. </p>
<p>Here is my configuration file, <code>.pre-commit-config.yaml</code>, for my Django projects:</p>
<pre><code class="lang-yaml"><span class="hljs-attr">fail_fast:</span> <span class="hljs-literal">true</span>
<span class="hljs-attr">repos:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">repo:</span> <span class="hljs-string">https://github.com/pre-commit/pre-commit-hooks</span>
    <span class="hljs-attr">rev:</span> <span class="hljs-string">v3.1.0</span>
    <span class="hljs-attr">hooks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">id:</span> <span class="hljs-string">detect-aws-credentials</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">repo:</span> <span class="hljs-string">https://github.com/psf/black</span>
    <span class="hljs-attr">rev:</span> <span class="hljs-number">19.</span><span class="hljs-string">3b0</span>
    <span class="hljs-attr">hooks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">id:</span> <span class="hljs-string">black</span>
  <span class="hljs-bullet">-</span> <span class="hljs-attr">repo:</span> <span class="hljs-string">https://github.com/asottile/blacken-docs</span>
    <span class="hljs-attr">rev:</span> <span class="hljs-string">v1.7.0</span>
    <span class="hljs-attr">hooks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">id:</span> <span class="hljs-string">blacken-docs</span>
        <span class="hljs-attr">additional_dependencies:</span> [<span class="hljs-string">black==19.3b0</span>]
  <span class="hljs-bullet">-</span> <span class="hljs-attr">repo:</span> <span class="hljs-string">local</span>
    <span class="hljs-attr">hooks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">id:</span> <span class="hljs-string">markdownlint</span>
        <span class="hljs-attr">name:</span> <span class="hljs-string">markdownlint</span>
        <span class="hljs-attr">description:</span> <span class="hljs-string">"Lint Markdown files"</span>
        <span class="hljs-attr">entry:</span> <span class="hljs-string">markdownlint</span> <span class="hljs-string">'**/*.md'</span> <span class="hljs-string">--fix</span> <span class="hljs-string">--ignore</span> <span class="hljs-string">node_modules</span> <span class="hljs-string">--config</span> <span class="hljs-string">"./.markdownlint.json"</span>
        <span class="hljs-attr">language:</span> <span class="hljs-string">node</span>
        <span class="hljs-attr">types:</span> [<span class="hljs-string">markdown</span>]
</code></pre>
<p>These hooks check for accidental secret commits, format Python files using <a target="_blank" href="https://github.com/psf/black">Black</a>, format Python snippets in Markdown files using <a target="_blank" href="https://github.com/asottile/blacken-docs"><code>blacken-docs</code></a>, and <a target="_blank" href="https://github.com/igorshubovych/markdownlint-cli">lint Markdown files</a> as well. </p>
<p>There are likely even more useful hooks available for your particular use case: see <a target="_blank" href="https://pre-commit.com/hooks.html">supported hooks</a> to explore.</p>
<h2 id="heading-useful-gitignores">Useful gitignores</h2>
<p>An under-appreciated way to improve your team’s daily development experience is to make sure your project uses a well-rounded <code>.gitignore</code> file. </p>
<p>This can help prevent files containing secrets from being committed, and can additionally save developers hours of tedium by ensuring you’re never sifting through a <code>git diff</code> of generated files.</p>
<p>To efficiently create a <a target="_blank" href="https://www.toptal.com/developers/gitignore/api/python,django">gitignore for Python and Django projects</a>, Toptal’s <a target="_blank" href="https://gitignore.io/">gitignore.io</a> can be a nice resource for generating a robust <code>.gitignore</code> file. </p>
<p>I still recommend examining the generated results yourself to ensure that ignored files suit your use case, and that nothing you want ignored is commented out.</p>
<h2 id="heading-continuous-testing-with-github-actions">Continuous testing with GitHub Actions</h2>
<p>If your team works on GitHub, setting up a testing process with Actions is low-hanging fruit. </p>
<p>Tests that run in a consistent environment on every pull request can help eliminate “works on my machine” conundrums. They can also help ensure that no one’s sitting around waiting for a test to run locally.</p>
<p>A hosted CI environment like GitHub Actions can also help when running integration tests that require using managed services resources. </p>
<p>You can use <a target="_blank" href="https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets">encrypted secrets in a repository</a> to grant the Actions runner access to resources in a testing environment, without worrying about creating testing resources and access keys for each of your developers to use.</p>
<p>I’ve written on many occasions about setting up Actions workflows, including <a target="_blank" href="https://victoria.dev/blog/a-lightweight-tool-agnostic-ci/cd-flow-with-github-actions/">using one to run your Makefile</a>, and <a target="_blank" href="https://victoria.dev/blog/publishing-github-event-data-with-github-actions-and-pages/">how to integrate GitHub event data</a>. GitHub even <a target="_blank" href="https://github.blog/2020-06-26-github-action-hero-victoria-drake/">interviewed me about Actions</a> once.</p>
<p>For Django projects, here’s a simple GitHub Actions workflow that runs tests with a consistent Python version.</p>
<pre><code class="lang-yaml"><span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">Django</span> <span class="hljs-string">tests</span>

<span class="hljs-attr">on:</span> <span class="hljs-string">push</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">test:</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">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Set</span> <span class="hljs-string">up</span> <span class="hljs-string">Python</span>
        <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-python@v2</span>
        <span class="hljs-attr">with:</span>
          <span class="hljs-attr">python-version:</span> <span class="hljs-string">'3.8'</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">make</span> <span class="hljs-string">install</span>
      <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Run</span> <span class="hljs-string">tests</span>
        <span class="hljs-attr">run:</span> <span class="hljs-string">make</span> <span class="hljs-string">test</span>
</code></pre>
<p>For the installation and test commands, I’ve simply utilized the <a target="_blank" href="https://victoria.dev/blog/my-django-project-best-practices-for-happy-developers/#a-custom-cli-tool-for-your-django-project">Makefile</a> that’s been checked in to the repository. </p>
<p>A benefit of using your Makefile commands in your CI test workflows is that you only need to keep them updated in one place – your Makefile! No more “why is this working locally but not in CI??!?” headaches.</p>
<p>If you want to step up your security game, you can add <a target="_blank" href="https://github.com/victoriadrake/django-security-check">Django Security Check</a> as an Action too.</p>
<h2 id="heading-set-up-your-django-project-for-success">Set up your Django project for success</h2>
<p>Want to help keep your development team happy? Set them up for success with these best practices for Django development. </p>
<p>Remember, an ounce of brainpower is worth a pound of software.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Manipulate Data with Django Migrations ]]>
                </title>
                <description>
                    <![CDATA[ In this article, we'll learn how to update Django models and manipulate existing data using migrations. Successful applications that are growing are a lovely problem to have. As a product develops, it tends to accumulate complication the way your wee... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-manipulate-data-with-django-migrations/</link>
                <guid isPermaLink="false">66bd8f4827629f4c5e1893ae</guid>
                
                    <category>
                        <![CDATA[ database ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Django ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Thu, 17 Sep 2020 16:23:19 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/cover-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, we'll learn how to update Django models and manipulate existing data using migrations.</p>
<p>Successful applications that are growing are a lovely problem to have. As a product develops, it tends to accumulate complication the way your weekend cake project accumulates layers of frosting. </p>
<p>Thankfully, Django, my favorite batteries-included framework, handles complexity pretty well.</p>
<p>Django <a target="_blank" href="https://victoria.dev/blog/writing-efficient-django/#django-models">models help humans work with data in a way that makes sense to our brains</a>. And the framework offers plenty of classes you can inherit to help you rapidly develop a robust application from scratch. </p>
<p>As for developing on existing Django applications, there’s a feature for that, too. </p>
<p>In this article, we’ll cover how to use Django migrations to update your existing models and database.</p>
<h2 id="heading-whats-under-the-hood">What’s under the hood</h2>
<p>Django migrations are Python files that help you add and change things in your database tables to reflect changes in your Django models. </p>
<p>To understand how Django migrations help you work with data, it may be helpful to understand the underlying structures we’re working with.</p>
<h3 id="heading-whats-a-database-table">What’s a database table?</h3>
<p>If you’ve laid eyes on a spreadsheet before, you’re already most of the way to understanding a database table. </p>
<p>In a relational database, for example, a PostgreSQL database, you can expect to see data organized into columns and rows. A relational database table may have a set number of columns and any number of rows.</p>
<p>In Django, each model is its own table. For example, here’s a Django model:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Lunch</span>(<span class="hljs-params">models.Model</span>):</span>
    left_side = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    center = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    right_side = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
</code></pre>
<p>Each field is a column, and each row is a Django object instance of that model. </p>
<p>Here’s a representation of a database table for the Django model “Lunch” above. In the database, its name would be <code>lunch_table</code>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>id</td><td>left_side</td><td>center</td><td>right_side</td></tr>
</thead>
<tbody>
<tr>
<td>1</td><td>Fork</td><td>Plate</td><td>Spoon</td></tr>
</tbody>
</table>
</div><p>The model <code>Lunch</code> has three fields: <code>left_side</code>, <code>center</code>, and <code>right-side</code>. One instance of a <code>Lunch</code> object would have “Fork” for the <code>left_side</code>, a “Plate” for the <code>center</code>, and “Spoon” for the <code>right_side</code>. </p>
<p>Django <a target="_blank" href="https://docs.djangoproject.com/en/3.1/topics/db/models/#automatic-primary-key-fields">automatically adds an <code>id</code> field</a> if you don’t specify a primary key.</p>
<p>If you wanted to change the name of your Lunch model, you would do so in your <code>models.py</code> code. </p>
<p>For example, change “Lunch” to “Dinner,” then <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/django-admin/#makemigrations">run <code>python manage.py makemigrations</code></a>. You’ll see:</p>
<pre><code class="lang-text">python manage.py makemigrations
Did you rename the backend.Lunch model to Dinner? [y/N] y
Migrations for 'backend':
  backend/migrations/0003_auto_20200922_2331.py
    - Rename model Lunch to Dinner
</code></pre>
<p>Django automatically generates the appropriate migration files. The relevant line of the generated migrations file in this case would look like:</p>
<pre><code class="lang-python">migrations.RenameModel(old_name=<span class="hljs-string">"Lunch"</span>, new_name=<span class="hljs-string">"Dinner"</span>),
</code></pre>
<p>This operation would rename our “Lunch” model to “Dinner” while keeping everything else the same. </p>
<p>But what if you also wanted to change the structure of the database table itself, its schema, as well as make sure that existing data ends up in the right place on your Dinner table?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/cover-2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Terrible cartoon by author.</em></p>
<p>Let’s explore how to turn our Lunch model into a Dinner model that looks like this:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> django.db <span class="hljs-keyword">import</span> models


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dinner</span>(<span class="hljs-params">models.Model</span>):</span>
    top_left = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    top_center = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    top_right = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    bottom_left = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    bottom_center = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    bottom_right = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
</code></pre>
<p>…with a database table that would look like this:</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>id</td><td>top_left</td><td>top_center</td><td>top_right</td><td>bottom_left</td><td>bottom_center</td><td>bottom_right</td></tr>
</thead>
<tbody>
<tr>
<td>1</td><td>Bread plate</td><td>Spoon</td><td>Glass</td><td>Fork</td><td>Plate</td><td>Knife</td></tr>
</tbody>
</table>
</div><h2 id="heading-how-to-manipulate-data-with-django-migrations">How to manipulate data with Django migrations</h2>
<p>Before you begin to manipulate your data, it’s always a good idea to create a backup of your database that you can restore in case something goes wrong. </p>
<p>There are various ways to do this depending on the database you’re using. You can typically find instructions by searching for <code>&lt;your database name&gt;</code> and keywords like <code>backup</code>, <code>recovery</code>, or <code>snapshot</code>.</p>
<p>In order to design your migration, it’s helpful to become familiar with the available <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/migration-operations/">migration operations</a>. </p>
<p>Migrations are run step-by-step, and each operation is some flavor of adding, removing, or altering data. Like a strategic puzzle, it’s important to make model changes one step at a time so that the generated migrations have the correct result.</p>
<p>We’ve already renamed our model successfully. Now, we’ll rename the fields that hold the data we want to retain:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dinner</span>(<span class="hljs-params">models.Model</span>):</span>
    bottom_left = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    bottom_center = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    top_center = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
</code></pre>
<p>Django is sometimes smart enough to determine the old and new field names correctly. You’ll be asked for confirmation:</p>
<pre><code class="lang-text">python manage.py makemigrations
Did you rename dinner.center to dinner.bottom_center (a CharField)? [y/N] y
Did you rename dinner.left_side to dinner.bottom_left (a CharField)? [y/N] y
Did you rename dinner.right_side to dinner.top_center (a CharField)? [y/N] y
Migrations for 'backend':
  backend/migrations/0004_auto_20200914_2345.py
    - Rename field center on dinner to bottom_center
    - Rename field left_side on dinner to bottom_left
    - Rename field right_side on dinner to top_center
</code></pre>
<p>In some cases, you’ll want to try renaming the field and running <code>makemigrations</code> one at a time.</p>
<p>Now that the existing fields have been migrated to their new names, add the remaining fields to the model:</p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Dinner</span>(<span class="hljs-params">models.Model</span>):</span>
    top_left = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    top_center = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    top_right = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    bottom_left = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    bottom_center = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
    bottom_right = models.CharField(max_length=<span class="hljs-number">100</span>, null=<span class="hljs-literal">True</span>)
</code></pre>
<p>Running <code>makemigrations</code> again now gives us:</p>
<pre><code class="lang-text">python manage.py makemigrations
Migrations for 'backend':
  backend/migrations/0005_auto_20200914_2351.py
    - Add field bottom_right to dinner
    - Add field top_left to dinner
    - Add field top_right to dinner
</code></pre>
<p>You’re done! By generating Django migrations, you’ve successfully set up your <code>dinner_table</code> and moved existing data to its new spot.</p>
<h2 id="heading-additional-complexity">Additional complexity</h2>
<p>You’ll notice that our Lunch and Dinner models are not very complex. Out of Django’s many <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/models/fields/#field-types">model field options</a>, we’re just using <code>CharField</code>. We also set <code>null=True</code> to let Django store empty values as <code>NULL</code> in the database.</p>
<p>Django migrations can handle additional complexity, such as changing field types, and whether a blank or null value is permitted. I keep Django’s <a target="_blank" href="https://docs.djangoproject.com/en/3.1/ref/models/fields/#">model field reference</a> handy as I work with varying types of data and different use cases.</p>
<h2 id="heading-de-mystified-migrations">De-mystified migrations</h2>
<p>I hope this article has helped you better understand Django migrations and how they work!</p>
<p>Now that you can change models and manipulate existing data in your Django application, be sure to use your powers wisely. </p>
<p>Backup your database, research and plan your migrations, and always run tests before working with customer data. By doing so, you have the potential to enable your application to grow – with manageable levels of complexity.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What is TLS? Transport Layer Security Encryption Explained in Plain English ]]>
                </title>
                <description>
                    <![CDATA[ If you want to have a confidential conversation with someone you know, you might meet up in person and find a private place to talk.  But if you want to send data confidentially over the Internet, you might have a few more considerations to cover. TL... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-is-tls-transport-layer-security-encryption-explained-in-plain-english/</link>
                <guid isPermaLink="false">66bd8f99c1ca1df1936e29e9</guid>
                
                    <category>
                        <![CDATA[ cybersecurity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ information security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ TLS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Tue, 08 Sep 2020 16:39:48 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/09/13466286-1BED-4E1F-A3BE-92A971BBF635.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you want to have a confidential conversation with someone you know, you might meet up in person and find a private place to talk. </p>
<p>But if you want to send data confidentially over the Internet, you might have a few more considerations to cover.</p>
<p>TLS, or Transport Layer Security, refers to a protocol. "Protocol" is a word that means, "the way we've agreed to do things around here," more or less. </p>
<p>The "transport layer" part of TLS simply refers to host-to-host communication, such as how a client and a server interact, in the <a target="_blank" href="https://en.wikipedia.org/wiki/Internet_protocol_suite">Internet protocol suite model</a>.</p>
<p>The TLS protocol attempts to solve these fundamental problems:</p>
<ul>
<li>How do I know you are who you say you are?</li>
<li>How do I know this message from you hasn't been tampered with?</li>
<li>How can we communicate securely?</li>
</ul>
<p>Here's how TLS works, explained in plain English. As with many successful interactions, it begins with a handshake.</p>
<h2 id="heading-getting-to-know-you">Getting to know you</h2>
<p>The basic process of a <a target="_blank" href="https://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_handshake">TLS handshake</a> involves a client, such as your web browser, and a server, such as one hosting a website, establishing some ground rules for communication. </p>
<p>It begins with the client saying hello. Literally. It's called a <em>ClientHello</em> message.</p>
<p>The <em>ClientHello</em> message tells the server which TLS protocol version and <em>cipher suites</em> it supports. </p>
<p>While "cipher suite" sounds like a fancy hotel upgrade, it just refers to a set of algorithms that can be used to secure communications. </p>
<p>The server, in a similarly named <em>ServerHello</em> message, chooses the protocol version and cipher suite to use from the choices offered. Other data may also be sent, for example, a <em>session ID</em>, if the server supports resuming a previous handshake.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/hello-hello.png" alt="Image" width="600" height="400" loading="lazy">
<em>Cartoon of a browser window and server saying hello, by author.</em></p>
<p>Depending on the cipher suite chosen, the client and server exchange further information in order to establish a shared secret. </p>
<p>Often, this process moves the exchange from <a target="_blank" href="https://en.wikipedia.org/wiki/Public-key_cryptography">asymmetric cryptography</a> to <a target="_blank" href="https://en.wikipedia.org/wiki/Symmetric-key_algorithm">symmetric cryptography</a> with varying levels of complexity. Let's explore these concepts at a general level and see why they matter to TLS.</p>
<h2 id="heading-asymmetric-beginnings">Asymmetric beginnings</h2>
<p>This is asymmetry:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/image.jpeg" alt="Image" width="600" height="400" loading="lazy">
<em>Small egg, big egg.</em></p>
<p>Asymmetric cryptography is one method by which you can perform <em>authentication</em>. When you authenticate yourself, you answer the fundamental question, "How do I know you are who you say you are?"</p>
<p>In an asymmetric cryptographic system, you use a pair of keys in order to achieve authentication. These keys are asymmetric. One key is your public key, which, as you would guess, is public. The other is your private key, which – well, you know.</p>
<p>Typically, during the TLS handshake, the server will provide its public key via its digital certificate, sometimes still called its <em>SSL certificate</em>, though TLS replaces the deprecated Secure Sockets Layer (SSL) protocol. </p>
<p>Digital certificates are provided and verified by trusted third parties known as <a target="_blank" href="https://en.wikipedia.org/wiki/Certificate_authority">Certificate Authorities (CA)</a>, which are a whole other article in themselves.</p>
<p>While anyone may encrypt a message using your public key, only your private key can then decrypt that message. </p>
<p>The security of asymmetric cryptography relies only on your private key staying private, hence the asymmetry. </p>
<p>It's also asymmetric in the sense that it's a one-way trip. Alice can send messages encrypted with your public key to you, but neither of your keys will help you send an encrypted message to Alice.</p>
<h2 id="heading-symmetric-secrets">Symmetric secrets</h2>
<p>Asymmetric cryptography also requires more computational resources than symmetric cryptography. </p>
<p>Thus when a TLS handshake begins with an asymmetric exchange, the client and server will use this initial communication to establish a shared secret, sometimes called a <em>session key</em>. This key is symmetric, meaning that both parties use the same shared secret and must maintain that secrecy for the encryption to be secure.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/09/image-11.png" alt="Image" width="600" height="400" loading="lazy">
<em>Wise person say: share your public key, but keep your shared keys private.</em></p>
<p>By using the initial asymmetric communication to establish a session key, the client and server can rely on the session key being known only to them. For the rest of the session, they'll both use this same shared key to encrypt and decrypt messages, which speeds up communication.</p>
<h2 id="heading-secure-sessions">Secure sessions</h2>
<p>A TLS handshake may use asymmetric cryptography or other cipher suites to establish the shared session key. Once the session key is established, the handshaking portion is complete and the session begins.</p>
<p>The <em>session</em> is the duration of encrypted communication between the client and server. During this time, messages are encrypted and decrypted using the session key that only the client and server have. This ensures that communication is secure.</p>
<p>The integrity of exchanged information is maintained by using a checksum. Messages exchanged using session keys have a <a target="_blank" href="https://en.wikipedia.org/wiki/Message_authentication_code">message authentication code (MAC)</a> attached. This is not the same thing as your device's <a target="_blank" href="https://en.wikipedia.org/wiki/MAC_address">MAC address</a>. The MAC is generated and verified using the session key. </p>
<p>Because of this, either party can detect if a message has been changed before being received. This solves the fundamental question, "How do I know this message from you hasn't been tampered with?"</p>
<p>Sessions can end deliberately, due to network disconnection, or from the client staying idle for too long. Once a session ends, it must be re-established via a new handshake or through previously established secrets called <em>session IDs</em> that allow resuming a session.</p>
<h2 id="heading-tls-and-you">TLS and you</h2>
<p>Let's recap:</p>
<ul>
<li>TLS is a cryptographic protocol for providing secure communication.</li>
<li>The process of creating a secure connection begins with a handshake.</li>
<li>The handshake establishes a shared session key that is then used to secure messages and provide message integrity.</li>
<li>Sessions are temporary, and once ended, must be re-established or resumed.</li>
</ul>
<p>This is just a surface-level skim of the very complex cryptographic systems that help to keep your communications secure. For more depth on the topic, I recommend exploring cipher suites and the various <a target="_blank" href="https://en.wikipedia.org/wiki/Cipher_suite#Supported_algorithms">supported algorithms</a>.</p>
<p>The TLS protocol serves a very important purpose in your everyday life. It helps to secure your emails to family, your online banking activities, and the connection by which you're reading this article. </p>
<p>The <a target="_blank" href="https://en.wikipedia.org/wiki/HTTPS">HTTPS communication protocol</a> is encrypted using TLS. Every time you see that little lock icon in your URL bar, you're experiencing firsthand all the concepts you've just read about in this article. </p>
<p>So now you know the answer to the last question: "How can we communicate securely?"</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Search-and-replace Across Multiple Files in Vim ]]>
                </title>
                <description>
                    <![CDATA[ In this article, you'll learn how to interactively search-and-replace across many files with just two commands, thanks to Vim. While a multitude of methods exist to search for and replace words in a single file, what do you do when you’ve got a strin... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-search-and-replace-across-multiple-files-in-vim/</link>
                <guid isPermaLink="false">66bd8f4d6d46d5e73b73e915</guid>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vim ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Fri, 28 Aug 2020 15:01:11 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/08/cover-5.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, you'll learn how to interactively search-and-replace across many files with just two commands, thanks to Vim.</p>
<p>While a multitude of methods exist to search for and replace words in a single file, what do you do when you’ve got a string to update across multiple unrelated files, all with different names? You harness the power of command line tools, of course!</p>
<p>First, you’ll need to <code>find</code> all the files you want to change. Stringing together what are effectively search queries for <code>find</code> is really only limited by your imagination. </p>
<p>Here’s a simple example that finds Python files:</p>
<pre><code class="lang-sh">find . -name <span class="hljs-string">'*.py'</span>
</code></pre>
<p>The <code>-name</code> test searches for a pattern, such as all files ending in <code>.py</code>. But <code>find</code> can do a lot more with other test conditions, including <code>-regex</code> tests. Run <code>find --help</code> to see the multitude of options.</p>
<p>Further tune your search by using <code>grep</code> to get only the files that contain the string you want to change, such as by adding:</p>
<pre><code class="lang-sh">grep -le <span class="hljs-string">'\&lt;a whale\&gt;'</span>
</code></pre>
<p>The <code>-l</code> option gives you just the file names for all files containing a pattern (denoted with <code>-e</code>) that match “a whale”.</p>
<p>You can also use Vim’s impressive <code>:bufdo</code> which lets you run the same command across multiple buffers. It interactively works with all of these files without the tedium of opening, saving, and closing each file, one at a time.</p>
<p>Let’s plug your powerful <code>find</code>+<code>grep</code> results into Vim with:</p>
<pre><code class="lang-sh">vim `find . -name <span class="hljs-string">'*.py'</span> \
-<span class="hljs-built_in">exec</span> grep -le <span class="hljs-string">'\&lt;a whale\&gt;'</span> {} \;`
</code></pre>
<p>Using backtick-expansion to pass our search to Vim opens up multiple buffers ready to go. (Do <code>:h backtick-expansion</code> in Vim for more.) </p>
<p>Now you can apply the Vim command <code>:bufdo</code> to all of these files and perform actions such as interactive search-and-replace:</p>
<pre><code class="lang-vim">:bufdo %s/a whale/a bowl of petunias/gce
</code></pre>
<p>The <code>g</code> for “global” will change occurrences of the pattern on all lines. The <code>e</code> will omit errors if the pattern is not found. The <code>c</code> option makes this interactive. If you’re feeling confident, you can omit it to make the changes without reviewing each one.</p>
<p>When you’ve finished going through all the buffers, save all the work you’ve completed with:</p>
<pre><code class="lang-vim">:bufdo wq!
</code></pre>
<p>Then bask in the glory of your saved time and effort.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How GitHub Codespaces Can Increase Productivity and Lower Barriers ]]>
                </title>
                <description>
                    <![CDATA[ In this article, we'll take a look at how GitHub Codespaces can help remove barriers for new teammates and contributors. The most recent integration between Visual Studio Code and GitHub really helps make development accessible and welcoming. Now in ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-github-codespaces-increase-productivity-and-lower-barriers/</link>
                <guid isPermaLink="false">66bd8f32ffb0fc5947cc912a</guid>
                
                    <category>
                        <![CDATA[ codespaces ]]>
                    </category>
                
                    <category>
                        <![CDATA[ GitHub ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Tue, 18 Aug 2020 15:36:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/08/cover-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, we'll take a look at how GitHub Codespaces can help remove barriers for new teammates and contributors.</p>
<p>The most recent integration between Visual Studio Code and GitHub really helps make development accessible and welcoming.</p>
<p>Now in beta, <a target="_blank" href="https://docs.github.com/en/github/developing-online-with-codespaces/about-codespaces">GitHub Codespaces</a> provide an online, in-the-browser IDE powered by Visual Studio Code.  </p>
<p>This lets you use this full-featured IDE, complete with extensions, terminal, Git commands, and all the settings you’re accustomed to, on any machine. You can now bring your development workflow anywhere using a tablet or other browser-based device.</p>
<p>Codespaces is great news for open source contributors, too. <a target="_blank" href="https://docs.github.com/en/github/developing-online-with-codespaces/configuring-codespaces-for-your-project">Adding a codespace configuration</a> to your project is a great way to invite new folks to easily start contributing. </p>
<p>A new open source contributor or new hire at your organization can quickly fire up a codespace and get hacking on a <code>good first issue</code> with no local environment set up or installations necessary.</p>
<p><img src="https://victoria.dev/blog/add-productivity-remove-barriers-with-github-codespaces/open-with-codespaces-button.png" alt="Starting a new codespace" width="600" height="400" loading="lazy"></p>
<p>We’ve added codespace configuration settings over at the <a target="_blank" href="https://github.com/OWASP/wstg">OWASP Web Security Testing Guide (WSTG)</a>. Want to take it for a spin? See our <a target="_blank" href="https://github.com/OWASP/wstg/issues">open issues</a>.</p>
<h2 id="heading-configuring-codespaces">Configuring Codespaces</h2>
<p>You can use Visual Studio Code’s <code>.devcontainer</code> folder to configure a development container for your repository as well. </p>
<p>Many <a target="_blank" href="https://github.com/microsoft/vscode-dev-containers/tree/master/containers">pre-built containers are available</a> – just copy the <code>.devcontainer</code> you need to your repository root. If your repository doesn’t have one, a <a target="_blank" href="https://github.com/microsoft/vscode-dev-containers/tree/master/containers/codespaces-linux">default base Linux image</a> will be used.</p>
<p>Here’s a reason to remove <code>.vscode</code> from your <code>.gitignore</code> file. Any new codespaces created in your repository will now respect settings found at <code>.vscode/settings.json</code>.  This means that your online IDE can have the same Workspace configuration as you have on your local machine. Isn’t that useful!</p>
<h2 id="heading-making-codespaces-personal">Making Codespaces Personal</h2>
<p>For next-level <a target="_blank" href="https://docs.github.com/en/github/developing-online-with-codespaces/personalizing-codespaces-for-your-account">dotfiles personalization</a>, consider committing relevant files from your local <code>dotfiles</code> folder as a public GitHub repository at <code>yourusername/dotfiles</code>. </p>
<p>When you create a new codespace, this brings in your configurations, such as shell aliases and preferences, by creating symlinks to dotfiles in your codespace <code>$HOME</code>. This personalizes all the codespaces you create in your account. </p>
<p>Need some inspiration? Browse <a target="_blank" href="https://github.com/victoriadrake/dotfiles">my dotfiles repository on GitHub</a>.</p>
<h2 id="heading-developing-in-codespaces">Developing in Codespaces</h2>
<p><a target="_blank" href="https://docs.github.com/en/github/developing-online-with-codespaces/developing-in-a-codespace">Developing in a codespace</a> is a familiar experience for Visual Studio Code users, right down to running an application locally. </p>
<p>Thanks to <a target="_blank" href="https://docs.github.com/en/github/developing-online-with-codespaces/developing-in-a-codespace">port forwarding</a>, when I run an application in a codespace terminal, clicking on the resulting <code>localhost</code> URL takes me to the appropriate port as output from my codespace. </p>
<p>When I’m working on <a target="_blank" href="https://victoria.dev/">my blog</a> in my codespace, for example, I run <code>hugo serve</code> then click the provided <code>localhost:1313</code> link to see a preview of my changes in another browser tab.</p>
<p>Want to stay in sync between devices? There’s an extension for that. You can <a target="_blank" href="https://docs.github.com/en/github/developing-online-with-codespaces/connecting-to-your-codespace-from-visual-studio-code">connect to your codespace from Visual Studio Code</a> on your local machine so you can always pick up right where you left off.</p>
<h2 id="heading-develop-anywhere">Develop Anywhere</h2>
<p>Codespaces is a super exciting addition to my GitHub workflow. It allows me to access my full development process pretty much anywhere, using devices like my iPad. </p>
<p>It’ll also make it easier for new open source contributors or new hires at your organization to hit the ground running with a set-up IDE. </p>
<p>If you have access to the limited beta, I invite you to spin up a codespace and try <a target="_blank" href="https://github.com/OWASP/wstg/issues">contributing to the WSTG</a>, or to <a target="_blank" href="https://github.com/users/victoriadrake/projects/1">an issue on one of my open source projects</a>.</p>
<p>I’m looking forward to general availability and seeing what the open source community will dream up for GitHub Codespaces next!</p>
<p>And yes – codespaces support <a target="_blank" href="https://github.com/victoriadrake/kabukicho-vscode">your favorite Visual Studio Code theme</a>. ?</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/codespace.png" alt="Image" width="600" height="400" loading="lazy">
<em>Screenshot of a codespace with the [Kabukichō](https://marketplace.visualstudio.com/items?itemName=VictoriaDrake.kabukicho" rel="noopener) theme for Visual Studio Code</em></p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create a Self-Documenting Makefile ]]>
                </title>
                <description>
                    <![CDATA[ My new favorite way to completely underuse a Makefile? Creating personalized, per-project repository workflow command aliases that you can check in. Can a Makefile improve your DevOps and keep developers happy? How awesome would it be if a new develo... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/self-documenting-makefile/</link>
                <guid isPermaLink="false">66bd8f81c1ca1df1936e29e3</guid>
                
                    <category>
                        <![CDATA[ Devops ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ workflow ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Victoria Drake ]]>
                </dc:creator>
                <pubDate>Mon, 10 Aug 2020 13:59:08 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/08/cover-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>My new favorite way to completely underuse a Makefile? Creating personalized, per-project repository workflow command aliases that you can check in.</p>
<p>Can a Makefile improve your DevOps and keep developers happy? How awesome would it be if a new developer working on your project didn’t start out by copying and pasting commands from your README? What if instead of:</p>
<pre><code class="lang-shell">pip3 install pipenv
pipenv shell --python 3.8
pipenv install --dev
npm install
pre-commit install --install-hooks
# look up how to install Framework X...
# copy and paste from README...
npm run serve
</code></pre>
<p>… you could just type:</p>
<p><code>make start</code></p>
<p>…and then start working?</p>
<h2 id="heading-making-a-difference">Making a difference</h2>
<p>I use <code>make</code> every day to take the tedium out of common development activities like updating programs, installing dependencies, and testing. </p>
<p>To do all this with a Makefile (GNU make), we use <a target="_blank" href="https://www.gnu.org/software/make/manual/make.html#Rules">Makefile rules</a> and <a target="_blank" href="https://www.gnu.org/software/make/manual/make.html#Recipes">recipes</a>. Similar parallels exist for POSIX flavor make, like <a target="_blank" href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html#tag_20_76_13_04">Target Rules</a>. Here’s a <a target="_blank" href="https://nullprogram.com/blog/2017/08/20/">great article</a> on POSIX-compatible Makefiles.</p>
<p>Here’s some examples of things we can <code>make</code> easier (sorry):</p>
<pre><code class="lang-makefile"><span class="hljs-section">update: ## Do apt upgrade and autoremove</span>
    sudo apt update &amp;&amp; sudo apt upgrade -y
    sudo apt autoremove -y

<span class="hljs-section">env:</span>
    pip3 install pipenv
    pipenv shell --python 3.8

<span class="hljs-section">install: ## Install or update dependencies</span>
    pipenv install --dev
    npm install
    pre-commit install --install-hooks

<span class="hljs-section">serve: ## Run the local development server</span>
    hugo serve --enableGitInfo --disableFastRender --environment development

<span class="hljs-section">initial: update env install serve ## Install tools and start development server</span>
</code></pre>
<p>Now we have some command-line aliases that you can check in. Great idea! If you’re wondering what’s up with that weird <code>##</code> comment syntax, it gets better.</p>
<h2 id="heading-a-self-documenting-makefile">A self-documenting Makefile</h2>
<p>Aliases are great, if you remember what they all are and what they do without constantly typing <code>cat Makefile</code>. Naturally, you need a <code>help</code> command:</p>
<pre><code class="lang-makefile"><span class="hljs-meta"><span class="hljs-meta-keyword">.PHONY</span>: help</span>
<span class="hljs-section">help: ## Show this help</span>
    @egrep -h '\s<span class="hljs-comment">##\s' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'</span>
</code></pre>
<p>With a little command-line magic, this <code>egrep</code> command takes the output of <code>MAKEFILE_LIST</code>, sorts it, and uses <code>awk</code> to find strings that follow the <code>##</code> pattern. It then prints a helpful formatted version of the comments.</p>
<p>We’ll put it at the top of the file so it’s the default target. Now to see all our handy shortcuts and what they do, we just run <code>make</code>, or <code>make help</code>:</p>
<pre><code class="lang-text">help                 Show this help
initial              Install tools and start development server
install              Install or update dependencies
serve                Run the local development server
update               Do apt upgrade and autoremove
</code></pre>
<p>Now we have our very own personalized and project-specific CLI tool!</p>
<p>The possibilities for improving your DevOps flow with a self-documenting Makefile are almost endless. You can use one to simplify any workflow and produce some very happy developers.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
