<?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: Ken Yegon</title>
    <description>The latest articles on DEV Community by Ken Yegon (@ken_yegon_k).</description>
    <link>https://dev.to/ken_yegon_k</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%2F4080524%2F4386edb0-0330-4e4d-9fac-4cc5b52efd57.png</url>
      <title>DEV Community: Ken Yegon</title>
      <link>https://dev.to/ken_yegon_k</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ken_yegon_k"/>
    <language>en</language>
    <item>
      <title>5 Silent Bugs I Hit Cleaning a Messy CSV in Power BI (and How I Caught Them)</title>
      <dc:creator>Ken Yegon</dc:creator>
      <pubDate>Thu, 15 Oct 2026 03:09:58 +0000</pubDate>
      <link>https://dev.to/ken_yegon_k/5-silent-bugs-i-hit-cleaning-a-messy-csv-in-power-bi-and-how-i-caught-them-501h</link>
      <guid>https://dev.to/ken_yegon_k/5-silent-bugs-i-hit-cleaning-a-messy-csv-in-power-bi-and-how-i-caught-them-501h</guid>
      <description>&lt;p&gt;I'm a nurse moving into data engineering, and my LuxDev Cohort 9 assessment was to turn a messy vehicle-sales CSV from a Kenyan dealership into a Power BI report. The data had 276 rows and 32 columns, and almost every column was dirty.&lt;/p&gt;

&lt;p&gt;The biggest lesson was that &lt;strong&gt;nothing in Power BI crashed when I got it wrong.&lt;/strong&gt; The numbers just came out quietly wrong. Here are the five silent bugs that taught me the most.&lt;/p&gt;

&lt;p&gt;Full project: &lt;a href="https://github.com/kenkiprotich/jcars-power-bi" rel="noopener noreferrer"&gt;https://github.com/kenkiprotich/jcars-power-bi&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What "messy" looked like
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prices as &lt;code&gt;KSh 112,000&lt;/code&gt;, &lt;code&gt;USD 238.46&lt;/code&gt;, &lt;code&gt;0.02M&lt;/code&gt;, &lt;code&gt;R 19,733.33&lt;/code&gt;, or plain text like &lt;code&gt;missing&lt;/code&gt; and &lt;code&gt;TBD&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Car makes spelled &lt;code&gt;totoya&lt;/code&gt;, &lt;code&gt;mitshubishi&lt;/code&gt;, &lt;code&gt;v.w&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Dates as Excel serial numbers, &lt;code&gt;DD/MM/YYYY&lt;/code&gt;, and &lt;code&gt;dd-Mon-yy&lt;/code&gt; in the same column&lt;/li&gt;
&lt;li&gt;Payment status written 32 different ways&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built 26 standardized columns in Power Query, converted six currencies to KES, and modelled the result as a star schema: one fact table and six dimensions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 1: The lookup that failed without an error
&lt;/h2&gt;

&lt;p&gt;For car make and model I first used &lt;code&gt;Record.Field&lt;/code&gt; with a record of mappings, wrapped in &lt;code&gt;try ... otherwise&lt;/code&gt;. The &lt;code&gt;try&lt;/code&gt; swallowed every failure, so unmatched values quietly became "Unknown" and I didn't notice.&lt;/p&gt;

&lt;p&gt;The fix was a list of pairs and &lt;code&gt;List.Select&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ecl"&gt;&lt;code&gt;&lt;span class="nx"&gt;Pairs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;toyota&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;Toyota&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;totoya&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;Toyota&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;toyta&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;Toyota&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
&lt;span class="nx"&gt;Match&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Pairs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt; &lt;span class="nx"&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Raw&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="nx"&gt;Result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;List&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nx"&gt;then&lt;/span&gt; &lt;span class="nx"&gt;Match&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;else&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="nx"&gt;Unknown&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I checked it against every distinct raw value. &lt;strong&gt;Lesson: &lt;code&gt;try ... otherwise&lt;/code&gt; hides mistakes, so verify the output, not just the absence of errors.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 2: A merge that multiplied my table by more than 200
&lt;/h2&gt;

&lt;p&gt;I merged a dimension table into the fact table on only one key column. Power Query matched every row to every similar row, and my 276-row table became &lt;strong&gt;61,544 rows&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The fix was to select &lt;strong&gt;all&lt;/strong&gt; matching columns in the merge. &lt;strong&gt;Lesson: check the row count after every merge.&lt;/strong&gt; It takes two seconds and would have saved me hours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 3: Four columns that were secretly the same column
&lt;/h2&gt;

&lt;p&gt;Unit cost, delivery fee, logistics cost and revenue all showed exactly the same numbers as the selling price. I had copied the price-cleaning step four times and never changed the column it read from. All four read &lt;code&gt;[Unit Selling Price]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Nothing errored, because the step was valid. &lt;strong&gt;Lesson: when two business columns should differ, check that they do.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 4: The column Power BI refused to sum
&lt;/h2&gt;

&lt;p&gt;My Card visual kept putting the price field into the wrong well. The real problem was that the custom column had no data type, so Power BI treated it as text. The tell is the &lt;strong&gt;Σ icon&lt;/strong&gt; in the Data pane: numeric columns have it, text columns don't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug 5: A join that was too strict
&lt;/h2&gt;

&lt;p&gt;2% of my sales had no branch. I had joined on four fields (region, county, city, branch), and one "Unknown" in any of them broke the match. Since each city has exactly one branch, matching on city alone fixed it, and I documented the assumption.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers still needed judgment
&lt;/h2&gt;

&lt;p&gt;Cleaning isn't only mechanical. Some decisions had no right answer, so I wrote each one down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Negative revenue on a paid order is a sign typo, so I flipped it. On a cancelled order it became 0, because no sale means no revenue.&lt;/li&gt;
&lt;li&gt;Sales with blank revenue were excluded from cost, because including their cost created a fake loss.&lt;/li&gt;
&lt;li&gt;Delivery fee is paid by the customer, so I kept it out of profit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the data said
&lt;/h2&gt;

&lt;p&gt;Overall margin came out near 13%. Kakamega led on revenue but Eldoret led on profit, and one branch, Thika, lost about 15m KES because its costs were higher than its revenue. I checked whether blank data caused the loss before calling it real. It didn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's still imperfect
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;About 5% of revenue values are blank, so profit is slightly understated.&lt;/li&gt;
&lt;li&gt;Customers aren't de-duplicated, because there was no reliable key.&lt;/li&gt;
&lt;li&gt;Exchange rates are fixed, not the rate on each order date.&lt;/li&gt;
&lt;li&gt;I haven't tested why Thika sells below cost. Discounting is my guess, not a finding.&lt;/li&gt;
&lt;li&gt;The report covers sales, vehicles, branches and reps. Customer, payment and returns pages are still to come.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I'd tell a beginner
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Check row counts after every join.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Check that columns that should differ actually differ.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never trust &lt;code&gt;try ... otherwise&lt;/code&gt; without checking the output.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write your assumptions down as you go.&lt;/strong&gt; They are the most valuable part of the documentation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The report and DAX are in the repo: [GitHub repo link]. If you've hit a silent bug of your own, I'd like to hear about it in the comments.&lt;/p&gt;

</description>
      <category>dataanalysis</category>
      <category>powerbi</category>
    </item>
    <item>
      <title>I had a hard time understanding GIT, until I stopped viewing it as a concept to understand but a tool</title>
      <dc:creator>Ken Yegon</dc:creator>
      <pubDate>Sat, 22 Aug 2026 22:17:33 +0000</pubDate>
      <link>https://dev.to/ken_yegon_k/i-had-a-hard-time-understanding-git-until-i-stopped-viewing-it-as-a-concept-to-understand-but-a-1plg</link>
      <guid>https://dev.to/ken_yegon_k/i-had-a-hard-time-understanding-git-until-i-stopped-viewing-it-as-a-concept-to-understand-but-a-1plg</guid>
      <description>&lt;p&gt;Pushing repos to github from git was quite hard for me at first.I kept staring at the tutor do it with much ease,commands and expected outputs flawlessly.I was impressed and humbled in equal measure.It seemed like a very smart thing that maybe I wasn't cut out for.I thought maybe I could stick to my medical career. Then I understood one thing, GitHub and Git were just tools and not a concept in development.&lt;br&gt;
By the end of this article, just like me you will have a good understanding of it. The catch though, is you have to relax your mind, don't overthink it , don't complicate it.&lt;br&gt;
Before I understood it, I kept mulling over how experienced techies' github appeared and went back and forth from github checking the very complicated website;the repos branches , the green contibution graph, pull requests were a little too much for my eyes.The first problem I encountered was generating the SSH keys, which i am going to start with.&lt;br&gt;
I didn't understand why Github needed SSH keys when it was password protected, or so i thought.Turns out SSH keys lets my computer and Github trust each other without requiring my password everytime I push(Time is of essence here).I opened Gitbash and ran:&lt;br&gt;
   ssh-keygen -t ed25519 -C "&lt;a href="mailto:kenyegonkiprotich@gmail.com"&gt;kenyegonkiprotich@gmail.com&lt;/a&gt;"&lt;br&gt;
A few seconds it gave me this:&lt;/p&gt;

&lt;p&gt;Your identification has been saved in /c/Users/User/.ssh/id_ed25519&lt;br&gt;
Your public key has been saved in /c/Users/User/.ssh/id_ed25519.pub&lt;br&gt;
The key fingerprint is:&lt;br&gt;
SHA256:lJy+5vBdz6+QnyWBgrRu7JO4ET++e+QULDlz78q4XK0 &lt;a href="mailto:kenyegonkiprotich@gmail.com"&gt;kenyegonkiprotich@gmail.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Along with a little ASCII art image apparently that's just a visual fingerprint, mostly decorative for a beginner like me.&lt;br&gt;
This was the first moment it stopped feeling abstract. I had two actual files on my computer now, a private key and a public key.&lt;br&gt;
To get the key , I ran:&lt;br&gt;
cat /c/Users/User/.ssh/id_ed25519.pub&lt;br&gt;
and copied the output into GitHub , under settings , SSH and GPG keys ,New SSH.&lt;br&gt;
I then went back to Git Bash to test the connection by running:&lt;br&gt;
ssh -T &lt;a href="mailto:git@github.com"&gt;git@github.com&lt;/a&gt;&lt;br&gt;
and got confirmation that i had succesfully authenticated.This was the first successes I had.&lt;/p&gt;

&lt;p&gt;Now lets move on to the actual Git workflow.I made a practice folder and turned it into a Git repository.On Git Bash ,I ran:&lt;/p&gt;

&lt;p&gt;mkdir git-practice&lt;br&gt;
cd git-practice&lt;br&gt;
git init&lt;/p&gt;

&lt;p&gt;Git gave this output :&lt;/p&gt;

&lt;p&gt;Initialized empty Git repository in C:/Users/User/git-practice/.git/&lt;/p&gt;

&lt;p&gt;Then I created this simple file by running:&lt;/p&gt;

&lt;p&gt;echo "This is my first Git practice file" &amp;gt; notes.txt&lt;/p&gt;

&lt;p&gt;and checked status:&lt;/p&gt;

&lt;p&gt;git status&lt;/p&gt;

&lt;p&gt;which gave me the output:&lt;br&gt;
Untracked files:&lt;br&gt;
        notes.txt&lt;/p&gt;

&lt;p&gt;to show that the file was untracked.&lt;br&gt;
This was the working directory.Git could see the file existed but it wasn't tracking it yet.Next I staged it:&lt;/p&gt;

&lt;p&gt;git add notes.txt&lt;br&gt;
git status&lt;/p&gt;

&lt;p&gt;and the message changed to:&lt;/p&gt;

&lt;p&gt;Changes to be committed:&lt;br&gt;
        new file:   notes.txt&lt;/p&gt;

&lt;p&gt;Finally I committed it:&lt;br&gt;
git commit -m "add notes file"&lt;/p&gt;

&lt;p&gt;output:&lt;/p&gt;

&lt;p&gt;[main (root-commit) 4400b81] add notes file&lt;br&gt;
 1 file changed, 1 insertion(+)&lt;br&gt;
 create mode 100644 notes.txt&lt;/p&gt;

&lt;p&gt;The last step was connecting my local repo to GitHub and pushing it up.I created an empty repository on GitHub , then linked it:&lt;/p&gt;

&lt;p&gt;git remote add origin &lt;a href="mailto:git@github.com"&gt;git@github.com&lt;/a&gt;:kenkiprotich/git-practice.git&lt;/p&gt;

&lt;p&gt;and pushed:&lt;/p&gt;

&lt;p&gt;git push -u origin main&lt;/p&gt;

&lt;p&gt;Output: &lt;br&gt;
 Enumerating objects: 3, done.&lt;br&gt;
Counting objects: 100% (3/3), done.&lt;br&gt;
Writing objects: 100% (3/3), 249 bytes | 249.00 KiB/s, done.&lt;br&gt;
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0&lt;br&gt;
To github.com:kenkiprotich/git-practice.git&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[new branch]      main -&amp;gt; main
branch 'main' set up to track 'origin/main'.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On refreshing the GitHub page , there it was ,visible.&lt;/p&gt;

&lt;p&gt;Looking back , I am cut out for this.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
