<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lou Creemers</title>
    <description>The latest articles on DEV Community by Lou Creemers (@lovelacecoding).</description>
    <link>https://dev.to/lovelacecoding</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F867091%2F6ec67fc9-2dfe-4473-8c8c-b51a1ef0634e.jpg</url>
      <title>DEV Community: Lou Creemers</title>
      <link>https://dev.to/lovelacecoding</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lovelacecoding"/>
    <language>en</language>
    <item>
      <title>European Law for .NET Developers: What the GDPR Means for Your Code</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Sat, 10 Oct 2026 14:28:19 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/european-law-for-net-developers-what-the-gdpr-means-for-your-code-2hkb</link>
      <guid>https://dev.to/lovelacecoding/european-law-for-net-developers-what-the-gdpr-means-for-your-code-2hkb</guid>
      <description>&lt;p&gt;Hey lovely readers,&lt;/p&gt;

&lt;p&gt;The GDPR has been around since 2018, and most of us have heard of it. But when I ask developers what it actually means for the code they write, they often don't know. Usually someone mentions an annoying cookie banner and that's it.&lt;/p&gt;

&lt;p&gt;So I'm starting a small series. I'm taking three European laws that affect developers and making them as simple as I can. This first post is about GDPR. After that, I'll cover the European Accessibility Act (EAA) and the AI Act.&lt;/p&gt;

&lt;p&gt;Quick note before we start: I'm a developer, not a lawyer. Even though I'm really interested in this topic, I even did a thesis on it, I do not have a law degree. This post will help you understand what GDPR means for your code but if your company handles a lot of personal data, please also talk to someone who does this professionally.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is GDPR?
&lt;/h2&gt;

&lt;p&gt;GDPR (General Data Protection Regulation) is a European law that protects the personal data of people in the EU. It decides what you're allowed to collect, how you have to store it, and what people can ask you to do with their data.&lt;/p&gt;

&lt;p&gt;Personal data is anything that can be linked to a real person. Names and email addresses are the obvious ones, but the list is longer than most people think:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A phone number or home address&lt;/li&gt;
&lt;li&gt;A date of birth&lt;/li&gt;
&lt;li&gt;An IP address&lt;/li&gt;
&lt;li&gt;A user ID, if you can connect it back to someone&lt;/li&gt;
&lt;li&gt;Location data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But not all personal data is the same. A first name or an email address is personal data, but some data is much more sensitive and risky when it leaks. GDPR calls these special categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Health data&lt;/li&gt;
&lt;li&gt;Sexual orientation and sex life&lt;/li&gt;
&lt;li&gt;Ethnic origin&lt;/li&gt;
&lt;li&gt;Religious or philosophical beliefs&lt;/li&gt;
&lt;li&gt;Political opinions&lt;/li&gt;
&lt;li&gt;Union membership&lt;/li&gt;
&lt;li&gt;Genetic data&lt;/li&gt;
&lt;li&gt;Biometric data used to identify someone, like a fingerprint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For these categories, the starting point is different. You're not allowed to process this data at all unless one of a few exceptions applies, like the user giving explicit consent. And if you process a lot of it, you need a risk assessment called a DPIA (more on that later). Criminal records have their own, similar set of rules.&lt;/p&gt;

&lt;p&gt;And why should you care as a developer? Because the fines are big. A company can be fined up to 20 million euros or 4% of its worldwide yearly revenue, whichever is higher. But honestly the biggest reason here is trust. Your users give you their data, and it's our job to treat it well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it apply to me?
&lt;/h2&gt;

&lt;p&gt;Probably yes. GDPR applies when your app handles personal data of people in the EU. It doesn't matter where your company is based. If you build a webshop in the United States and people in Germany can order from it then the GDPR applies to you. So if your app has user accounts, a contact form, a newsletter sign up, or even just logs with IP addresses in them, this post is for you.&lt;/p&gt;

&lt;p&gt;But what if your project is really small? Maybe you have a SaaS with four users, or just a newsletter sign up on your blog. Then GDPR still applies. There is no minimum number of users, and no minimum revenue. One person from the EU in your database is enough.&lt;/p&gt;

&lt;p&gt;But here's the good news. What GDPR asks from you grows with your size and your risk. A small project with simple data needs a small, simple setup. Let's look at two examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  A small SaaS
&lt;/h3&gt;

&lt;p&gt;Let's say you have a SaaS with four users who pay you a few euros a month. Here's what you do need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A privacy policy.&lt;/strong&gt; What you collect, why, how long you keep it, and who you share it with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agreements with the services you use.&lt;/strong&gt; Your hosting and payment provider handle personal data for you. Most of them have a standard data processing agreement you can simply accept.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decent security.&lt;/strong&gt; HTTPS, hashed passwords, and backups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A simple overview of your data.&lt;/strong&gt; One page with what you store and why is enough. There's an exception for companies with fewer than 250 employees.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A way to handle requests.&lt;/strong&gt; If someone asks to see or delete their data, you need to be able to do that.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here's what you probably don't need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A risk assessment, since your processing isn't high risk&lt;/li&gt;
&lt;li&gt;A data protection officer&lt;/li&gt;
&lt;li&gt;An EU representative, if your business is based in the EU&lt;/li&gt;
&lt;li&gt;Special features in your code. If someone emails you to delete their account, doing it by hand is completely fine at this size.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A newsletter on your blog
&lt;/h3&gt;

&lt;p&gt;Maybe you just have a blog with a newsletter sign up, and you store the email addresses in your own database. GDPR still applies. There is an exception for "purely personal" use, but a public newsletter isn't that.&lt;/p&gt;

&lt;p&gt;Here's what you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consent.&lt;/strong&gt; Someone has to actively sign up. A double opt in where people confirm their email address is stored in your system is the best way to do this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Proof of that consent.&lt;/strong&gt; Store when and how someone signed up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An unsubscribe link in every email.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A short privacy notice&lt;/strong&gt; at your sign up form.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deleting the data&lt;/strong&gt; when someone unsubscribes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An agreement with your email service&lt;/strong&gt; if you use one to send your newsletter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In code, that's a timestamp for the consent and an unsubscribe action. That's really it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The rule of thumb
&lt;/h3&gt;

&lt;p&gt;GDPR asks for results, not for features. When your project is small, a privacy policy, a simple overview of your data, and handling requests by hand is often enough. Build features for it once doing things by hand starts to hurt.&lt;/p&gt;

&lt;p&gt;But what if you have a whole backend running with lots of users, well then there's some more work to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  GDPR is more than code
&lt;/h2&gt;

&lt;p&gt;Recently I helped a client who wanted to become GDPR compliant. When I wrote down all the work in tickets, something stood out: most of them weren't about code at all. They were about research and documentation.&lt;/p&gt;

&lt;p&gt;So before we open our IDE, let's look at the work that comes first. You don't have to do all of this alone as a developer but you will be part of it. And honestly, you're often the person who knows best where the data actually lives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Find out what you have
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Map all personal data you collect.&lt;/strong&gt; Every table, every form field, every log should be on there. This becomes your data inventory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Map how data flows.&lt;/strong&gt; Where does it go after it enters your app? Think of your database, your email service, your analytics tool, and your payment provider.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check what you receive from others.&lt;/strong&gt; Partners or third parties might send you personal data too. That counts as well.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 2: Know why you have it
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Write down the purpose for each type of data.&lt;/strong&gt; Why do you store a phone number? "Maybe we'll need it someday" is not a purpose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick a lawful basis for each purpose.&lt;/strong&gt; GDPR has six of them, like consent, a contract with the user, or a legal obligation. Every purpose needs one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document legitimate interest when you use it.&lt;/strong&gt; It's the most flexible basis, so you have to explain why your reason is fair, and why it doesn't hurt the rights of your users too much.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Check the risk
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Find your high-risk processing.&lt;/strong&gt; Think of large amounts of sensitive data, tracking people, or making automatic decisions about them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decide if you need a DPIA.&lt;/strong&gt; A Data Protection Impact Assessment is a document where you describe the risks and how you reduce them. For high-risk processing, it's required.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Write it all down
&lt;/h3&gt;

&lt;p&gt;This is the biggest part, and the least exciting one. But it matters, because GDPR asks you to be able to prove what you do.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Records of processing activities.&lt;/strong&gt; An overview of what you process, why, and for how long.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A data retention schedule and a deletion policy.&lt;/strong&gt; How long you keep each type of data and what happens after that.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A data breach response plan.&lt;/strong&gt; If something leaks, you usually have to report it to the data protection authority within 72 hours. That's not the moment to start figuring out who does what. You want that decided and written down somewhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Procedures for user requests.&lt;/strong&gt; What do you do when someone asks to see, change, or delete their data?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consent documentation.&lt;/strong&gt; If you use consent, you need to be able to show when and how someone gave it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A vendor register and data processing agreements.&lt;/strong&gt; Every service that handles personal data for you needs an agreement with you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy notices.&lt;/strong&gt; One for your users, and don't forget your employees. Their data counts too.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 5: Check if you need a representative
&lt;/h3&gt;

&lt;p&gt;If your company is not based in the EU but you do you do collect data from people that live in  there, you might need to appoint an EU representative. The UK has its own version of GDPR after Brexit, so the same goes for the UK.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where this meets your code
&lt;/h3&gt;

&lt;p&gt;Here's the nice part. A lot of these documents turn straight into work for developers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The data inventory tells you which properties to mark as personal data.&lt;/li&gt;
&lt;li&gt;The retention schedule becomes a background job that deletes or anonymizes old data.&lt;/li&gt;
&lt;li&gt;The user request procedures become a "download my data" and a "forget me" feature.&lt;/li&gt;
&lt;li&gt;The breach response plan only works if you have good logging and monitoring.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So let's get to that code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep personal data out of your logs
&lt;/h2&gt;

&lt;p&gt;Let's start with the mistake I see the most. Something goes wrong in production, so someone adds this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User signed up: {@User}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works great for debugging. But now the user's name, email address, and maybe even their phone number are sitting in your logs. And logs get copied everywhere: to a log service, to a colleague's screen, to a support ticket. You lose control over that data very quickly.&lt;/p&gt;

&lt;p&gt;.NET has a built-in way to fix this, with the &lt;code&gt;Microsoft.Extensions.Compliance.Redaction&lt;/code&gt; package. You mark which data is personal, and .NET removes it from your logs for you.&lt;/p&gt;

&lt;p&gt;First, install these packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package Microsoft.Extensions.Compliance.Redaction
dotnet add package Microsoft.Extensions.Telemetry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, you create a small "taxonomy". That's just a fancy word for a list of the types of data you want to treat differently:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Extensions.Compliance.Classification&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataTaxonomy&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;TaxonomyName&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DataTaxonomy&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;FullName&lt;/span&gt;&lt;span class="p"&gt;!;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="n"&gt;DataClassification&lt;/span&gt; &lt;span class="n"&gt;PersonalInfo&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TaxonomyName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PersonalInfo&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PersonalInfoAttribute&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DataClassificationAttribute&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;PersonalInfoAttribute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DataTaxonomy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PersonalInfo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can use that attribute on your model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PersonalInfo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PersonalInfo&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Empty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then you turn on redaction in your &lt;code&gt;Program.cs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;EnableRedaction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddRedaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;redaction&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;redaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetRedactor&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ErasingRedactor&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DataClassificationSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DataTaxonomy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PersonalInfo&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The last step is logging with the logging source generator, so .NET knows which properties to look at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;partial&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Log&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;LoggerMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Level&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Information&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"User signed up"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;partial&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;UserSignedUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;LogProperties&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you call it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UserSignedUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the user's ID still shows up in your logs, so you can still debug. But the name and email are erased before they ever reach a log file. You get the information you need, without the personal data you don't.&lt;/p&gt;

&lt;p&gt;Quick side note: &lt;code&gt;ErasingRedactor&lt;/code&gt; removes the value completely. If you'd rather still be able to see that two log lines belong to the same person, you can use the &lt;code&gt;HmacRedactor&lt;/code&gt; instead, which turns the value into a hash.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protect sensitive data with the Data Protection API
&lt;/h2&gt;

&lt;p&gt;Some data you do need to store, like a phone number. But that doesn't mean it should sit in your database as plain text. If someone ever gets access to your database, plain text is the worst possible situation.&lt;/p&gt;

&lt;h3&gt;
  
  
  How strong should the protection be?
&lt;/h3&gt;

&lt;p&gt;Remember the special categories from the start of this post, like health data? You might expect GDPR to say exactly how you should encrypt that kind of data. It doesn't. GDPR asks for "appropriate" security, based on the risk. Encryption is mentioned as an example, but there's no required algorithm or key size.&lt;/p&gt;

&lt;p&gt;In practice, it comes down to this: the more sensitive the data, the stronger the protection should be. For something like health data or sexual orientation, encryption is really the minimum. If that data leaks and it wasn't encrypted, then that's very hard to defend.&lt;/p&gt;

&lt;p&gt;And there's a nice bonus. If data leaks but it was properly encrypted, you often don't have to inform every affected user because the data is useless to whoever has it.&lt;/p&gt;

&lt;p&gt;Good to know: some sectors have extra rules on top of GDPR. In the Netherlands, for example, healthcare organizations have to follow a security standard called NEN 7510. So if you build apps for a specific sector, check if something like that applies to you too.&lt;/p&gt;

&lt;h3&gt;
  
  
  Encrypting data in .NET
&lt;/h3&gt;

&lt;p&gt;ASP.NET Core comes with the Data Protection API, which can encrypt and decrypt values for you. Here's a small class that protects a phone number:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.DataProtection&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PhoneNumberProtector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDataProtectionProvider&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IDataProtector&lt;/span&gt; &lt;span class="n"&gt;_protector&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
        &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateProtector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Users.PhoneNumber"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Protect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_protector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Protect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;phoneNumber&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Unprotect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;protectedPhoneNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="n"&gt;_protector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Unprotect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;protectedPhoneNumber&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The string you pass to &lt;code&gt;CreateProtector&lt;/code&gt; is called a purpose. Values protected with one purpose can't be unprotected with another, so your phone numbers and, say, your password reset tokens stay separated.&lt;/p&gt;

&lt;p&gt;One important thing to know: the Data Protection API uses keys, and those keys need to be stored somewhere safe and permanent. If you lose them, you can't decrypt your data anymore. So make sure you configure where the keys live, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDataProtection&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PersistKeysToFileSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;DirectoryInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/keys"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetApplicationName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyApp"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind that Microsoft built this API mainly for data that doesn't live forever, like cookies and tokens. For sensitive data that you store for years, it's worth looking at options like Always Encrypted in SQL Server or keys in Azure Key Vault. But for getting started and understanding the idea, the Data Protection API is a great first step.&lt;/p&gt;

&lt;h2&gt;
  
  
  The right to be forgotten with EF Core
&lt;/h2&gt;

&lt;p&gt;Under GDPR users can ask you to delete their personal data. This is called the right to be forgotten.&lt;/p&gt;

&lt;p&gt;Sounds easy, right? Just delete the user. But here's where it gets interesting. Say this user has placed orders in your webshop. You often have to keep those orders for your bookkeeping. In the Netherlands, for example, that's seven years.&lt;/p&gt;

&lt;p&gt;GDPR allows that. When the law says you have to keep something, then you can keep it. But you should remove everything that points to the person. That's where anonymizing comes in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ForgetUserAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SingleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Orders&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToListAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CustomerName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Removed"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ShippingAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Removed"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveChangesAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The user is gone, and the orders stay, but nobody can tell who placed them anymore.&lt;/p&gt;

&lt;p&gt;Here's something I see very often in different web apps. Many apps use soft delete: an &lt;code&gt;IsDeleted&lt;/code&gt; column that you set to &lt;code&gt;true&lt;/code&gt;. That's great for "undo" buttons but it's not deleting. The data is still in your database. So if a user asks to be forgotten, a soft delete is not enough. And don't forget the places outside your main database: backups, logs, analytics tools, and third-party services you send data to. Those count too.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about backups?
&lt;/h2&gt;

&lt;p&gt;You can't delete one person from a backup. A backup is a snapshot of your whole database, so you'd have to change every backup you have. That's not realistic, and luckily it's not what's expected either.&lt;/p&gt;

&lt;p&gt;What I'd advise instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Put a retention period on your backups.&lt;/strong&gt; Old backups expire and get deleted automatically. On Azure SQL, for example, you choose how long point-in-time backups are kept, between 1 and 35 days. If you also use long-term retention, keep it as short as your legal obligations allow.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don't use the data in the meantime.&lt;/strong&gt; Until a backup expires, nobody should touch the data of a deleted user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;State it clearly in your privacy policy.&lt;/strong&gt; Something like: "Deleted data is removed from our backups within 35 days."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keep an erasure log.&lt;/strong&gt; This is a small table with the user IDs of everyone who asked to be forgotten, and the date. Store it outside the database you back up, otherwise a restore rolls it back too.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one matters when you restore a backup. Without it, deleted users might come back without anybody noticing. With it, you simply run your "forget me" logic again before the database goes live:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ReapplyErasuresAsync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;erasedUserIds&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;erasureLog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAllUserIdsAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;erasedUserIds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ForgetUserAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Anonymization vs pseudonymization
&lt;/h2&gt;

&lt;p&gt;In the example above, I anonymized the orders. That word comes up a lot when you work with GDPR, and so does a word that sounds very similar: pseudonymization. They sound alike, but GDPR treats them very differently.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pseudonymization: you can still go back
&lt;/h3&gt;

&lt;p&gt;With pseudonymization, you replace something that identifies a person, like a name or an email address with a code. The information to link that code back to the person is stored somewhere else.&lt;/p&gt;

&lt;p&gt;For example, your analytics tool only sees &lt;code&gt;user_8f3a2c&lt;/code&gt;. A separate table or a key tells you who that is. This is still personal data, so GDPR still fully applies. But it lowers the risk a lot. If your analytics data leaks, nobody can see who &lt;code&gt;user_8f3a2c&lt;/code&gt; is. That's why GDPR actively encourages it. The &lt;code&gt;HmacRedactor&lt;/code&gt; I mentioned in the logging section is a good example. You can still see that two log lines belong to the same user, without seeing who that user is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anonymization: there's no way back
&lt;/h3&gt;

&lt;p&gt;With anonymization, you change the data so nobody can find out who it belongs to anymore. Not your colleague, not a hacker, and not even you.&lt;/p&gt;

&lt;p&gt;For example: "32 orders were placed in Amsterdam in March." There's no link to any customer at all. Data that is truly anonymous is no longer personal data. That means GDPR doesn't apply to it anymore.&lt;/p&gt;

&lt;h3&gt;
  
  
  The trap developers fall into
&lt;/h3&gt;

&lt;p&gt;"Anonymous" is a high bar, and it's easy to think you've reached it when you haven't. Two common examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hashing an email address.&lt;/strong&gt; That's pseudonymization, not anonymization. Anyone with a list of email addresses can hash them too and look for matches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only removing the name.&lt;/strong&gt; A postal code, a birth date, and a gender together can often point to one specific person. Each piece looks harmless, but together they're not.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This also goes for the "forget me" example above. Anonymizing the orders only works if nothing else on the order, like a postal code or a phone number, still points to the person.&lt;/p&gt;

&lt;p&gt;Here's my advice after spending a lot of time thinking about this: if you're not 100% sure your data is anonymous, treat it as pseudonymized, and keep protecting it like personal data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Only collect what you need
&lt;/h2&gt;

&lt;p&gt;The easiest personal data to protect is the data you never collected. GDPR calls this data minimization.&lt;/p&gt;

&lt;p&gt;A very common example is an endpoint that returns the full user entity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That sends everything to the frontend, including the date of birth, the address, and the phone number, even if the page only shows a name. Let's fix that with a small DTO:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;record&lt;/span&gt; &lt;span class="nc"&gt;UserSummary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapGet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AppDbContext&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;UserSummary&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SingleOrDefaultAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now only the data the page actually needs leaves your API.&lt;/p&gt;

&lt;p&gt;The same idea works for your forms. Do you really need someone's full date of birth? Or do you only need to know that they're 18 or older? A simple checkbox might be all you need.&lt;/p&gt;

&lt;h2&gt;
  
  
  What about outside of Europe?
&lt;/h2&gt;

&lt;p&gt;Before we wrap up, one more thing. GDPR is the most famous privacy law, but it's definitely not the only one. Many countries looked at GDPR and built something similar. Here are a few you might run into:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;th&gt;Law&lt;/th&gt;
&lt;th&gt;Good to know&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;United Kingdom&lt;/td&gt;
&lt;td&gt;UK GDPR&lt;/td&gt;
&lt;td&gt;After Brexit, the UK kept its own copy of GDPR. It's almost the same, with a few small differences.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Switzerland&lt;/td&gt;
&lt;td&gt;FADP&lt;/td&gt;
&lt;td&gt;Switzerland isn't in the EU, so it has its own law. It's very close to GDPR.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Brazil&lt;/td&gt;
&lt;td&gt;LGPD&lt;/td&gt;
&lt;td&gt;Strongly inspired by GDPR, with similar user rights and its own data protection authority.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;California, USA&lt;/td&gt;
&lt;td&gt;CCPA&lt;/td&gt;
&lt;td&gt;Focuses a lot on letting users opt out of their data being sold or shared.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canada&lt;/td&gt;
&lt;td&gt;PIPEDA&lt;/td&gt;
&lt;td&gt;Canada's federal privacy law for companies.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;South Africa&lt;/td&gt;
&lt;td&gt;POPIA&lt;/td&gt;
&lt;td&gt;Also close to GDPR in how it treats personal data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;India&lt;/td&gt;
&lt;td&gt;DPDP Act&lt;/td&gt;
&lt;td&gt;One of the newer ones, focused on consent.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you build your app with GDPR in mind then you're already in a good place for most of these laws. The ideas are often the same. Know what data you have, collect only what you need, protect it, and let users see and delete it.&lt;/p&gt;

&lt;p&gt;But "similar" doesn't mean "the same". The details can be different like how users can say no, or how fast you need to report a data breach. So if your app has a lot of users in one of these countries, check that specific law too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your GDPR checklist
&lt;/h2&gt;

&lt;p&gt;A short list you can bookmark:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Map your personal data, where it goes, and why you have it.&lt;/li&gt;
&lt;li&gt;Make sure the documentation exists, and help turn it into code.&lt;/li&gt;
&lt;li&gt;Mark personal data in your code, and turn on redaction so it never ends up in your logs.&lt;/li&gt;
&lt;li&gt;Encrypt sensitive data you store, especially special categories like health data, and keep your keys safe.&lt;/li&gt;
&lt;li&gt;Build a real "forget me" flow: delete what you can, anonymize what you have to keep.&lt;/li&gt;
&lt;li&gt;If you're not sure data is truly anonymous, treat it as pseudonymized and keep protecting it.&lt;/li&gt;
&lt;li&gt;Remember that soft delete is not deleting.&lt;/li&gt;
&lt;li&gt;Use DTOs, and only collect and send the data you actually need.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  That's a wrap!
&lt;/h2&gt;

&lt;p&gt;GDPR can feel like a big scary law, but a lot of it comes down to good habits you can build right into your code. Start small, maybe with the logging part, and go from there.&lt;/p&gt;

&lt;p&gt;In the next post of this series, I'll talk about the European Accessibility Act. It has been in force since June 2025, and it might apply to your app more than you think.&lt;/p&gt;

&lt;p&gt;If you have questions, or tips on how you handle GDPR in your own projects, feel free to leave a comment or reach out to me on &lt;a href="http://louella.dev/socials" rel="noopener noreferrer"&gt;my socials&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See ya!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Emotional Intelligence: The Developer Skill AI Can't Replace</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Sun, 04 Oct 2026 14:23:31 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/emotional-intelligence-the-developer-skill-ai-cant-replace-25jn</link>
      <guid>https://dev.to/lovelacecoding/emotional-intelligence-the-developer-skill-ai-cant-replace-25jn</guid>
      <description>&lt;p&gt;Hi lovely readers,&lt;/p&gt;

&lt;p&gt;A few months ago I wrote about how AI is making English a must-have skill for developers. The idea was simple: when you spend more of your day describing problems instead of typing code, the way you communicate becomes much more important.&lt;/p&gt;

&lt;p&gt;Recently I sat in on a talk by Manuela Beltrami at a women in tech event for Rotterdam University of Applied Sciences that I help organize. Her talk was all about failure, and one slide stuck with me. It called emotional intelligence your superpower in the age of AI. That slide kept going round in my head, and it made me realize there was a second half to my English post that I had not written yet.&lt;/p&gt;

&lt;p&gt;Writing a clear sentence is one thing. Knowing what the other person actually needs to hear, how they are feeling, and how you are feeling yourself is something else. That something else is emotional intelligence, and I think it might be one of the most underrated developer skills right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is emotional intelligence?
&lt;/h2&gt;

&lt;p&gt;Let me try to explain this term in the easiest way possible. Emotional intelligence is the ability to notice and understand emotions, both your own and other people's, and to use that understanding to handle situations well.&lt;/p&gt;

&lt;p&gt;The term became popular through psychologist Daniel Goleman and his 1995 book &lt;em&gt;Emotional Intelligence&lt;/em&gt;. He breaks it down into five components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Self-awareness&lt;/strong&gt;: recognizing your own emotions and how they affect your work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-regulation&lt;/strong&gt;: managing those emotions instead of reacting on impulse.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Motivation&lt;/strong&gt;: being driven by more than external rewards.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Empathy&lt;/strong&gt;: understanding what others feel and need.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Social skills&lt;/strong&gt;: building relationships, communicating, and handling conflict.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first three are about you. The last two are about the people around you. You will see all five come back in this post.&lt;/p&gt;

&lt;p&gt;At work, it looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Noticing that you are frustrated before you send that message in Teams or Slack&lt;/li&gt;
&lt;li&gt;Understanding that a stakeholder who keeps changing their mind might be under pressure from their own manager&lt;/li&gt;
&lt;li&gt;Seeing that a colleague has gone quiet in meetings and asking if they are okay&lt;/li&gt;
&lt;li&gt;Giving feedback in a way that helps someone grow instead of making them defensive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of this involves code. But all of it affects how well software gets built.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI does the typing, not the understanding
&lt;/h2&gt;

&lt;p&gt;AI tools are getting better every day. They can generate an endpoint, write tests, and explain an error message. Tasks that used to take an hour now take a few minutes.&lt;/p&gt;

&lt;p&gt;But if you look at why projects actually go wrong, it is rarely because someone could not write a for loop. It is because the team built the wrong thing. Because two people misunderstood each other. Because someone was afraid to say they were stuck. Because a disagreement about architecture slowly turned personal.&lt;/p&gt;

&lt;p&gt;AI does not fix any of that. It can transcribe a meeting and maybe even guess at the mood in the room, but it misses the context that gives those signals meaning. It does not know that the client who says "that's fine" said exactly the same thing right before the last project went sideways. It does not know your colleague just had a really hard week, or that your stakeholder's manager is breathing down their neck. It can sound friendly and understanding, but sounding kind is not the same as actually understanding.&lt;/p&gt;

&lt;p&gt;So as the technical part of our work gets faster, the human part becomes a bigger piece of what makes you valuable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Empathy helps you find the real problem
&lt;/h2&gt;

&lt;p&gt;The more clearly you describe a problem, the better the answer you get from AI. But there is a step before that. You first need to understand what the problem actually is.&lt;/p&gt;

&lt;p&gt;That is where empathy comes in. When a user says "this page is annoying," the real problem might be that the button is hard to find, that the page is slow on their phone, or that they are simply stressed and this page is the last thing standing between them and going home. You only find out by putting yourself in their shoes and asking the right questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessibility is empathy you can ship
&lt;/h2&gt;

&lt;p&gt;This is also why I care so much about accessibility. For me, it is the most practical form of emotional intelligence in our field.&lt;/p&gt;

&lt;p&gt;Accessibility means thinking about people who are not in the room. The person using a screen reader. The person with shaky hands who struggles with tiny buttons. The person reading your UI in their second language, or on a bad day when their focus is gone.&lt;/p&gt;

&lt;p&gt;AI can help here. It can suggest alt text, point out missing labels, or check your color contrast. But it only does that when someone asks. If you never thought about those users in the first place, no tool will do that thinking for you. The empathy has to come first, and the tooling comes after.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing your own emotions matters too
&lt;/h2&gt;

&lt;p&gt;Emotional intelligence is not only about other people. It is also about you.&lt;/p&gt;

&lt;p&gt;Let's be honest, working in tech right now can be stressful. There is a lot of noise about AI replacing developers, the job market is harder than it used to be, and it is easy to feel like you are always behind on the newest tool. On top of that, working with AI can be frustrating in a very specific way. You explain something three times, it confidently gives you the wrong answer again, and you feel your patience disappear. By the end of the day, these situations can really get to me.&lt;/p&gt;

&lt;p&gt;Being aware of those feelings helps a lot. When you notice "I am frustrated right now," you can take a break instead of accepting code you do not understand just to be done with it. When you notice "I am anxious about my future," you can talk about it with someone instead of letting it quietly stress out your work and your sleep. In Goleman's terms, noticing the feeling is self-awareness, and choosing what to do with it is self-regulation.&lt;/p&gt;

&lt;p&gt;It also helps to know what keeps you going. If your only motivation is keeping up with every new release, you will always feel behind, because there will always be another one. Maybe for you it is curiosity, or the moment a hard concept finally clicks, or building something that actually makes someone's day easier. That is what Goleman means by motivation: being driven by something deeper than the next shiny tool or a pat on the back. It is also what gets you through the weeks when the hype is exhausting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Failure builds emotional intelligence
&lt;/h2&gt;

&lt;p&gt;Here is something Manuela's talk made me realize: every time something goes wrong, you are training your emotional intelligence, whether you notice it or not.&lt;/p&gt;

&lt;p&gt;Dealing with disappointment when a release breaks. Asking for help when you are stuck, even though it feels embarrassing. Supporting a colleague who just took down production. Reading the room in the meeting after something went wrong. All of that builds the same muscle.&lt;/p&gt;

&lt;p&gt;When I look back at my first years as a developer, the moments that taught me the most about myself were not the successes. They were leaving a job that undervalued me, working somewhere that just did not click, and getting let go before I had even started. None of that felt good at the time. But it taught me how to handle disappointment, how to stop blaming myself for everything, and how to recognize what I need.&lt;/p&gt;

&lt;p&gt;AI can help you avoid some mistakes. It cannot go through them for you. And the growth that comes from getting through a hard moment, and helping others get through theirs, is still something only you can do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Emotional intelligence in PR reviews
&lt;/h2&gt;

&lt;p&gt;AI means more code gets written, which also means more code needs to be reviewed. And reviewing is one of the most emotional parts of our job, even if you think that it is not. This is where Goleman's social skills come in.&lt;/p&gt;

&lt;p&gt;When you review a pull request, try to be curious instead of harsh. "Can you walk me through why you chose this approach?" lands very differently than "Did AI write this?" Even when AI did write it, the person who opened the pull request is still a colleague, and they are still the one who will learn from your feedback.&lt;/p&gt;

&lt;p&gt;The same goes for receiving feedback. Your code is not you. A comment on your pull request is about the code, not about your worth as a developer. That is easy to say and hard to feel, and learning to feel it is part of emotional intelligence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Emotional intelligence is not the same as being outgoing
&lt;/h2&gt;

&lt;p&gt;I want to be clear about this one, because I think a lot of people get it wrong. Emotional intelligence does not mean being the loudest person in the room, loving networking events, or being friends with everyone.&lt;/p&gt;

&lt;p&gt;As I shared in an earlier post, I struggle with busy social events and open offices. That does not make me bad at understanding people. Quiet people are often very good at this, because they spend more time listening and observing. And knowing your own limits, like knowing when you need a quiet space to recharge, is emotional intelligence as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Emotional intelligence and neurodiversity
&lt;/h2&gt;

&lt;p&gt;There is a stereotype I want to push back on: that neurodivergent people, for example autistic people or people with ADHD, are "bad" at emotional intelligence. That is not true, and it is not a helpful way to think about it.&lt;/p&gt;

&lt;p&gt;A lot of what we call emotional intelligence is based on one specific way of communicating. Making eye contact, reading between the lines, picking up on tone of voice, understanding what someone means when they actually say something else. If your brain works differently, those signals might not come naturally. But that does not mean you do not care or do not feel. Many neurodivergent people feel emotions very strongly, including other people's.&lt;/p&gt;

&lt;p&gt;There is a term for this: the double empathy problem. The idea, which comes from autism researcher Damian Milton, is that when an autistic and a non-autistic person misunderstand each other, the problem goes both ways. It is not that one person lacks empathy. It is that two different communication styles meet, and both sides find the other hard to read.&lt;/p&gt;

&lt;p&gt;That changes what emotional intelligence looks like in a team. It is not only about reading others well. It is also about making yourself easy to understand, and accepting that people show things in different ways.&lt;/p&gt;

&lt;p&gt;In practice, that can look like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Say what you mean.&lt;/strong&gt; "Can you fix this before Friday?" is much clearer than "It would be nice if someone looked at this soon."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not read tone into short messages.&lt;/strong&gt; A one-word "ok" in Slack is usually just an "ok."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask how people like to work instead of assuming.&lt;/strong&gt; Some people prefer a quick call. Others want things in writing so they can process them in their own time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make room for different energy levels.&lt;/strong&gt; Cameras off, quiet spaces, and meetings with a clear agenda help more people than you might think.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interestingly, AI can help here too. Some neurodivergent developers use AI tools to check how a message might come across, or to ask "what could this person have meant?" That is a nice example of AI supporting human connection instead of replacing it. Still, it is a tool, not the solution. The real work is people meeting each other halfway.&lt;/p&gt;

&lt;p&gt;Emotional intelligence was never about everyone communicating the same way. It is about understanding that we do not, and making it work anyway.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teaching and mentoring are changing
&lt;/h2&gt;

&lt;p&gt;As someone who teaches and mentors, I notice that what learners need from me is changing. They can ask an AI to explain a concept at 2 AM, as many times as they want. What they cannot get from it is someone who notices they are overwhelmed, who tells them that being confused is a normal part of learning, or who helps them believe they can actually do this.&lt;/p&gt;

&lt;p&gt;Knowledge is easier to get than ever. Encouragement, trust, and feeling seen are not. Those still come from people.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to get better at it
&lt;/h2&gt;

&lt;p&gt;The good news is that emotional intelligence is not something you either have or do not have. You can practice it, just like any other skill.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Listen to understand, not to reply.&lt;/strong&gt; In your next meeting, try to repeat back what someone said in your own words before you answer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask one more question.&lt;/strong&gt; "What would make this a success for you?" often tells you more than the whole requirements document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pause before you send.&lt;/strong&gt; Reread your message as if you are the person receiving it. How does it sound on a bad day?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name what you feel.&lt;/strong&gt; Just saying "I am frustrated" or "I am nervous" to yourself makes it easier to handle.I sometimes even say it out loud at conference talks in front of an audience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask, do not assume.&lt;/strong&gt; How someone communicates tells you about their style, not about how much they care.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask how you come across.&lt;/strong&gt; A trusted colleague can tell you things about your communication that you will never notice yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  That's a wrap!
&lt;/h2&gt;

&lt;p&gt;AI is changing how we write code, and that is exciting. But software is still built by people, for people. The better you understand the humans around you, and yourself, the more valuable you become, no matter how good the tools get.&lt;/p&gt;

&lt;p&gt;Or, as Manuela put it on that slide: "AI is a tool. You are the strategy."&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you have thoughts, disagree with me, or want to share your own experience, feel free to leave a comment or reach out on &lt;a href="https://louella.dev/socials" rel="noopener noreferrer"&gt;my socials&lt;/a&gt;. I am always happy to talk about this stuff.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>career</category>
      <category>software</category>
    </item>
    <item>
      <title>SQL Database Projects and AI: A Match Made in Heaven</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Thu, 24 Sep 2026 15:34:09 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/sql-database-projects-and-ai-a-match-made-in-heaven-4pn2</link>
      <guid>https://dev.to/lovelacecoding/sql-database-projects-and-ai-a-match-made-in-heaven-4pn2</guid>
      <description>&lt;p&gt;Hey lovely readers,&lt;/p&gt;

&lt;p&gt;If you have ever asked an AI tool to write some SQL for you, you have probably seen this happen. You ask for a query, you get something that looks great, and then you run it and find out it uses a column that does not exist. Or a function your SQL Server version does not support. Or it quietly drops something you really wanted to keep.&lt;/p&gt;

&lt;p&gt;I wrote before about how &lt;a href="https://dev.to/lovelacecoding/ai-is-making-english-a-must-have-skill-for-developers-29e"&gt;AI tools are confident even when they are wrong&lt;/a&gt;. That is annoying in C#, but at least the compiler yells at you. With databases, there often is no compiler. There is just you, a script, and a database that is about to find out.&lt;/p&gt;

&lt;p&gt;That is exactly why I think SQL Database projects and AI are a match made in heaven. Let's talk about why.&lt;/p&gt;

&lt;p&gt;If you have worked with SQL Database projects before, feel free to skip to "Why AI and SQL projects get along so well". If you have never heard of them, don't worry, we will start from the beginning.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a SQL Database project?
&lt;/h2&gt;

&lt;p&gt;A SQL Database project is a local representation of your database schema. Your tables, views, stored procedures, and functions all live in &lt;code&gt;.sql&lt;/code&gt; files inside a project on your machine, right next to your application code and in the same Git repository.&lt;/p&gt;

&lt;p&gt;If you are a .NET developer, you can think of it as a &lt;code&gt;.csproj&lt;/code&gt;, but for your database. You write files, you build the project, and you get an output you can deploy.&lt;/p&gt;

&lt;p&gt;Here is what a table looks like in a SQL project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing special, right? The special part is what happens when you want to change it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Declarative instead of step by step
&lt;/h2&gt;

&lt;p&gt;Most of us learned to change databases step by step. First you create the table. Then, a bit later, you write a script that adds a column. Then another script that changes a data type. After a year, you have a folder with 80 scripts that need to run in exactly the right order.&lt;/p&gt;

&lt;p&gt;SQL projects work differently. They are declarative, which means you describe what the database should look like, not how to get there. Each object is declared once, in one file. Want to add a phone number to your customers? You do not write an &lt;code&gt;ALTER TABLE&lt;/code&gt; script. You just edit the same file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PhoneNumber&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think of it like a blueprint of a house. You do not hand the builder a list of "knock down this wall, then add a window here". You hand them the blueprint of what the house should look like, and they figure out what needs to change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build and deploy
&lt;/h2&gt;

&lt;p&gt;When you build a SQL project with &lt;code&gt;dotnet build&lt;/code&gt;, two things happen.&lt;/p&gt;

&lt;p&gt;First, the project gets validated. The build checks that every object you reference actually exists. A view can't use a table or column that is not in your project. The build also checks your syntax against a target platform, which is the SQL version you are targeting. For example, if your project targets SQL Server 2017, you can't use JSON functions that were added in SQL Server 2022.&lt;/p&gt;

&lt;p&gt;Second, you get a &lt;code&gt;.dacpac&lt;/code&gt; file. That is the build artifact, a package that contains your whole schema.&lt;/p&gt;

&lt;p&gt;To deploy it, you use a tool like SqlPackage. When you publish a &lt;code&gt;.dacpac&lt;/code&gt; to a new database, it creates everything in the right order, so a table with a foreign key is created after the table it points to. When you publish to an existing database, it compares your &lt;code&gt;.dacpac&lt;/code&gt; to that database and only generates the changes that are needed. Missing two columns? You get an &lt;code&gt;ALTER TABLE&lt;/code&gt;. Changed a stored procedure? You get an &lt;code&gt;ALTER PROCEDURE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So the blueprint is yours, and the builder is SqlPackage.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick note on project formats
&lt;/h2&gt;

&lt;p&gt;If you worked with SQL projects years ago, you probably remember the original format, based on .NET Framework and mostly tied to Visual Studio on Windows.&lt;/p&gt;

&lt;p&gt;The newer format is SDK-style, using the Microsoft.Build.Sql SDK. It runs on modern .NET, works cross-platform, supports NuGet package references for database references, and automatically includes all .sql files in your project folder. Microsoft recommends it for new development, and it is the format that will be supported in the future.&lt;/p&gt;

&lt;p&gt;Tooling support is different per IDE, so here is where things stand right now. SDK-style projects are generally available in the SQL Database Projects extension for VS Code. JetBrains Rider supports them since version 2025.2 through a bundled plugin, with project templates, importing from an existing database, schema compare, and publishing. In Visual Studio 2022, they are available as a preview component. Visual Studio 2026 only supports the original format for now, so if Visual Studio is your IDE of choice, keep that in mind when picking your tools.&lt;/p&gt;

&lt;p&gt;Getting started with the SDK-style format looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new &lt;span class="nb"&gt;install &lt;/span&gt;Microsoft.Build.Sql.Templates
dotnet new sqlproj &lt;span class="nt"&gt;-n&lt;/span&gt; MyDatabase
dotnet build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why AI and SQL projects get along so well
&lt;/h2&gt;

&lt;p&gt;Now for the fun part. Here is why I think this combination works so well.&lt;/p&gt;

&lt;h3&gt;
  
  
  The whole schema is right there as context
&lt;/h3&gt;

&lt;p&gt;AI tools are only as good as the context you give them. If your schema lives only inside a running database, the AI either has to guess what your tables look like, or you have to give it a connection to your database. &lt;strong&gt;Please do NOT give an AI agent a connection string to production.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With a SQL project, your entire schema is plain text in your repository. One object per file, easy to search, easy to read. An AI agent in your editor can open &lt;code&gt;Tables/Customers.sql&lt;/code&gt; and see exactly what columns exist, what the types are, and what the foreign keys point to. No guessing, no database access needed.&lt;/p&gt;

&lt;p&gt;And if you already have a database without a SQL project, you can extract one. You can do this from VS Code, or from the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sqlpackage /Action:Extract /SourceConnectionString:&lt;span class="s2"&gt;"&amp;lt;your connection string&amp;gt;"&lt;/span&gt; /TargetFile:MyDatabase /p:ExtractTarget&lt;span class="o"&gt;=&lt;/span&gt;SchemaObjectType
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works no matter how the database was created, even if you use an ORM like EF Core. That means you can give AI tools a readable picture of your schema without changing how your team works.&lt;/p&gt;

&lt;h3&gt;
  
  
  The build is a fact-checker
&lt;/h3&gt;

&lt;p&gt;This is my favorite part. Remember the AI that confidently used a column that does not exist? In a SQL project, that is a build error.&lt;/p&gt;

&lt;p&gt;Say you ask an AI to create a view, and it comes up with this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;CustomerContacts&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;AS&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Phone&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;].[&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Imagine that our column is called &lt;code&gt;PhoneNumber&lt;/code&gt;, not &lt;code&gt;Phone&lt;/code&gt;. Run &lt;code&gt;dotnet build&lt;/code&gt;, and you get an unresolved reference error (SQL71501) pointing right at the problem. Same for syntax your target platform does not support.&lt;/p&gt;

&lt;p&gt;This gives AI agents something they are really good at using: a feedback loop. Make a change, build, read the errors, fix them, build again. The agent can find its own mistakes before you ever have to look at them. The database finally gets something that feels like a compiler.&lt;/p&gt;

&lt;h3&gt;
  
  
  AI describes the destination, not the route
&lt;/h3&gt;

&lt;p&gt;Migration scripts are where things tend to go wrong. The order matters, the current state of the database matters, and one wrong assumption can break everything.&lt;/p&gt;

&lt;p&gt;With a SQL project, the AI does not have to write migration scripts at all. It only has to edit the file that describes what the object should look like. Figuring out how to get the actual database from its current state to that new state is SqlPackage's job, and SqlPackage has been doing that reliably for a long time.&lt;/p&gt;

&lt;p&gt;So the AI does the part it is good at (writing a clear description of what you want) and a deterministic tool does the risky part (calculating the changes). I love that split.&lt;/p&gt;

&lt;h3&gt;
  
  
  You can review every change like normal code
&lt;/h3&gt;

&lt;p&gt;Because everything is a file in Git, every AI change to your database shows up as a normal diff in a pull request. You see exactly which column was added, which view changed, and which procedure got rewritten. Your teammates can review it the same way they review C# code.&lt;/p&gt;

&lt;p&gt;That also means your normal CI/CD pipeline can build the project on every pull request. If the AI (or a human, let's be honest) broke something, the pipeline catches it before it gets merged.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code analysis adds extra guardrails
&lt;/h3&gt;

&lt;p&gt;SQL projects can also run code analysis during the build. You turn it on in your project file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;RunSqlCodeAnalysis&amp;gt;&lt;/span&gt;True&lt;span class="nt"&gt;&amp;lt;/RunSqlCodeAnalysis&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you get warnings for common bad practices, like using &lt;code&gt;SELECT *&lt;/code&gt; in views and stored procedures. AI tools love &lt;code&gt;SELECT *&lt;/code&gt;, so this one alone is worth it. You can customize which rules apply, and if you want to go further, you can even write your own rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  You see the plan before anything touches a database
&lt;/h3&gt;

&lt;p&gt;Before you deploy, you can ask SqlPackage to generate the script it would run, instead of running it right away:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sqlpackage /Action:Script /SourceFile:bin/Debug/MyDatabase.dacpac /TargetConnectionString:&lt;span class="s2"&gt;"&amp;lt;your connection string&amp;gt;"&lt;/span&gt; /OutputPath:deploy.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or use &lt;code&gt;/Action:DeployReport&lt;/code&gt; to get an overview of the changes. That way there are two review moments: the diff of the SQL files, and the actual script that will run against your database. Nothing reaches a real database without you seeing it first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making it work in practice
&lt;/h2&gt;

&lt;p&gt;A few things that help a lot when you let AI work on a SQL project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tell your AI tool how your project works.&lt;/strong&gt; Most AI coding tools support an instructions file in your repository. Add a small section about your database, something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Database changes&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; The database schema lives in /database as a SQL Database project.
&lt;span class="p"&gt;-&lt;/span&gt; Each object is declared once, in its own file. Never write ALTER statements or migration scripts.
&lt;span class="p"&gt;-&lt;/span&gt; After every schema change, run &lt;span class="sb"&gt;`dotnet build database/MyDatabase.sqlproj`&lt;/span&gt; and fix all errors before continuing.
&lt;span class="p"&gt;-&lt;/span&gt; The target platform is SQL Server 2022. Do not use features from newer versions.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Set the right target platform.&lt;/strong&gt; The build can only protect you from unsupported syntax if the target platform matches the SQL version you actually deploy to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep the AI away from real databases.&lt;/strong&gt; Let it work on files and run builds. Deploying stays a human decision, or a pipeline decision with a human approving it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does not solve
&lt;/h2&gt;

&lt;p&gt;I do not want to pretend this is magic so here are a few honest limitations.&lt;/p&gt;

&lt;p&gt;Renames are tricky. If an AI renames a column by just editing the file, the deployment can see that as "drop the old column, add a new one", and that means data loss. By default, SqlPackage blocks deployments that might lose data, which is great. However, you still need to handle renames properly. SQL projects have a refactor log for this, which the tooling creates when you use the rename refactoring. An AI editing text files will not create that for you, so keep an eye on renames in reviews.&lt;/p&gt;

&lt;p&gt;Data changes are also a different story. SQL projects describe the schema, not the data. If you need to move or transform data, you still write that yourself, for example in a post-deployment script.&lt;/p&gt;

&lt;p&gt;And of course, a green build does not mean the change is a good idea. The build tells you the schema is valid, not that the design makes sense. Reviewing is still your job.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's a wrap!
&lt;/h2&gt;

&lt;p&gt;SQL Database projects give your database the things we take for granted in application code: files you can read, a build that catches mistakes, and changes you can review. It turns out those are exactly the things AI tools need to be actually useful instead of confidently wrong.&lt;/p&gt;

&lt;p&gt;If you are a junior developer, this is a really nice way to learn database development with a safety net. If you have worked with SQL projects for years, you might find they suddenly got a lot more interesting now that an AI agent can use that same build to check its own work.&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you have thoughts, questions, or your own experience with AI and databases, feel free to leave a comment or reach out to me on &lt;a href="https://louella.dev/socials" rel="noopener noreferrer"&gt;my socials&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See ya!&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>sql</category>
      <category>ai</category>
      <category>beginners</category>
    </item>
    <item>
      <title>My JetBrains Rider Setup for Surviving Live-Coding Demos</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Sat, 15 Aug 2026 14:57:16 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/my-jetbrains-rider-setup-for-surviving-live-coding-demos-lh</link>
      <guid>https://dev.to/lovelacecoding/my-jetbrains-rider-setup-for-surviving-live-coding-demos-lh</guid>
      <description>&lt;p&gt;Hey lovely readers,&lt;/p&gt;

&lt;p&gt;If you've read any of my Public Speaking at Tech Events 101 blog posts, you already know I take demo prep very seriously. What I haven't written about yet is my IDE setup. I spend most of my working hours in JetBrains Rider, and I also spend most of my stage time there. Over the years I built a setup that helps me get through a live demo without fighting my own tools on top of fighting my nerves.&lt;/p&gt;

&lt;p&gt;This post is that setup written down. That way it can help you too if you ever want to challenge the demo gods.&lt;/p&gt;

&lt;p&gt;A quick note before we start: I'm writing this as a Rider user, since that's where I live most days. But almost everything here works the same way in WebStorm, IntelliJ IDEA, PyCharm, and the other JetBrains IDEs, since it's mostly the same underlying platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Presentation Mode and light theme
&lt;/h2&gt;

&lt;p&gt;The first thing I do before any talk is turn on Presentation Mode. You'll find it under &lt;code&gt;View &amp;gt; Appearance &amp;gt; Enter Presentation Mode&lt;/code&gt;. It makes the editor fill the whole screen and it makes the font bigger automatically. That way you don't have to change font sizes by hand right before you walk on stage.&lt;/p&gt;

&lt;p&gt;You can also set a fixed zoom level ahead of time. Then it's already right the moment you turn Presentation Mode on, instead of adjusting it in front of a room full of people. Go to File &amp;gt; Settings (or Preferences on macOS), then Appearance &amp;amp; Behavior &amp;gt; Appearance and look for the Presentation Mode settings there.&lt;/p&gt;

&lt;p&gt;The second thing I do is switch to light theme. I know, most of us live in dark mode (me included). But dark themes often look washed out under conference lighting and projectors. Light backgrounds are simply easier to read from the back of the room. Your eyes might need a minute to adjust, but your audience will thank you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Markdown-powered slides with MARP
&lt;/h2&gt;

&lt;p&gt;This one changed how I build talks completely. Instead of switching between PowerPoint and Rider during a demo, I now write my slides in Markdown. I preview them right inside the IDE, using MARP (Markdown Presentation Ecosystem).&lt;/p&gt;

&lt;p&gt;Here is the short version of the setup. Add a &lt;code&gt;package.json&lt;/code&gt; file next to your presentation file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"marp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"marp index.md -w --html --allow-local-files"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@marp-team/marp-cli"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.5.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create an &lt;code&gt;index.md&lt;/code&gt; file in the same folder. Write your slides in Markdown, and separate each slide with &lt;code&gt;---&lt;/code&gt;. Run &lt;code&gt;npm install&lt;/code&gt;, and Rider will show a small run button next to your script. Run it, and the &lt;code&gt;-w&lt;/code&gt; flag keeps watching your Markdown file. It rebuilds the HTML every time you save.&lt;/p&gt;

&lt;p&gt;To show the presentation, right click the new HTML file and choose &lt;code&gt;Open In &amp;gt; Browser &amp;gt; Built-in Preview&lt;/code&gt;. Now your slides live in a tab right next to your code. You can switch between them using Rider's normal tab shortcuts, instead of switching to a completely different app.&lt;/p&gt;

&lt;p&gt;A few things that are worth knowing. Press &lt;code&gt;P&lt;/code&gt; while previewing to open a window with your speaker notes, which you can keep on a second screen. If you use the &lt;code&gt;--html&lt;/code&gt; flag like in the script above, you can also add things like Mermaid diagrams straight into your slides. Unfortunately I don't get lots of opportunities to add Mermaid Diagrams to demos but I do love them :)&lt;/p&gt;

&lt;p&gt;I like this setup because my whole talk, slides and demo code both, lives in one place. That's one less app to manage, and one less thing that can go wrong.&lt;/p&gt;

&lt;p&gt;Quick side note if you do JavaScript or Vue talks: I use &lt;a href="https://sli.dev/" rel="noopener noreferrer"&gt;Slidev&lt;/a&gt; for those instead. It's also Markdown powered, but it's built with the JS ecosystem in mind, so it fits that kind of talk a bit better. Same idea, just a different tool depending on the stack I'm presenting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Switching files and projects quickly
&lt;/h2&gt;

&lt;p&gt;During a demo, the last thing you want is to search through 5 different projects, trying to remember where you put a file. &lt;code&gt;Search Everywhere&lt;/code&gt; (press Shift twice) is your best friend here. Type a few letters of a file, class, or action name, and you jump straight to it. No scrolling needed.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Recent Files&lt;/code&gt; (&lt;code&gt;View &amp;gt; Recent Files&lt;/code&gt;, or &lt;code&gt;Ctrl/Cmd+E&lt;/code&gt;) and &lt;code&gt;Recent Locations&lt;/code&gt; (&lt;code&gt;View &amp;gt; Recent Locations&lt;/code&gt;, or &lt;code&gt;Ctrl/Cmd+Shift+E&lt;/code&gt;) are both super useful in addition to Shift + Shift. Recent Files just shows you the files you had open recently. Recent Locations goes a step further and shows you actual code snippets from the places you edited, which is handy if you remember what the code looked like but not which file it was in.&lt;/p&gt;

&lt;p&gt;All three of these search options help you move fast between the two or three files a demo actually uses. And if something goes wrong and you need to switch from a working project to a backup project, being able to jump between run configurations or entire projects fast matters just as much as knowing your code.&lt;/p&gt;

&lt;h2&gt;
  
  
  dotnet run and .http files
&lt;/h2&gt;

&lt;p&gt;Since .NET 10 we can now use single C# files without setting up a full project first. This is great for quick demos. I often skip run configurations completely and just use &lt;code&gt;dotnet run&lt;/code&gt; from the terminal. It's fast, it's predictable, and there is less to explain if something looks unfamiliar to the audience.&lt;/p&gt;

&lt;p&gt;For live API demos, .http files are one of my favorite Rider features. Instead of switching to an API client and breaking the flow of your talk, you write the request right there in your project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://localhost:5001/api/dadjoke
Accept: application/json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click the small run icon next to it, and the response shows up right there. No separate tool, no window switching, no explaining why you suddenly switched apps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Live templates
&lt;/h2&gt;

&lt;p&gt;The live templates might be the best thing ever for demos. They are one of the best tools for reducing what can go wrong on stage. A live template is a code snippet you can insert with a short name and a press of Tab.&lt;/p&gt;

&lt;p&gt;You'll find them under &lt;code&gt;File &amp;gt; Settings&lt;/code&gt; (or &lt;code&gt;Preferences&lt;/code&gt; on macOS), then &lt;code&gt;Editor &amp;gt; Live Templates&lt;/code&gt;. From there you can create a new template group, or add templates to an existing one, each with its own abbreviation, description, and body.&lt;/p&gt;

&lt;p&gt;I use these a lot, but especially for two of my talks: Minimal APIs and modern C# features. Both involve a lot of boilerplate. If I had to type every endpoint or every record from scratch during a session, I would be typing the whole time instead of talking to the room.&lt;/p&gt;

&lt;p&gt;This is where a naming format helps. Instead of picking random short abbreviations, I group mine by talk topic with a short prefix. &lt;code&gt;api-get&lt;/code&gt;, &lt;code&gt;api-post&lt;/code&gt;, and &lt;code&gt;api-delete&lt;/code&gt; are all Minimal API templates. &lt;code&gt;csx-record&lt;/code&gt; and &lt;code&gt;csx-pattern&lt;/code&gt; are all modern C# templates. That way I'm not stuck remembering fifteen unrelated abbreviations, I just remember the prefix for the talk I'm giving, and Rider's autocomplete shows me the rest as I type.&lt;/p&gt;

&lt;p&gt;Less typing under pressure means fewer mistakes. That's really the whole point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shortcuts worth knowing by heart
&lt;/h2&gt;

&lt;p&gt;I'm not going to give you a giant list of every Rider shortcut that exists. That's not useful in the middle of a talk. These are the ones I actually know by heart, the ones that help when your brain isn't at its sharpest:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Shift Shift&lt;/code&gt; for Search Everywhere&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl/Cmd + Shift + F10&lt;/code&gt; (or the run icon) to run the current file or test&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Shift + F9&lt;/code&gt; to debug&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Ctrl/Cmd + Alt + L&lt;/code&gt; to reformat code, handy if a live edit gets messy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the list. You don't need fifty shortcuts. You mostly need these four to get you out of trouble.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's a wrap!
&lt;/h2&gt;

&lt;p&gt;None of this actually removes the nerves before a talk. I still feel them every single time, and that's completely normal. What this setup does is remove the things you can actually control. That way your nervous energy can go into the talk itself, instead of into fighting your IDE.&lt;/p&gt;

&lt;p&gt;I hope this helps you for your upcoming presentation or talk. If you have questions about anything above, feel free to leave a comment or reach out to me on &lt;a href="http://louella.dev/socials" rel="noopener noreferrer"&gt;my socials&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;See ya!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>csharp</category>
      <category>tutorial</category>
      <category>tools</category>
    </item>
    <item>
      <title>How Being a Junior Developer Taught Me More About Myself Than About Code</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Sat, 18 Jul 2026 12:55:34 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/how-being-a-junior-developer-taught-me-more-about-myself-than-about-code-co8</link>
      <guid>https://dev.to/lovelacecoding/how-being-a-junior-developer-taught-me-more-about-myself-than-about-code-co8</guid>
      <description>&lt;p&gt;Hey lovely readers,&lt;/p&gt;

&lt;p&gt;My 3-year anniversary of graduating from university with my bachelor's in Applied Computer Science is coming up. It feels like 5 centuries and 5 minutes ago at the same time.&lt;/p&gt;

&lt;p&gt;I started working right after graduation, and let me tell you, I learned a lot about the working field, and even more about myself. I quit a company that offered me a contract barely above minimum wage. I experienced a company not liking me, and me not liking them back. I even got fired from a job before my trial period had properly started.&lt;/p&gt;

&lt;p&gt;None of that felt great at the time. But looking back, it all led me to where I am now. So let's talk about it. Let's talk about why it is completely okay to still be figuring yourself out, and what you actually want, as a junior developer.&lt;/p&gt;

&lt;p&gt;Before I go on, I do want to be honest about one thing. I started looking for my first dev job in 2023, and the junior job market looked very different back then compared to now. Getting a first developer job in 2026 is a lot harder. Entry-level job postings have dropped a lot over the past few years, and companies now ask junior candidates for more experience and a stronger portfolio than they used to. On top of that, I already had my Microsoft MVP title back then and was speaking at events, so companies already knew who I was before I even applied. That gave me an advantage that most junior developers simply do not have, and I do not want to pretend otherwise. So please read the rest of this post with that in mind. The lessons still hold, but walking away from a bad offer, or leaving a mismatch, was easier for me in a market, and with an advantage most people do not get. If you are job hunting right now, it makes complete sense if some of this advice is harder to apply, and that is not a reflection of you doing anything wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Underpaid does not mean grateful
&lt;/h2&gt;

&lt;p&gt;When you are fresh out of university, it is easy to feel like you should be grateful for any offer at all. You do not have much experience yet, the job market can feel scary, and a company offering you a contract feels like a win, even if the salary for it is not great.&lt;/p&gt;

&lt;p&gt;I want to gently disagree with that feeling.&lt;/p&gt;

&lt;p&gt;Being a junior developer does not mean your work has no value. It means you are early in your career, not that you should accept barely above minimum wage for a full-time developer role. When I quit that company, it did not feel like a great moment. It felt scary. But it was also the first time I really understood that walking away from something that undervalues you is not bad.&lt;/p&gt;

&lt;p&gt;If you are in a similar position right now, please know this: it is okay to say no. It is okay to negotiate. And it is okay to leave, even as a junior, even if it feels early to make that kind of decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sometimes it just does not click, and that is fine
&lt;/h2&gt;

&lt;p&gt;Not every company and developer are a good match, and that is nobody's fault.&lt;/p&gt;

&lt;p&gt;I have been in a situation where a company simply did not like me, and if I am honest, I did not really like them either. That is an sad thing to accept, especially early in your career when you assume that if something is not working, it must be you.&lt;/p&gt;

&lt;p&gt;But work relationships are a two-way fit, just like any other relationship. Communication style, expectations, pace of work, sense of humour, all of it plays a role. A mismatch does not mean you are difficult to work with, and it does not mean the company is bad either. It just means that particular combination was not right.&lt;/p&gt;

&lt;p&gt;Recognising this early saved me a lot of unnecessary guilt later on. If a place does not feel right, it is worth asking why, without immediately assuming the answer is something wrong with you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting let go before you even started
&lt;/h2&gt;

&lt;p&gt;This one is a strange story, but I will tell it simply: I got fired from a job before my trial period had even started, just a short time before I was supposed to begin. The reason was not about me at all. The company made a business decision that had nothing to do with me, my skills, or my fit for the role, and that decision meant my contract could not go ahead.&lt;/p&gt;

&lt;p&gt;It still stings, even when you know exactly why it happened. There is something oddly personal about being let go before you even get the chance to prove yourself, even when the reason has nothing to do with you as a person or as a developer. In my case, it genuinely had nothing to do with my skills or fit. Sometimes it really is that simple: a company makes a decision for its own business reasons, and it happens to affect you directly, even though it is not about you at all.&lt;/p&gt;

&lt;p&gt;But not every story like this comes with such a clear reason. Sometimes it is about fit or timing on the company's side, and you never get a clean explanation. Either way, the lesson stays the same: one mismatch, or one company's decision, does not decide your whole career.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning what you actually need from a work environment
&lt;/h2&gt;

&lt;p&gt;One of the biggest things I have figured out over these 3 years is how much my environment affects how well I can do my job.&lt;/p&gt;

&lt;p&gt;I have learned that I struggle with things like busy social events and open offices, and that this is not something that gets easier just because I push through it a few more times. It is a pattern, not a bad day here and there. For a long time I assumed I should just be able to handle it, the way it seemed like everyone else could. It took a while to understand that some environments just don't work for me, no matter how much I want them to.&lt;/p&gt;

&lt;p&gt;Once I understood that about myself, it changed the way I looked at job offers and company cultures completely. I started paying attention to things like: is there a quiet space to work if I need one? Are social events something I am expected to attend, or something I can choose to join when I have the energy for it? Is the office open-plan, and if so, is there a way to get a break of it?&lt;/p&gt;

&lt;p&gt;None of this means those environments are bad, or that people who thrive in them are doing something wrong. It just means I learned that my own needs are specific, and that ignoring them does not make them go away. It only makes work harder than it needs to be.&lt;/p&gt;

&lt;p&gt;If there is one thing I would want every junior developer to take from this, it is that learning how you work best is just as important as learning how to code. That kind of self-knowledge is not something you are handed on day one. It is something you build, often through experiences that are uncomfortable at the time.&lt;/p&gt;

&lt;h2&gt;
  
  
  You do not need to be everyone's friend
&lt;/h2&gt;

&lt;p&gt;This is one of the harder lessons, but also one that calms me down: you cannot be friends with every single colleague, and some people will simply dislike you without there being a clear reason why.&lt;/p&gt;

&lt;p&gt;That used to bother me a lot. I would try to figure out what I did wrong, replay conversations, wonder if I said something strange or looked at somebody wrong. Sometimes there really is no answer. Personalities just clash sometimes, and it does not always come with a clear explanation.&lt;/p&gt;

&lt;p&gt;What helped me was realising that being liked by absolutely everyone was never actually the goal. What matters is being respectful, doing good work, and being someone people can rely on. That is a very different thing from being everyone's favourite person in the office, and it is a much more reasonable standard to hold yourself to.&lt;/p&gt;

&lt;p&gt;So if there is a colleague who just does not seem to like you, and you cannot figure out exactly why, it is okay to let that be. Not every relationship needs to be solved. Some things simply are what they are.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I know now that I wish I knew as a fresh graduate
&lt;/h2&gt;

&lt;p&gt;Looking back at all of this from where I am now, a few things stand out that I wish someone had told me sooner:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pay attention to how a company communicates with you during the interview process. It tells you a lot about what working there will actually be like.&lt;/li&gt;
&lt;li&gt;Trust how you feel in the first few weeks of a new job. If something feels off, it is worth paying attention to that feeling instead of ignoring it.&lt;/li&gt;
&lt;li&gt;Leaving a job, or having a job not work out, is not failing. It is part of figuring out what you actually want, even if the timing or the market makes that decision harder than it sounds.&lt;/li&gt;
&lt;li&gt;Your first job does not have to be your dream job. It is allowed to just be a step that teaches you something about yourself.&lt;/li&gt;
&lt;li&gt;Learning how you work best, like what kind of environment helps you and what kind of environment drains you, is just as valuable as learning a new framework or language.&lt;/li&gt;
&lt;li&gt;Not everyone has to like you, and you do not have to like everyone either. That is not a failure on your part or theirs.&lt;/li&gt;
&lt;li&gt;If the market right now means you have less room to walk away than I did, that is not a personal failure either. It is a reflection of a genuinely tougher market, not a lack of drive or talent on your part.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  That is a wrap
&lt;/h2&gt;

&lt;p&gt;3 years in, I do not have it all figured out, and I do not think that is the goal anymore. What I do know is that every one of these experiences, the good ones and the uncomfortable ones, taught me something about what I want and what I do not want in my career.&lt;/p&gt;

&lt;p&gt;If you are a junior developer still finding your way, please be patient with yourself. It is a marathon, not a race.&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you have thoughts, questions, or your own stories from early in your career, feel free to leave a comment or reach out to me on &lt;a href="http://louella.dev/socials" rel="noopener noreferrer"&gt;my socials&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>beginners</category>
      <category>devjournal</category>
    </item>
    <item>
      <title>C# Async/Await Made Simple</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Sun, 12 Jul 2026 19:39:07 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/c-asyncawait-made-simple-2bo0</link>
      <guid>https://dev.to/lovelacecoding/c-asyncawait-made-simple-2bo0</guid>
      <description>&lt;p&gt;Hi lovely readers,&lt;/p&gt;

&lt;p&gt;Today we are looking at &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt;. If these two words have ever shown up in your code and made you a little nervous, do not worry. This post is written for people who are seeing async/await for the very first time, so we will take it slow and build things up step by step.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem async/await solves
&lt;/h2&gt;

&lt;p&gt;Let's start with why this exists at all, using a simple example from real life.&lt;/p&gt;

&lt;p&gt;Imagine you are cooking dinner and you put a pot of water on the stove to boil. If you just stood there, staring at the pot until it boiled, you would waste a lot of time. A better approach is to start the water boiling, and while you wait, you chop vegetables or set the table. When the water is ready, you go back to it.&lt;/p&gt;

&lt;p&gt;That is exactly what async/await lets your code do. When your application needs to do something that takes time, like reading from a database or calling a web page, it does not have to freeze and wait. It can start that task, do other useful work, and come back to it once it is done.&lt;/p&gt;

&lt;p&gt;Without async/await, your program has to wait for one task to fully finish before it can do anything else. This is called &lt;strong&gt;blocking&lt;/strong&gt;, and it can make an application feel slow, especially when many people are using it at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two keywords, explained simply
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;async&lt;/code&gt;&lt;/strong&gt; is a label you put on a method to say: "this method contains something that might take time, and it is allowed to pause halfway through."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;await&lt;/code&gt;&lt;/strong&gt; is the actual pause. It is the exact place where your code says: "wait here until this is finished, but do not block anything else while you wait."&lt;/p&gt;

&lt;p&gt;Here is a small example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetUserAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This is where we "wait" for the database to respond&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_dbContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Once the database has answered, we continue from here&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice three things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The method has &lt;code&gt;async&lt;/code&gt; in its signature.&lt;/li&gt;
&lt;li&gt;It returns a &lt;code&gt;Task&amp;lt;User&amp;gt;&lt;/code&gt; instead of just &lt;code&gt;User&lt;/code&gt;. This is normal for async methods. Think of &lt;code&gt;Task&amp;lt;User&amp;gt;&lt;/code&gt; as a promise that a &lt;code&gt;User&lt;/code&gt; will be delivered eventually.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;await&lt;/code&gt; keyword is placed right before the slow operation, &lt;code&gt;FindAsync&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  How do you call an async method?
&lt;/h2&gt;

&lt;p&gt;To call an async method, you also need to use &lt;code&gt;await&lt;/code&gt;, and the method that is calling it usually needs to be &lt;code&gt;async&lt;/code&gt; too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;PrintUserNameAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;GetUserAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a pattern you will see everywhere in C#. Once one method becomes async, the methods that call it usually become async as well. This is completely normal, so do not worry if it feels like async spreads through your code. That is simply how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few beginner-friendly rules to hold onto
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Always return &lt;code&gt;Task&lt;/code&gt; or &lt;code&gt;Task&amp;lt;T&amp;gt;&lt;/code&gt; from your async methods, never &lt;code&gt;void&lt;/code&gt;.&lt;/strong&gt; The only exception is event handlers, which is a more advanced topic you will run into later. If something goes wrong inside a method that returns &lt;code&gt;void&lt;/code&gt;, the error can get lost and your application might crash without a clear reason.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Avoid this&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessOrderAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Do this instead&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessOrderAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_repository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Never call &lt;code&gt;.Result&lt;/code&gt; or &lt;code&gt;.Wait()&lt;/code&gt; on a task.&lt;/strong&gt; It might be tempting to use these when you are not in an async method yourself, but they force your program to block and wait, which is exactly what async/await is trying to avoid. In some situations, this can even cause your application to freeze completely. Stick to &lt;code&gt;await&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Avoid this, it can cause your app to freeze&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetUserAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Use this instead&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;GetUserAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;If you have several tasks that do not depend on each other, you can run them at the same time.&lt;/strong&gt; Waiting for them one by one when you do not need to is a common beginner habit, and it is an easy thing to improve once you notice it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// One after another, even though they do not depend on each other&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;ProcessSingleOrderAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// All at once instead&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ProcessSingleOrderAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;Once you feel comfortable with the basics, there are a few more advanced topics worth exploring later on, like &lt;code&gt;ConfigureAwait&lt;/code&gt;, the difference between &lt;code&gt;Task&lt;/code&gt; and &lt;code&gt;ValueTask&lt;/code&gt;, and async streams with &lt;code&gt;IAsyncEnumerable&lt;/code&gt;. You do not need any of that to get started, though. For now, focus on getting comfortable with &lt;code&gt;async&lt;/code&gt;, &lt;code&gt;await&lt;/code&gt;, and &lt;code&gt;Task&lt;/code&gt;, since that foundation will carry you a long way.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's a wrap!
&lt;/h2&gt;

&lt;p&gt;Async/await can feel a bit strange the first time you use it, and that is completely normal. Give yourself time to get used to it. The short version to remember: &lt;code&gt;async&lt;/code&gt; marks a method that can pause, &lt;code&gt;await&lt;/code&gt; is where it pauses, and &lt;code&gt;Task&lt;/code&gt; is the promise that something will be ready eventually.&lt;/p&gt;

&lt;p&gt;If you have thoughts, questions, or you are working through your own first async method right now, feel free to leave a comment or reach out to me on &lt;a href="http://louella.dev/socials" rel="noopener noreferrer"&gt;my socials&lt;/a&gt;. I remember exactly how confusing this felt at first, so do not hesitate to ask anything.&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>Bye AZ-204, hello AI-200: What you need to know about the new Azure developer certification</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Tue, 23 Jun 2026 11:10:15 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/bye-az-204-hello-ai-200-what-you-need-to-know-about-the-new-azure-developer-certification-2lo</link>
      <guid>https://dev.to/lovelacecoding/bye-az-204-hello-ai-200-what-you-need-to-know-about-the-new-azure-developer-certification-2lo</guid>
      <description>&lt;p&gt;Hi lovely readers,&lt;/p&gt;

&lt;p&gt;If you have been working toward your AZ-204 certification or have been thinking about starting, there is something important you need to know. Microsoft has officially announced that AZ-204: Developing Solutions for Microsoft Azure will retire on July 31, 2026. Its replacement is AI-200: Developing AI Cloud Solutions on Azure, and this is a much bigger change than just a new name.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is actually changing?
&lt;/h2&gt;

&lt;p&gt;AZ-204 has been the main certification for Azure developers for years. It covers the topics you would expect from a solid Azure developer: App Service, Azure Functions, Cosmos DB, Blob Storage, API Management, and authentication through the Microsoft Identity platform. It is a broad and practical exam, and many developers specializing in Microsoft have this certification or have tried to get it.&lt;/p&gt;

&lt;p&gt;AI-200 replaces that entirely. The new exam leads to the Microsoft Certified: Azure AI Cloud Developer Associate credential, and the focus has moved strongly toward building AI-powered applications. Think vector databases, retrieval-augmented generation (RAG), Azure Cosmos DB with semantic search, PostgreSQL with pgvector, Azure Managed Redis for similarity search, and containerized applications on Azure Kubernetes.&lt;/p&gt;

&lt;p&gt;This is not a small update. Microsoft is making something very clear here: being an Azure developer in 2026 means knowing how to build with AI, not just around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What carries over and what does not?
&lt;/h2&gt;

&lt;p&gt;Around 60% of AZ-204 content carries forward into AI-200. That sounds alright, but it is important to look at what is being removed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is gone in AI-200:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blob Storage SDK&lt;/li&gt;
&lt;li&gt;Microsoft Identity platform&lt;/li&gt;
&lt;li&gt;Microsoft Graph&lt;/li&gt;
&lt;li&gt;API Management&lt;/li&gt;
&lt;li&gt;Azure Event Hubs&lt;/li&gt;
&lt;li&gt;Azure Queue Storage&lt;/li&gt;
&lt;li&gt;Application Insights SDK (replaced by OpenTelemetry)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have been studying those topics, they will not be tested in AI-200.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is new in AI-200:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vector search across Cosmos DB NoSQL, pgvector on PostgreSQL, and Azure Managed Redis&lt;/li&gt;
&lt;li&gt;Kubernetes Event-driven Autoscaling (KEDA) in Container Apps&lt;/li&gt;
&lt;li&gt;Full AKS deployment and management using manifest files&lt;/li&gt;
&lt;li&gt;OpenTelemetry for distributed tracing, instead of the Application Insights SDK&lt;/li&gt;
&lt;li&gt;KQL queries for logs and metrics&lt;/li&gt;
&lt;li&gt;RAG pattern implementation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difference between the two exams is large enough that you cannot assume your existing study materials for AZ-204 like books or online courses will work for AI-200.&lt;/p&gt;

&lt;h2&gt;
  
  
  From C# to Python
&lt;/h2&gt;

&lt;p&gt;AZ-204 is designed for developers working in C# or Python. The audience profile mentions Azure SDKs broadly, and the prerequisites name both languages.&lt;/p&gt;

&lt;p&gt;AI-200 is different. The official study guide lists Python programming as a required skill, and it is the only language mentioned. If you are a .NET developer who mainly works in C#, that is worth knowing before you start preparing. It does not mean you cannot take the exam, but the exam is written with Python in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you still take AZ-204?
&lt;/h2&gt;

&lt;p&gt;It depends on where you are in your preparation.&lt;/p&gt;

&lt;p&gt;If you are close to being ready for the exam, taking AZ-204 before July 31st still makes sense. The credential stays valid through its full renewal period even after the exam retires, so you are not losing anything by taking the exam.&lt;/p&gt;

&lt;p&gt;If you are just getting started with studying, moving to AI-200 now is the better choice. There is no reason to spend time on topics that will not appear on any future exam. The AZ-204T training course retired on May 29, 2026, and AI-200 training course is now the replacement, so the official learning path has already changed.&lt;/p&gt;

&lt;p&gt;If you are starting from scratch: skip AZ-204 entirely and go straight to AI-200.&lt;/p&gt;

&lt;p&gt;One thing to keep in mind: the AI-200 exam is currently still in beta. That means practice exams are not available yet, and beta exams are not scored right away while Microsoft collects data on question quality. This might mean that you have to wait for a bit if you prefer to have more practice materials before sitting the actual exam.&lt;/p&gt;

&lt;h2&gt;
  
  
  A bigger picture
&lt;/h2&gt;

&lt;p&gt;AZ-204 is not the only certification going through this kind of change. Microsoft is retiring several familiar exams this year and replacing them with AI-focused alternatives. AZ-500 is being replaced by SC-500 (Cloud and AI Security Engineer), DP-100 is being replaced by AI-300 (Machine Learning Operations Engineer), and AI-900 was already updated to AI-901 in March 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's a wrap!
&lt;/h2&gt;

&lt;p&gt;If you have thoughts, questions, or experiences you would like to share, feel free to leave a comment or reach out to me on &lt;a href="http://louella.dev/socials" rel="noopener noreferrer"&gt;my socials&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>cloud</category>
      <category>ai</category>
      <category>certification</category>
    </item>
    <item>
      <title>AI Is Making English a Must-Have Skill for Developers</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Tue, 09 Jun 2026 16:29:05 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/ai-is-making-english-a-must-have-skill-for-developers-29e</link>
      <guid>https://dev.to/lovelacecoding/ai-is-making-english-a-must-have-skill-for-developers-29e</guid>
      <description>&lt;p&gt;Hi lovely readers,&lt;/p&gt;

&lt;p&gt;If you have spent any time online lately, you have probably seen the endless debates about which programming language you should learn next. Should it be Rust because everyone keeps saying it is the future? Should you stick with C# and .NET? Is JavaScript still worth it, or is it finally time to pick up Python because of all the AI tooling?&lt;/p&gt;

&lt;p&gt;These are fair questions, and I love a good language debate as much as the next developer. But after spending the last couple of years watching how AI tools changed the way I actually work day to day, I have come to a slightly different conclusion. The most important language for a developer in the age of AI is not C#, JavaScript, or Rust.&lt;/p&gt;

&lt;p&gt;It is English.&lt;/p&gt;

&lt;h2&gt;
  
  
  You are not writing code anymore, you are describing it
&lt;/h2&gt;

&lt;p&gt;For most of my career, the gap between an idea in my head and working code was filled by me typing that code out, line by line. I knew the syntax, I knew the patterns, and the language I used to get from idea to result was C#.&lt;/p&gt;

&lt;p&gt;That gap looks very different now. A large part of my day involves explaining what I want to an AI tool, reviewing what it gives back, and then explaining what was wrong or what I want changed. The bottleneck is no longer "do I know the syntax for this LINQ query." The bottleneck is "can I describe this problem clearly enough that something else can solve it."&lt;/p&gt;

&lt;p&gt;That is not a coding skill. That is a communication skill.&lt;/p&gt;

&lt;p&gt;If you ask a vague question, you get a vague answer. If you describe the wrong problem, you get a solution to a problem you do not have. The clearer you can express what you actually need, the better the result. And the language most of these tools were trained on, the language most documentation is written, the language most of the prompts and examples online use, is English.&lt;/p&gt;

&lt;h2&gt;
  
  
  I learned this the hard way in my second language
&lt;/h2&gt;

&lt;p&gt;If you have read some of my other posts, you already know that English is not my first language. I am Dutch, and during university my teachers regularly pointed out how I would lose my train of thought halfway through a sentence. Writing clearly in a second language took me years of effort, which I learned mostly through blogging. That effort turned out to be one of the best investments I ever made, and I did not even realize it at the time.&lt;/p&gt;

&lt;p&gt;When you work with AI tools, the quality of your output is tied directly to how clearly you can phrase things. A messy, half-finished thought gives you a messy, half-finished answer. A precise description, with the right context and the right constraints, gives you something you can actually use. The skill of taking a fuzzy idea and turning it into clear sentences is exactly the same skill I had been practicing for years without knowing how useful it would become.&lt;/p&gt;

&lt;p&gt;So if English is not your first language either, I want to be honest with you. Yes, this puts a little extra weight on something that is already harder for us. But it is also a skill you can build, the same way you built your ability to read a stack trace or debug a null reference exception. It just takes practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Communication was always a huge part
&lt;/h2&gt;

&lt;p&gt;Here is something that I think a lot of us already knew before AI made it impossible to ignore. The hardest parts of software development were rarely the code itself.&lt;/p&gt;

&lt;p&gt;The hard parts were understanding what a stakeholder actually wanted instead of what they said they wanted. Writing a pull request description that your reviewer could understand without three follow-up messages. Explaining a technical decision to someone who does not write code. Leaving a comment that your future self would thank you for. Writing documentation that someone could actually follow.&lt;/p&gt;

&lt;p&gt;All of that is language. All of that is the ability to take something complicated and make it understandable for another human being. AI did not create this skill, it just turned up the volume on how much it matters. The developers who can clearly explain a problem, give good context, and describe what "done" looks like are the ones getting the most out of these tools right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading is half of the skill
&lt;/h2&gt;

&lt;p&gt;It is easy to focus only on the part where you describe what you want, but there is another half that matters just as much. You also have to read carefully.&lt;/p&gt;

&lt;p&gt;AI tools are confident even when they are wrong. They will happily invent a method that does not exist, suggest a package that was deprecated years ago, or solve your problem in a way that quietly breaks something else. If you cannot read the answer critically and notice when something is off, you are going to have a bad time.&lt;/p&gt;

&lt;p&gt;That critical reading is, again, a language skill. It is the ability to follow an explanation, spot the part that does not make sense, and ask a sharp follow-up question. The same way a good code reviewer reads a diff and immediately senses something is wrong, you now need to read generated answers the same way. The better you are at reading, the less likely you are to copy something into production that you did not actually understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Programming languages do not stop being important
&lt;/h2&gt;

&lt;p&gt;I want to be clear, because I can already see the comments online. I am not saying you should stop learning programming languages, or that syntax no longer matters, or that you can ship software without understanding what the code does. You absolutely still need to understand your stack. You need to know enough to tell when an answer is nonsense, to debug the thing when it breaks at 4 PM on a Friday, and to make real decisions about architecture and trade-offs.&lt;/p&gt;

&lt;p&gt;Programming languages are still the thing the machine runs. But English has quietly become the thing you use to get there. One does not replace the other. They sit next to each other, and right now, a lot of developers are not putting enough effort into the second one.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to actually get better at it
&lt;/h2&gt;

&lt;p&gt;The good news is that this is a skill you can practice, and you probably already have the perfect tools for it.&lt;/p&gt;

&lt;p&gt;Write more. Write blog posts, write detailed pull request descriptions, write proper commit messages, write documentation for the thing you just built. Every time you force yourself to explain something clearly in writing, you are training the exact muscle that makes you better at working with AI.&lt;/p&gt;

&lt;p&gt;Pay attention to your prompts. When you get a bad answer, do not just try again with the same vague request. Ask yourself what context was missing, what you assumed the tool already knew, and how you could have phrased it more precisely.&lt;/p&gt;

&lt;p&gt;And if English is not your first language, do not let that stop you. Read in English, write in English, and let yourself be a little uncomfortable while you improve. I promise it gets easier, and it pays off in more ways than you expect.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's a wrap!
&lt;/h2&gt;

&lt;p&gt;Thanks for reading! If you have thoughts, disagree with me, or want to share your own experience, feel free to leave a comment or reach out on &lt;a href="https://louella.dev/socials" rel="noopener noreferrer"&gt;my socials&lt;/a&gt;. I am always happy to talk about this stuff.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Vue Composition API: Computed and Ref Properties Explained</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Thu, 19 Feb 2026 20:44:41 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/vue-composition-api-a-clear-guide-to-ref-and-computed-4aeh</link>
      <guid>https://dev.to/lovelacecoding/vue-composition-api-a-clear-guide-to-ref-and-computed-4aeh</guid>
      <description>&lt;p&gt;Hey lovely readers,&lt;/p&gt;

&lt;p&gt;If you are working with Vue 3 and TypeScript, you have probably seen &lt;code&gt;ref&lt;/code&gt; and &lt;code&gt;computed&lt;/code&gt; many times. They appear in tutorials, real projects, and even job interviews. When I first started using Vue 3, I kept wondering why everything had to be wrapped in &lt;code&gt;ref&lt;/code&gt;, and what made &lt;code&gt;computed&lt;/code&gt; different from a normal function.&lt;/p&gt;

&lt;p&gt;I would consider myself more of a backend developer, and I spent a lot of time in 2025 trying to wrap my head around frontend development. So if you are using Vue 3 with TypeScript now, or planning to start learning Vue, this guide will help you clearly understand these two important concepts.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is state?
&lt;/h2&gt;

&lt;p&gt;Before we talk about &lt;code&gt;ref&lt;/code&gt; and &lt;code&gt;computed&lt;/code&gt;, we need to understand one important concept: state.&lt;/p&gt;

&lt;p&gt;State is simply data that can change over time and affects what the user sees on the screen. If the data changes and the UI must update because of it, that data is state.&lt;/p&gt;

&lt;p&gt;Examples of state in a frontend application include a counter value, a list of users fetched from an API, whether a modal is open or closed, the content of an input field, or the currently logged in user.&lt;/p&gt;

&lt;h3&gt;
  
  
  State from a backend perspective
&lt;/h3&gt;

&lt;p&gt;If you come from a backend background, you are already familiar with state. You work with database records, request and response objects, session data, and cached values. That is all state too. The difference is where it lives.&lt;/p&gt;

&lt;p&gt;In traditional backend driven applications, the flow usually looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The client sends a request&lt;/li&gt;
&lt;li&gt;The server processes data&lt;/li&gt;
&lt;li&gt;The server returns HTML or JSON&lt;/li&gt;
&lt;li&gt;The page reloads with updated data&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this model, most of the state lives on the server.&lt;/p&gt;

&lt;p&gt;In modern frontend frameworks like Vue, state often lives in the browser. There is no full page reload. Instead, a user clicks a button, data changes in memory, and the UI updates automatically. This automatic update is what we call reactivity.&lt;/p&gt;

&lt;p&gt;Vue needs a way to know which data should trigger UI updates. That is exactly what &lt;code&gt;ref&lt;/code&gt; and &lt;code&gt;computed&lt;/code&gt; help with.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are &lt;code&gt;ref&lt;/code&gt; and &lt;code&gt;computed&lt;/code&gt; in Vue 3?
&lt;/h2&gt;

&lt;p&gt;In Vue 3, reactivity is managed with the Composition API. Two key features are &lt;code&gt;ref&lt;/code&gt; and &lt;code&gt;computed&lt;/code&gt;. You can think of &lt;code&gt;ref&lt;/code&gt; as reactive state and &lt;code&gt;computed&lt;/code&gt; as derived state.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;ref&lt;/code&gt; as reactive state
&lt;/h3&gt;

&lt;p&gt;You use &lt;code&gt;ref&lt;/code&gt; to create reactive values such as numbers, strings, and booleans. This should be a value that you want to change when some action happens in the template.&lt;/p&gt;

&lt;p&gt;Here is a simple example in Vue 3 with TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is what is happening. &lt;code&gt;ref&amp;lt;number&amp;gt;(0)&lt;/code&gt; tells TypeScript that this ref contains a number. The actual value is accessed using &lt;code&gt;.value&lt;/code&gt;. When &lt;code&gt;count.value&lt;/code&gt; changes, Vue automatically updates the user interface.&lt;/p&gt;

&lt;p&gt;In backend terms, you can think of &lt;code&gt;ref&lt;/code&gt; as a variable stored in memory that Vue is actively watching. When the value changes, Vue reacts and updates the UI.&lt;/p&gt;

&lt;p&gt;In the template, you do not need to use &lt;code&gt;.value&lt;/code&gt; because Vue unwraps it for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="na"&gt;click=&lt;/span&gt;&lt;span class="s"&gt;"increment"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Increment&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use &lt;code&gt;.value&lt;/code&gt; in the script because &lt;code&gt;ref&lt;/code&gt; does not return the raw number. It returns a reactive wrapper object that allows Vue to track changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;ref&lt;/code&gt; with objects
&lt;/h2&gt;

&lt;p&gt;You can also use &lt;code&gt;ref&lt;/code&gt; with objects, especially when working with TypeScript interfaces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lou&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To update it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you mainly work with objects, you will also come across the &lt;code&gt;reactive&lt;/code&gt; function, but the core idea stays the same. Vue tracks changes and updates the UI when the state changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Derived state and &lt;code&gt;computed&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;If &lt;code&gt;ref&lt;/code&gt; represents your source of truth, then &lt;code&gt;computed&lt;/code&gt; represents values derived from that source.&lt;/p&gt;

&lt;p&gt;Derived state is data that is calculated from other state, should always stay in sync, and should not be manually updated.&lt;/p&gt;

&lt;p&gt;Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;quantity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, &lt;code&gt;price&lt;/code&gt; and &lt;code&gt;quantity&lt;/code&gt; are source state. &lt;code&gt;total&lt;/code&gt; is derived state.&lt;/p&gt;

&lt;p&gt;From a backend perspective, this is similar to a calculated column, a DTO field built from other fields, or a value computed from query results. You would not store &lt;code&gt;total&lt;/code&gt; separately in a database if it can always be calculated from &lt;code&gt;price * quantity&lt;/code&gt;, because that would create duplication and possible inconsistencies.&lt;/p&gt;

&lt;p&gt;The same idea applies here. &lt;code&gt;computed&lt;/code&gt; helps you avoid duplicated state and keeps your data consistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;computed&lt;/code&gt; vs a function
&lt;/h2&gt;

&lt;p&gt;You could write a normal function instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use it in the template like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ fullName() }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So why use &lt;code&gt;computed&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;The main difference is caching and dependency tracking. A normal function runs every time the component re renders. It does not remember its previous result. Even if the underlying values have not changed, the function will still run again.&lt;/p&gt;

&lt;p&gt;A computed property is cached. Vue tracks which reactive values it depends on and only recalculates when one of those values changes. If nothing changes, Vue reuses the previous result.&lt;/p&gt;

&lt;p&gt;In small examples, the difference is not very noticeable. In larger components with complex logic or expensive calculations, &lt;code&gt;computed&lt;/code&gt; makes your code more efficient and easier to reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple rule that helps
&lt;/h2&gt;

&lt;p&gt;When deciding between &lt;code&gt;ref&lt;/code&gt; and &lt;code&gt;computed&lt;/code&gt;, ask yourself one question:&lt;/p&gt;

&lt;p&gt;Is this the source of truth, or is it derived from something else?&lt;/p&gt;

&lt;p&gt;If it is the source of truth, use &lt;code&gt;ref&lt;/code&gt;. If it is derived from other state, use &lt;code&gt;computed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This mental model is especially helpful if you come from a backend background where you already think in terms of data consistency and single sources of truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;computed&lt;/code&gt; with getters and setters
&lt;/h2&gt;

&lt;p&gt;Sometimes you want a computed property that can both read and update data. In that case, you can use a getter and a setter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fullName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="nx"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can assign a value directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fullName&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lou Creemers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful in forms where one input field represents multiple pieces of state.&lt;/p&gt;

&lt;h2&gt;
  
  
  TypeScript tips
&lt;/h2&gt;

&lt;p&gt;When using Vue 3 with TypeScript, it is good to think about types early. TypeScript often already recognizes the type automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But you can also define it explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isVisible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;code&gt;computed&lt;/code&gt;, the return type is usually recognized automatically. If needed, you can define it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;computed&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Being clear about types helps prevent subtle bugs, especially in larger projects or team environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;p&gt;Here are some common mistakes that I've made dozens of times include: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Forgetting to use &lt;code&gt;.value&lt;/code&gt; inside the script&lt;/li&gt;
&lt;li&gt;Trying to change a computed property without defining a setter &lt;/li&gt;
&lt;li&gt;using &lt;code&gt;computed&lt;/code&gt; for something that should just be a normal constant.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If something is not updating in your template, the first thing to check is whether you are actually working with a reactive source.&lt;/p&gt;

&lt;h2&gt;
  
  
  That is a wrap
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ref&lt;/code&gt; and &lt;code&gt;computed&lt;/code&gt; are central parts of Vue 3’s reactivity model. Once you understand the difference between source state and derived state, your components become much easier to reason about. If you are building applications with Vue 3 and TypeScript, mastering these two concepts will give you a strong foundation for everything that follows.&lt;/p&gt;

&lt;p&gt;If you have any questions or comments, feel free to reach out (&lt;a href="//louella.dev/socials"&gt;louella.dev/socials&lt;/a&gt;) or leave a comment down below.&lt;/p&gt;

&lt;p&gt;See ya!&lt;/p&gt;

</description>
      <category>vue</category>
      <category>typescript</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Public Speaking at Tech Events 101: Being Uncomfortable Is Worth It</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Tue, 10 Feb 2026 15:06:25 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/public-speaking-at-conferences-101-being-uncomfortable-is-worth-it-43kk</link>
      <guid>https://dev.to/lovelacecoding/public-speaking-at-conferences-101-being-uncomfortable-is-worth-it-43kk</guid>
      <description>&lt;p&gt;Hey lovely readers,&lt;/p&gt;

&lt;p&gt;If you have been following this series from the start, you now know how to get started with speaking, how to apply to conferences, and how to prepare once you get accepted. You might have even stood on stage already, or you might be right at the point where you are thinking about submitting your first abstract. Either way, there is a very big chance you have already felt uncomfortable at some point in this process.&lt;/p&gt;

&lt;p&gt;Your heart rate goes up, your hands feel shaky, and your brain suddenly starts questioning every decision that led you here. Maybe that happens right before you walk on stage, or maybe it happens much earlier, when you are staring at a submit button and wondering if you should really go through with it. This post is about that feeling, not about getting rid of it or pretending it does not exist, but about understanding it and learning why it might actually be a good sign.&lt;/p&gt;

&lt;h2&gt;
  
  
  Even “good speakers” feel weird before a talk
&lt;/h2&gt;

&lt;p&gt;One of the most comforting things I learned after getting more involved in the speaker world is how many experienced speakers still struggle with the same things beginners do. Not just the people doing their first talk, but also the ones you see on big stages at well-known conferences. The difference is not that they do not feel it, but that they no longer see it as a reason to stop.&lt;/p&gt;

&lt;p&gt;A lot of speakers that are 1000 times better than me at speaking openly talk about how they can barely eat breakfast or lunch on the day of their talk. Their stomach is upset, adrenaline takes over, and food just does not sound appealing at all until everything is done. Others mention that they delay working on their slides or demos until the last moment, even though they care deeply about their talk, simply because their brain refuses to fully engage until there is pressure. And almost all of them will admit that they are nervous in the minutes before they walk on stage, even after years of experience.&lt;/p&gt;

&lt;p&gt;What matters is that these are also the same people who say they love public speaking. They keep submitting abstracts, they keep traveling, and they keep going back on stage again and again. Being nervous, procrastinating a bit, or not being able to eat beforehand does not mean you are bad at this. It means your body is reacting to something that matters to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discomfort is not a warning sign
&lt;/h2&gt;

&lt;p&gt;A lot of us grow up learning that discomfort is something to avoid. If something feels scary, awkward, or stressful, we assume it must be wrong or unsafe, and we look for ways to back out. That reaction makes sense in many situations, but public speaking is usually not one of them.&lt;/p&gt;

&lt;p&gt;Standing on a stage, sharing your ideas, and letting people form opinions about your work is scary by nature. Your nervous system reacts because it thinks you are about to do something important and unpredictable, not because you are in danger. Feeling uncomfortable in that moment does not mean you are unprepared or incapable. More often, it simply means you care about doing a good job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your body knows before your brain does
&lt;/h2&gt;

&lt;p&gt;That tight feeling in your chest before walking on stage, the restless energy while waiting to be introduced, or the sudden urge to back out even though you practiced and prepared are all very common reactions. Your body is responding before your brain has time to rationalize what is happening. It is not trying to sabotage you, it is trying to keep you alert.&lt;/p&gt;

&lt;p&gt;Your brain, on the other hand, might start listing reasons why you should not be there. Someone else is more experienced, you might forget something, or someone might ask a question you cannot answer. In reality, your body is reacting to the importance of the moment, not to the outcome. Once you start seeing discomfort as a signal instead of a problem, it becomes much easier to move forward while feeling it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Five uncomfortable minutes can change years
&lt;/h2&gt;

&lt;p&gt;Most of the truly uncomfortable parts of speaking are surprisingly short. The walk to the stage, the introduction, and the first few minutes where your voice might shake and your thoughts feel scattered are often the hardest part. After that, something usually shifts and you settle into your rhythm. That’s also why you should practice the beginning more often than the rest.&lt;/p&gt;

&lt;p&gt;Those first minutes can feel intense, but they are nothing compared to what can come out of them. Speaking can lead to opportunities like traveling to places you might never have visited otherwise, meeting some very smart and generous people, getting invited to share knowledge you already care about, or being offered jobs and freelance work because someone saw you speak. None of those things happen without those uncomfortable moments at the start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Confidence is not a prerequisite
&lt;/h2&gt;

&lt;p&gt;One of the biggest misconceptions about public speaking is that you need to feel confident before you start. In reality, confidence is something that slowly builds because you keep showing up, even when it feels uncomfortable. You do not wait for confidence and then act, you act and let confidence catch up later.&lt;/p&gt;

&lt;p&gt;You are allowed to be nervous, to doubt yourself, and to feel like you do not fully belong yet. You can still submit the abstract, accept the talk, and walk on stage anyway. Every time you do, you show yourself that you can survive the discomfort, and that is where confidence comes from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Loving speaking and being nervous can exist at the same time
&lt;/h2&gt;

&lt;p&gt;This is something I wish more people talked about openly. You can genuinely love public speaking and still feel nervous before every session. You can enjoy being on stage and still struggle to eat beforehand, or procrastinate on slides until the deadline is uncomfortably close.&lt;/p&gt;

&lt;p&gt;These things do not cancel each other out. They are simply different ways your body and brain deal with adrenaline, pressure, and expectations.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small reminder before you click submit
&lt;/h2&gt;

&lt;p&gt;If you are reading this while hovering over a submit button, of a Call for Papers or wondering if you are really ready, it helps to remember that discomfort is not a stop sign. More often, it is a sign that you care about the stuff you put out to people. Feeling uncomfortable does not mean you should wait, it usually means you are growing.&lt;/p&gt;

&lt;p&gt;Five uncomfortable minutes are a very small price to pay for the experiences, connections, and confidence that can follow. You do not need to get rid of the discomfort to move forward. You just need to decide that it is not in charge.&lt;/p&gt;

&lt;h2&gt;
  
  
  That is a wrap
&lt;/h2&gt;

&lt;p&gt;Public speaking will probably always come with some level of discomfort, even after years of experience and many talks. If it matters to you, your body will react, and that is completely normal. Feeling uncomfortable does not mean you are failing, it means you are paying attention.&lt;/p&gt;

&lt;p&gt;Thanks for reading! If you want to share anything or have any questions, feel free to leave a comment or reach out on my socials.&lt;/p&gt;

</description>
      <category>speaking</category>
      <category>programming</category>
      <category>community</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why Blogging Still Matters in the Age of AI</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Sun, 28 Dec 2025 20:07:56 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/why-blogging-still-matters-in-the-age-of-ai-438b</link>
      <guid>https://dev.to/lovelacecoding/why-blogging-still-matters-in-the-age-of-ai-438b</guid>
      <description>&lt;p&gt;Hi lovely readers,&lt;/p&gt;

&lt;p&gt;If you’ve ever thought about starting a blog but stopped because “no one reads blogs anymore,” you’re not alone. With AI changing how people consume content, it’s easy to assume blogging has lost its value. I started blogging in 2021, and since then I’ve published 45 posts, with my most read one reaching 40 thousand views. That experience has shown me that blogging is still incredibly important and worth pursuing today. Here’s why.&lt;/p&gt;

&lt;h2&gt;
  
  
  For yourself
&lt;/h2&gt;

&lt;p&gt;We only save a limited amount of information every day in our heads. In my case, that limit is very noticeable. My brain often feels like a strainer. All my loved ones know that if they want me to remember something, they need to write it down for me. Telling me while I am doing something else guarantees I will forget it within minutes.&lt;/p&gt;

&lt;p&gt;I sometimes get the opportunity to talk to some of the smartest people in the tech field. People who know far more about the subject than I ever will, and that is completely fine. What frustrates me is when someone explains something clearly, and five minutes later I realize I have already forgotten most of it.&lt;/p&gt;

&lt;p&gt;That is where writing things down becomes important. Whether it is a reminder, a to do list, or a personal knowledge base, writing forces you to slow down and think about what you just learned. Instead of just listening and moving on, you actively process the information.&lt;/p&gt;

&lt;p&gt;Writing things down also helps with memory. When you put something into your own words, your brain has to revisit the concept instead of letting it fade away. Writing on paper is generally better for remembering the concept, but writing a blog post is a great alternative. You can even start on paper and later turn it into a digital blog post.&lt;/p&gt;

&lt;p&gt;Over time, your blog becomes a manual for your future self. You will forget things, especially technical details. Having blog posts that you wrote yourself means you always have an explanation that already made sense to you once. Often these posts include examples, demos, or code snippets that you can reuse or quickly understand again.&lt;/p&gt;

&lt;p&gt;Another benefit is language development, especially if English is not your first language. My native language is Dutch, and during university my teachers often pointed out how I would lose my train of thought halfway through a sentence. Writing technical blog posts in a non-native language takes time and effort, but that effort adds up. I now notice awkward sentences much faster and make far fewer grammar mistakes than I did in 2021. That improvement also carries over into my work life, where clear written communication through Slack, Teams, or email is essential in an international environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  For others
&lt;/h2&gt;

&lt;p&gt;If you learn something interesting or feel genuinely excited about a topic, sharing it can help others while trying to understand it or practicing it yourself.&lt;/p&gt;

&lt;p&gt;When I started blogging, I was still in university. By spending a lot of time on Twitter, I slowly realized that going to university is not something everyone has access to. In many countries, studying is extremely expensive. Others choose not to pursue it because of family responsibilities or personal circumstances. Meanwhile, I was 22, living in a country where university cost around 2500 euros a year, and I was learning a lot of genuinely interesting things.&lt;/p&gt;

&lt;p&gt;That realization became a big motivator for me. Besides all the personal benefits blogging gave me, it felt good to share knowledge that I had easy access to. I would go to class, take notes on my laptop or on paper, put everything into Notion, and then turn those notes into a blog post or sometimes a short series of tweets if I felt it could be useful to others.&lt;/p&gt;

&lt;p&gt;I still do this today. I learn from public speakers at conferences, from colleagues, and even from students I teach who are deeply interested in topics I know very little about. Someone mentions a concept or explains something new to me, and I write it down so I can explore it further later.&lt;/p&gt;

&lt;p&gt;Some of those notes stay in Notion forever. Others turn into blog posts. Either way, writing and sharing creates a way to pass knowledge forward. AI is not always reliable for this yet. A concept might be too new for it to know about, it might hallucinate features or solutions, or it might explain something in a way that simply does not click for people. That is where you can make a real difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  For your career
&lt;/h2&gt;

&lt;p&gt;Blogging also plays a role in your career, even if that is not the reason you started in the first place.&lt;/p&gt;

&lt;p&gt;When you write blog posts, you are not just sharing knowledge. You are showing how you think. You show how you break down problems, how you explain concepts, and what you find important enough to spend time on. That is very different from listing skills on a CV or LinkedIn profile.&lt;/p&gt;

&lt;p&gt;A blog gives context to your experience. It shows what you actually do with the tools and technologies you work with. Someone reading your post can see how deep you go, how you approach learning something new, and how you communicate technical ideas.&lt;/p&gt;

&lt;p&gt;Another important part is visibility. Your work normally stays within your team or your company. A blog moves that work into the open. People outside your immediate circle can find it, learn from it, and form an opinion of you long before you ever speak to them.&lt;/p&gt;

&lt;p&gt;This can lead to opportunities you did not actively chase. Conversations start more easily when someone already knows what you’re interested in and what you know. Sometimes people reach out because a post helped them. Sometimes it becomes a reference point during an interview or a collaboration. None of this is guaranteed, but it is something you would not have without blogging.&lt;/p&gt;

&lt;p&gt;For me, blogging never felt like a career strategy. It felt like documenting what I was learning. Over time, it simply became part of how I work and how I grow. And that visibility is something that helps just as much as the knowledge itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your keystrokes are precious
&lt;/h2&gt;

&lt;p&gt;Once you start working in a team and someone asks you to explain something over text, you usually have two options. One is writing a long Teams or Slack message that only one or two people will ever read. The other is writing a blog post so that many people can benefit from the same amount of effort.&lt;/p&gt;

&lt;p&gt;At that point, it is worth asking yourself whether those keystrokes are really worth your time and energy.&lt;/p&gt;

&lt;p&gt;I first learned about this idea in 2024 when Scott Hanselman spoke at a meetup near me. He mentioned his website &lt;a href="http://keysleft.com/" rel="noopener noreferrer"&gt;keysleft.com&lt;/a&gt; and his blog post &lt;a href="https://www.hanselman.com/blog/do-they-deserve-the-gift-of-your-keystrokes" rel="noopener noreferrer"&gt;Do they deserve the gift of your keystrokes&lt;/a&gt;. One quote from that post really stuck with me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you email someone one on one, you are reaching that one person.&lt;/p&gt;

&lt;p&gt;If you blog about it, or update a wiki or something similar, your keystrokes travel farther and reach more people.&lt;/p&gt;

&lt;p&gt;You only have so many hours in the day.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That idea is absolutely true. Why put the same amount of effort into a one to one message when you can help more people with that same effort. Writing a blog post forces you to think more clearly about the concept, allows you to reuse it later, and gives future colleagues or random people on the internet something useful to learn from.&lt;/p&gt;

&lt;p&gt;I do this for students as well. In their first year, my students have to learn PyGame and Python Flask. Instead of explaining the same concepts from scratch every year, I wrote blog posts like &lt;a href="https://dev.to/lovelacecoding/how-to-build-your-first-python-game-a-step-by-step-guide-to-creating-a-simple-shooter-with-pygame-f0k"&gt;&lt;code&gt;How to Build Your First Python Game: A Step-by-Step Guide to Creating a Simple Shooter with PyGame&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://lovelacecoding.hashnode.dev/build-a-to-do-list-app-using-python-flask-jinja2-and-sql" rel="noopener noreferrer"&gt;&lt;code&gt;Build a To-Do List App Using Python Flask, Jinja2, and SQL&lt;/code&gt;&lt;/a&gt;. They also struggled with topics like &lt;a href="https://dev.to/lovelacecoding/secure-your-coding-create-an-ssh-key-on-mac-or-windows-pdd"&gt;SSH keys&lt;/a&gt; and &lt;a href="https://dev.to/lovelacecoding/how-to-create-a-git-tag-with-github-18of"&gt;Git Tags&lt;/a&gt;, so I wrote blog posts on those as well. All of these blog posts are public. I need to explain these concepts every year anyway, so it makes sense to put them online where they can help more than just one group of students.&lt;/p&gt;

&lt;p&gt;The work stays the same. The reach does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  That’s a wrap!
&lt;/h2&gt;

&lt;p&gt;Blogging does not have to be about algorithms, monetization, or chasing numbers. At its core, it is about learning, documenting, and sharing in a way that works for you. It helps you remember what you learn, makes knowledge more accessible for others, and allows your effort to reach further than a single message or conversation ever could.&lt;/p&gt;

&lt;p&gt;You do not need a big audience to start. You do not need a perfect writing style or a niche figured out from day one. What matters is that you write things down, in your own words, and put them somewhere you can come back to later. Everything else grows from there.&lt;/p&gt;

&lt;p&gt;If you have been on the fence about starting a blog, I hope this gave you a different perspective. And if you already have one, maybe this is your sign to keep going.&lt;/p&gt;

&lt;p&gt;If you have thoughts, questions, or experiences you would like to share, feel free to leave a comment under this post or reach out to me on &lt;a href="http://louella.dev/socials" rel="noopener noreferrer"&gt;my socials&lt;/a&gt;. I am always happy to talk about blogging, learning in public, and all things tech.&lt;/p&gt;

</description>
      <category>writing</category>
      <category>community</category>
      <category>learning</category>
    </item>
    <item>
      <title>Public Speaking at Tech Events 101: From Acceptance to the Stage</title>
      <dc:creator>Lou Creemers</dc:creator>
      <pubDate>Mon, 22 Dec 2025 19:39:00 +0000</pubDate>
      <link>https://dev.to/lovelacecoding/public-speaking-at-tech-events-101-from-acceptance-to-the-stage-487l</link>
      <guid>https://dev.to/lovelacecoding/public-speaking-at-tech-events-101-from-acceptance-to-the-stage-487l</guid>
      <description>&lt;p&gt;Hey lovely readers,&lt;/p&gt;

&lt;p&gt;So you submitted your abstract, refreshed your inbox a little too often, and got the email you were hoping for. You have been accepted. That is exciting, and also a tiny bit terrifying, because now it is real.&lt;/p&gt;

&lt;p&gt;I remember being afraid to click the confirmation button for the first time. It felt like I was signing a contract I might not be ready for. That feeling passed quickly, but I still remember the moment.&lt;/p&gt;

&lt;p&gt;If you are new here, this post is part 2 of a series about getting into public speaking. In &lt;a href="https://dev.to/lovelacecoding/public-speaking-at-tech-events-101-how-to-start-your-speaker-journey-2olj"&gt;part 1&lt;/a&gt;, I talked about how to get started, how to write talk abstracts, how to use Sessionize, and how to apply to meetups and conferences.&lt;/p&gt;

&lt;p&gt;If you already read part 1, welcome back. This is the next step.&lt;/p&gt;

&lt;p&gt;In this part, we will go through what happens after the “yes”: what to check right away, how to plan your prep time, how to build slides and demos in a way that makes you feel comfortable on stage, and what to do on the actual day of the event so you can focus on having fun instead of feeling stressed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of content
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I’ve been accepted, now what?&lt;/li&gt;
&lt;li&gt;Confirm the details&lt;/li&gt;
&lt;li&gt;Plan it out&lt;/li&gt;
&lt;li&gt;Make a rough sketch&lt;/li&gt;
&lt;li&gt;Presentation&lt;/li&gt;
&lt;li&gt;Demo Code&lt;/li&gt;
&lt;li&gt;Prepare, prepare, prepare&lt;/li&gt;
&lt;li&gt;
The fun part: the event

&lt;ul&gt;
&lt;li&gt;Planning your trip&lt;/li&gt;
&lt;li&gt;Just before leaving the house&lt;/li&gt;
&lt;li&gt;The night before your session&lt;/li&gt;
&lt;li&gt;Waking up&lt;/li&gt;
&lt;li&gt;At the event&lt;/li&gt;
&lt;li&gt;Just before your talk&lt;/li&gt;
&lt;li&gt;After your talk&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Other questions answered that I could not put anywhere else

&lt;ul&gt;
&lt;li&gt;Do I need a new talk for every event?&lt;/li&gt;
&lt;li&gt;Do speakers get paid?&lt;/li&gt;
&lt;li&gt;What if my demo fails during the talk?&lt;/li&gt;
&lt;li&gt;How do I deal with nerves or stage fright?&lt;/li&gt;
&lt;li&gt;How do I grow visibility as a speaker?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;That’s a wrap!&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  I’ve been accepted, now what?
&lt;/h2&gt;

&lt;p&gt;Have you been accepted to your very first conference or meetup talk? Congratulations, now the real work begins.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Confirm the details&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When your session is accepted for a conference through Sessionize, you will receive an email with the subject “[Session title] has been accepted” with an email from the organizer and a confirmation button. Once you receive this email, immediately check the event date in your calendar to make sure you are not double booked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ne1z6tzexz63cphaqrw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ne1z6tzexz63cphaqrw.png" alt="Email notification showing a session acceptance message with the text “Well done, Louëlla. Your session ‘Modern Java and C#: How You Win by Knowing Both’ has been accepted” and a green “Confirm participation” button." width="800" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take a moment to read through the email carefully and make sure you understand what is expected from you. Things to double check include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The exact length of your session&lt;/li&gt;
&lt;li&gt;Whether there is time reserved for Q&amp;amp;A&lt;/li&gt;
&lt;li&gt;If the session will be recorded and shared publicly&lt;/li&gt;
&lt;li&gt;How travel and hotel arrangements work, or how reimbursement is handled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If anything is unclear, reach out to the organizing team and ask. It is completely normal to have questions, especially for your first conference. Most confirmation emails include a contact email address for the organizers, and they are usually happy to clarify things early rather than deal with confusion later.&lt;/p&gt;

&lt;p&gt;If you think you have a clear vision of what they expect of you, feel free to click ‘confirm participation’. This way the organizer knows that you’ve confirmed too.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Plan it out&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Sometimes you will be accepted 8 months before the conference or event takes place. Sometimes it will be only 2 months beforehand. You need to think about when you are going to make time to build your talk, prepare a demo, and practice. Try to do this when your mind has the most energy. If you are a night person, try working on it after regular work hours. If you are a morning person, prepare before your day starts.&lt;/p&gt;

&lt;p&gt;How long it takes to finish your talk is really up to you. Did you promise demos in your abstract? Then you will have to code something. Just a presentation? In theory, that should take less time. It also depends on your time slot. A 20-minute talk takes less time to prepare than a 60-minute talk.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Make a rough sketch&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Begin with a rough sketch. Read your abstract again to see what you promised, and decide what you want to talk about and for how long. AI can help with this part if you need some outlining. You usually start with an intro, then a bit of information about yourself and how you got interested in the topic. Then you add some background information on what people need to know before the talk starts, then the actual talk itself, a demo, and finally a conclusion with resources and your socials.&lt;/p&gt;

&lt;p&gt;What you actually talk about depends on your topic. Keep in mind that you usually talk faster when you are nervous, and if the conference wants you to do Q&amp;amp;A at the end, keep 5 to 10 minutes available for that as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Presentation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Your presentation should not do the talking for you. Use it to explain things and to support your story. Do not put long sentences in your slides. Try to have a maximum of six items on a slide, such as bullet points or images.&lt;/p&gt;

&lt;p&gt;Keep in mind accessibility and visibility. Use images that look good on small screens and large screens. Use code snippets and text with enough contrast and make sure the font size is big enough. If you use videos, be sure they have subtitles. Many conferences put talks online, so be careful with copyright for videos, images, and music.&lt;/p&gt;

&lt;p&gt;Go through your rough sketch and make slides that fit your style or vision. Most likely, you already have an idea of what they should look like. Everyone has their own way of creating presentations, so I will not tell you exactly what yours should look like.&lt;/p&gt;

&lt;p&gt;If you are having a hard time deciding which tool to use, a lot of people use PowerPoint or Google Slides. If you prefer making slides from code, check out &lt;a href="https://sli.dev/" rel="noopener noreferrer"&gt;Slidev&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Demo Code&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You should prepare your demo code well before your talk and have backups ready. If I am live coding, I always have a fully working project as well as video recordings as a backup. I also have a brand-new or halfway-finished project that I can start building on stage. In the past, I had a project that I wanted to create live on stage, until something in my project template suddenly decided to update. Do not let that be you. Be prepared for the unexpected.&lt;/p&gt;

&lt;p&gt;Also have code snippets ready. If you need to type a big chunk of code, you might forget something due to adrenaline or the noise of the room. If you use a JetBrains IDE like I do, you can use &lt;a href="https://www.jetbrains.com/help/idea/using-live-templates.html" rel="noopener noreferrer"&gt;live templates&lt;/a&gt;, where you can add code snippets and use them with just a shortcut name and a press of the Tab key.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Prepare, prepare, prepare&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Before you leave your house to go to the event, rehearse your presentation and your code until you feel comfortable. Time it, and see where you need to add or remove slides. Keep in mind that you will talk faster under pressure, and try not to wander off in your story.&lt;/p&gt;

&lt;p&gt;Once you think you are 80 percent done, present it to something or somebody. Preferably a real person. Even if they do not know what you are talking about, ask them to focus on your timing, filler words you repeat a lot, and how often you say “uh.” Knowing they are listening for these things will help you improve.&lt;/p&gt;

&lt;p&gt;If you don’t have anybody near you, then record yourself. Once you’re done giving your talk in front of the camera, you’re going to watch and listen to it separately. For listening, turn your screen around so that you can’t see the video and just listen. See where the ‘uh’ moments and filler words are. For viewing, turn off your sound and just watch what you do with your body posture and with your hands. &lt;/p&gt;

&lt;p&gt;Are you using those hands too little or too much? are you saying ‘uh’ a lot in a certain part of the talk? Are you sloughed over? Notice what you would like to do better, focus on that when you record yourself again and only rehearse the bits you were unhappy with, especially when it’s a longer (45 minutes or more) talk.&lt;/p&gt;

&lt;p&gt;If you feel fully comfortable with your talk, you can decide to only rehearse the first few minutes of your talk. Starting is always the hardest part. Once you get past that first hurdle, your brain will take over if you have practiced the full talk a few times.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fun part: the event
&lt;/h2&gt;

&lt;p&gt;What are you going to do just before you arrive at the event? What are you going to do while you are there? Here are the ins and outs.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Planning your trip&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Normally, when you are accepted to a conference that pays for your travel, there are two possible ways they will handle it. They might have a travel agent who will contact you and book your plane ticket, or you might book the ticket yourself and they will reimburse you after the conference. In most cases, the ticket will be an economy seat without checked luggage, so do not pack too heavy.&lt;/p&gt;

&lt;p&gt;Also keep in mind that the evening before the conference, there is usually a “speaker dinner.” This is a dinner with all the speakers, where you can network and enjoy some local food near the hotel where the rooms were booked. It is great fun, so I recommend booking a flight that arrives at least a couple of hours before dinner time.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Just before leaving the house&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Make sure you have your laptop with your slides and code on it. Also have a backup on the cloud or on GitHub, just in case. If you have a laptop without an HDMI port, bring an USB-C to HDMI adapter. If you need internet for your session, consider bringing an USB-C to ethernet adapter as well. Finally, take your laptop charger and a presentation clicker if you have one.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The night before your session&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;During dinner and the night after, try to stay away from too much alcohol. Speakers really love to drink after or before conference days. However, having a hangover during your talk, especially with bright lights on stage, is not fun. Eat enough so that you sleep well, and do not stay up too late if your talk is early.&lt;/p&gt;

&lt;p&gt;Rest before your talk is very important for your memory, patience, and focus the next day. Try to get the amount of sleep you normally need.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Waking up&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Do your usual morning routine and eat breakfast like you normally do. After that, rehearse your talk a couple of times, either completely or partially, just before leaving for the venue.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;At the event&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;If you are speaking at a meetup, try to be there early and stay for a while if there are other speakers that day. People at meetups really appreciate it if you stay a bit longer for drinks, to have a conversation about your talk or to ask additional questions.&lt;/p&gt;

&lt;p&gt;If it is a multi-day event, it is important to spend some time at the venue before and after your talk. Organizers put in a lot of effort to make the event comfortable for you, often with a speaker room where only speakers are allowed to relax, work, or chat without the busy conference noise. Walk around and talk to attendees, other speakers and sponsors. You can learn a lot from people who are interested in the same topics and it is a great way to connect.&lt;/p&gt;

&lt;p&gt;Also, if it feels like it would help your nerves, go check out the room you’ll be speaking in.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Just before your talk&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is usually the moment where my nerves peak. Everything is ready, there is nothing left to change, and my brain suddenly wants to change everything anyway. But trust me, you’ll be fine.&lt;/p&gt;

&lt;p&gt;Open your laptop and check your slides one more time. Close all software that you do not need. Double-check that Slack, Teams, Discord, or anything similar is not open, and keep your slides ready.&lt;/p&gt;

&lt;p&gt;If you are showing code in an IDE, switch your IDE theme to light mode because it is easier to see on screens. Increase the font size for the IDE and the terminal. JetBrains IDEs have a &lt;a href="https://www.jetbrains.com/guide/java/tutorials/presenting/presentation-mode/" rel="noopener noreferrer"&gt;presentation mode&lt;/a&gt; built in that works very well once you learn how to use it.&lt;/p&gt;

&lt;p&gt;If you’re at a bigger event, also be prepared to get a microphone attached to a headband from somebody. You will need space in one of your pockets for the sender.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;After your talk&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You just gave your (first) talk. Congratulations! Do you want to do more? If so, write down what went well and what did not. That way, you can improve your presentation or demo if you give it again at another event.&lt;/p&gt;

&lt;p&gt;Some events collect feedback from attendees. Some give you that feedback automatically. Others give it to you only if you ask. I still find negative, unhelpful feedback difficult to deal with, so I do not request feedback forms. But positive feedback and constructive criticism can be incredibly helpful, so if you want those forms, ask someone on the event team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other questions answered that I could not put anywhere else
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Do I need a new talk for every event?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;No. Most speakers reuse talks many times, especially in the beginning. Every event has a different audience, so the same session can be given at multiple meetups and conferences. Most speakers refine a talk over time instead of constantly creating new ones.&lt;/p&gt;

&lt;p&gt;As you give the same talk more often, you will naturally start improving it. Feedback from attendees, questions that come up during Q&amp;amp;A, or moments where you notice people lose interest can help you adjust the flow, examples, or depth of the content. You might simplify the talk for beginner-friendly meetups, go deeper into technical details for conferences, or swap demos depending on the audience. Over time, you will also notice when a talk no longer excites you or feels outdated, which is usually a good sign that it is time to retire it or turn it into something new.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Do speakers get paid?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It depends. Meetups usually do not pay. Many conferences will cover travel and hotel, but not a speaking fee, especially when you are starting out. Paid speaking gigs are more common once you are known in the community or when companies invite you directly.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What if my demo fails during the talk?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It happens to everyone. Have backups: a working version, screenshots, or a pre-recorded demo. If something fails, stay calm, explain what would have happened, and move on. Attendees did not come to your session to laugh at you when you ‘fail’. The majority are forgiving and helpful. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How do I deal with nerves or stage fright?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Practice helps a lot, especially the first bit. Also try breathing slowly, drinking water, or having a short script for your opening line. Remember that the audience wants you to succeed. If you forget something, nobody knows your script but you.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How do I grow visibility as a speaker?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Share your slides and demos, write blogs about your talk, post recordings if available, tag the organizers on social media, and keep your Sessionize profile up to date. Being active in online and offline communities helps people remember you.&lt;/p&gt;

&lt;h2&gt;
  
  
  That’s a wrap!
&lt;/h2&gt;

&lt;p&gt;Getting accepted is a big step, but it is only the beginning of the journey. Preparing your talk, dealing with nerves, and standing on stage are all part of learning how public speaking really works. Every single talk will teach you something new, about your content, your timing, and yourself.&lt;/p&gt;

&lt;p&gt;Do not aim for perfection. Aim for feeling prepared and confident enough to enjoy the moment. Your slides do not have to be perfect, your demo does not have to be flawless, and you do not need to sound like a professional keynote speaker. What matters is that you show up, share your knowledge, and do your best.&lt;/p&gt;

&lt;p&gt;If this is your very first accepted talk, take a moment to be proud of yourself. Enjoy the experience, talk to people, and learn from other speakers. If you have done this before, you already know that every event feels different, and that is part of what makes speaking interesting and fun.&lt;/p&gt;

&lt;p&gt;Public speaking is something you grow into over time. With every talk, it gets a little easier, a little more comfortable, and a lot more rewarding.&lt;/p&gt;

&lt;p&gt;If you have questions, experiences to share, or things you are unsure about, feel free to leave a comment under this post. You can also find me on &lt;a href="https://louella.dev/socials" rel="noopener noreferrer"&gt;my socials&lt;/a&gt; if you would rather reach out there.&lt;/p&gt;

</description>
      <category>speaking</category>
      <category>programming</category>
      <category>beginners</category>
      <category>community</category>
    </item>
  </channel>
</rss>
