﻿<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
	<channel>
		<title>Ankur Sheel</title>
		<link>https://www.ankursheel.com/</link>
		<description>I go down rabbit holes and blog about them</description>
		<copyright>2026</copyright>
		<pubDate>Thu, 05 Mar 2026 01:41:56 GMT</pubDate>
		<lastBuildDate>Thu, 05 Mar 2026 01:41:56 GMT</lastBuildDate>
		<item>
			<title>WordXplorer Update 11</title>
			<link>https://www.ankursheel.com/blog/wordxplorer-update-11</link>
			<description>New theme, smarter background</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/wordxplorer-update-11-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/wordxplorer-update-11</guid>
			<pubDate>Thu, 05 Feb 2026 00:00:00 GMT</pubDate>
			<content:encoded>&lt;h2 id="new-theme"&gt;New Theme&lt;/h2&gt;
&lt;p&gt;Remember when I asked you which theme should come next?&lt;/p&gt;
&lt;p&gt;Well, you voted. And here it is.&lt;/p&gt;
&lt;p&gt;I've added a brand-new theme with 24 levels focusing on &lt;strong&gt;body parts&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Hands, feet, eyes – the classics and a few tricky ones. It's the kind of vocabulary that actually helps kids describe their world.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center;"&gt;Level Selection Screen&lt;/th&gt;
&lt;th style="text-align: center;"&gt;Game Screen&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-11/body_part_level_selection_screen.png" width="200" alt="Body Part Level Selection Screen"&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-11/body_part_game_screen.png" width="200" alt="Body Part Game Screen.png"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="dynamic-backgrounds"&gt;Dynamic Backgrounds&lt;/h2&gt;
&lt;p&gt;Some of the more eagle eyed readers might have noticed that the background is a little different in the above 2 screen shots.&lt;/p&gt;
&lt;p&gt;There are no more generic bubbles. No more one-size-fits-all backgrounds. The backgrounds now change based on the theme.&lt;/p&gt;
&lt;p&gt;If you're playing the &lt;em&gt;Things We Eat&lt;/em&gt; theme, you see food. If you're in &lt;em&gt;Body Parts&lt;/em&gt;, you see... well, you know. It sounds simple, and it is. But, it gives kids an instant visual clue about what the theme is.&lt;/p&gt;
&lt;p&gt;To be honest, this works best on a tablet where you can really see the new elements.&lt;/p&gt;
&lt;p&gt;On a phone? It's more subtle – due to the lack of screen space. But if kids need a reminder of the theme, the hint screen has them covered.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center;"&gt;Before&lt;/th&gt;
&lt;th style="text-align: center;"&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-11/before_splash_screen.png" width="200" alt="Before Splash Screen"&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-11/after_splash_screen.png" width="200" alt="After Splash Screen"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-11/before_level_selection_screen.png" width="200" alt="Before Level Selection Screen"&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-11/after_level_selection_screen.png" width="200" alt="After Level Selection Screen"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-11/before_game_screen.png" width="200" alt="Before Game Screen"&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-11/after_game_screen.png" width="200" alt="After Game Screen"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="beta-testers-save-the-day"&gt;Beta Testers Save the Day&lt;/h2&gt;
&lt;p&gt;Before I released this update to everyone, the beta testers found a couple of nasty bugs.&lt;/p&gt;
&lt;p&gt;One was particularly gnarly: if you completed the last level and then tried to click "next level," the game would crash. When you reopened it, the level selection screen would be completely borked.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I'm so glad we caught it before release.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If that had made it to a paying user? Ooof. That would have sucked.&lt;/p&gt;
&lt;h3 id="want-to-be-a-beta-tester"&gt;Want to Be a Beta Tester?&lt;/h3&gt;
&lt;p&gt;If you're interested in helping me catch bugs before they reach everyone else, I'd love to have you on board. All you need to do is send me a screenshot of a review (to prove you've got the app). That's it.  As an added bonus, I will give you a free copy of the app to give to your friends.&lt;/p&gt;
&lt;h2 id="level-button-updates"&gt;Level Button Updates&lt;/h2&gt;
&lt;p&gt;Before the level selection screen, the level buttons were just random colors. They looked colorful but didn't give a clear indication of what level is completed and which one is newly unlocked. Now the level buttons can only have 1 of 3 colors - depending on the level status.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center;"&gt;Before&lt;/th&gt;
&lt;th style="text-align: center;"&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-11/before_level_selection_screen.png" width="200" alt="Before Level Selection Screen"&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-11/body_part_level_selection_screen.png" width="200" alt="After Level Selection Screen"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="whats-next"&gt;What's Next?&lt;/h2&gt;
&lt;p&gt;I'm adding a proper menu screen. It's not flashy – just polish and table stakes. Things that I had cut for the intial release.&lt;/p&gt;
&lt;p&gt;More updates coming soon. Can't wait to share what's next.&lt;/p&gt;
&lt;h2 id="get-wordxplorer"&gt;Get WordXplorer&lt;/h2&gt;
&lt;p&gt;WordXplorer is available on the iOS App Store and Google Play store.&lt;/p&gt;
&lt;div class="appstore-badges-container"&gt;
  &lt;a href="https://apps.apple.com/in/app/wordxplorer-guess-the-word/id6504664783" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-app-store-badge.png" alt="Get WordXplorer on App Store"&gt;
  &lt;/a&gt;
  &lt;a href="https://play.google.com/store/apps/details?id=com.glhf.wordleforkids" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-play-store-badge.png" alt="Get WordXplorer on Play Store"&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Want to try before you buy? Check out our &lt;a href="https://wordxplorer.ankursheel.com/"&gt;web demo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you for being a part of this journey with me! I'm eager to hear your thoughts and feedback. Stay tuned for more updates!&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>WordXplorer One Year In: Am I a Millionaire Yet?</title>
			<link>https://www.ankursheel.com/blog/wordxplorer-one-year-am-millionaire-yet</link>
			<description>Am I Millionaire yet? A retrospective and some numbers one year after the launch of WordXplorer</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/wordxplorer-one-year-am-millionaire-yet-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/wordxplorer-one-year-am-millionaire-yet</guid>
			<pubDate>Tue, 13 Jan 2026 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;It's been just over a year since I released WordXplorer - a Wordle-inspired game for kids built in Unity. Available on the App Store and Play Store, this has been an interesting adventure.&lt;/p&gt;
&lt;p&gt;The million-dollar question that is on everyone's mind:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Are you a millionaire yet?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not quite. But I've crossed a few items off my &lt;a href="https://www.ankursheel.com/impossible-list"&gt;impossible list&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Most importantly, I've validated that people are willing to pay for something I've built. And that feels good.&lt;/p&gt;
&lt;p&gt;In this post, I'll share WordXplorer's performance over the past year, the feedback I've received, and the lessons learned along the way.&lt;/p&gt;
&lt;h2 id="a-little-backstory"&gt;A Little Backstory&lt;/h2&gt;
&lt;p&gt;In June 2024, I started working on a prototype of a Wordle-like game for my daughter. She loved trying to do the New York Times Wordle with us, but it was (at times) just too hard for her. It was also not very enticing for a kid. Greys and black are not the most kid-friendly colours.&lt;/p&gt;
&lt;p&gt;Thinking that other kids might want to play along with their Wordle-loving parents, I decided to make it into a paid app and announced a release date of December 1st in early November 2024. I priced it at USD 3.99 - roughly the cost of a coffee.&lt;/p&gt;
&lt;h2 id="what-went-right"&gt;What went right&lt;/h2&gt;
&lt;h3 id="my-daughter-still-plays-it"&gt;My daughter still plays it&lt;/h3&gt;
&lt;p&gt;Seeing my daughter play and enjoy something I built for her - that never gets old. That's why I started this whole thing. She's the 1st tester for all the changes I make and always has some good feedback for me. She's quick to tell me when a word is too hard or when she spots a bug I missed.&lt;/p&gt;
&lt;p&gt;Including my daughter, I still have 1-4 other active users on any given day.&lt;/p&gt;
&lt;h3 id="getting-help-early-on"&gt;Getting help early on&lt;/h3&gt;
&lt;p&gt;My artistic chops are average at best (and that's me being extremely generous). Getting Manjari to help me with the non-engineering side of things was one of the best decisions I made.&lt;/p&gt;
&lt;p&gt;Even though we are both extremely busy with work and syncs across the timezones were (and still are) challenging, having someone else to shoulder some of the load and talk through ideas made it a lot easier.&lt;/p&gt;
&lt;p&gt;The game also looks significantly better than I had made in the prototype phase. See for yourself.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center;"&gt;Before&lt;/th&gt;
&lt;th style="text-align: center;"&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-one-year-am-millionaire-yet/old_game_screen.jpg" alt="Old Game Screen"&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-one-year-am-millionaire-yet/new_game_screen.jpg" width="200" alt="New Game Screen"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="github-actions-and-cicd"&gt;GitHub actions and CI/CD&lt;/h3&gt;
&lt;p&gt;One of the first things I did was set up GitHub actions to run automated tests on every merge to the master branch. I also set up workflows to deploy to the web and app stores.&lt;/p&gt;
&lt;p&gt;Since I don't have a Mac, this made deploying to the iOS App Store much cheaper and easier. I could trigger a deployment at any time. On PRs, I had test builds on the web using Netlify's branch deploy feature. Best of all, I could work in parallel on my local machine while it was building (which took upwards of 20 minutes).&lt;/p&gt;
&lt;h3 id="pre-orders"&gt;Pre-orders&lt;/h3&gt;
&lt;p&gt;I started the App Store pre-order process early. It let me navigate the approval process and work out most of the kinks before the December 1st launch day.&lt;/p&gt;
&lt;p&gt;One thing I learned during pre-order: I can't use "Wordle" in the app description or screenshots which kinda sucks since the game is essentially "Wordle For Kids" and would have been the easiest way to get people to buy it.&lt;/p&gt;
&lt;p&gt;Imagine being ready to launch and then hearing from the App Store &lt;del&gt;gods&lt;/del&gt; reviewers that "Wordle" is not allowed in the description or screenshots and having to delay the launch by a few weeks.&lt;/p&gt;
&lt;h3 id="making-hard-calls-to-ship"&gt;Making hard calls to ship&lt;/h3&gt;
&lt;p&gt;When I announced December 1st as the launch date, there was &lt;em&gt;so much&lt;/em&gt; to be done.&lt;/p&gt;
&lt;p&gt;It was fine when it was a free game that I made for my daughter, but a paid app for strangers is a totally different ball game. Deciding which features to cut for launch wasn't easy, but I had to ship, so I made the hard calls.&lt;/p&gt;
&lt;p&gt;Too many side projects die in "&lt;strong&gt;&lt;em&gt;just one more feature&lt;/em&gt;&lt;/strong&gt;" hell.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-one-year-am-millionaire-yet/feature_hell.png" width="300" alt="Feature Hell.png"&gt;&lt;/p&gt;
&lt;p&gt;Looking back, it was the right call even though I knew 30 levels wasn't enough and I didn't have all the polish. I had to get it out on time.&lt;/p&gt;
&lt;h3 id="validation"&gt;Validation&lt;/h3&gt;
&lt;p&gt;I didn't go viral. I didn't make life-changing money. But &lt;strong&gt;people paid real money for something I built&lt;/strong&gt;. That's something.&lt;/p&gt;
&lt;p&gt;Friends and family bought it initially - that's expected.&lt;/p&gt;
&lt;p&gt;But then someone else bought it. A complete stranger who had no obligation to support me. It was proof that someone out there thought what I built was worth paying for.&lt;/p&gt;
&lt;p&gt;If you're sitting on a side project, waiting for it to be "perfect" before launching - just ship it. Shipping something you know is not finished is scary, but you should still do it. You will learn a lot.&lt;/p&gt;
&lt;h3 id="natural-break-patterns"&gt;Natural break patterns&lt;/h3&gt;
&lt;p&gt;The average session is around &lt;strong&gt;3 minutes&lt;/strong&gt;. That's roughly one to two levels, which means most kids play, complete a level or two, and then leave the app to do something else.&lt;/p&gt;
&lt;p&gt;Some kids binge multiple levels and go up to 30 minutes, but the typical pattern is short sessions.&lt;/p&gt;
&lt;p&gt;This is great since I didn't want kids getting hooked and be on the screen for hours on end. And since most users have completed all 30 levels, they have clearly come back to play the levels.&lt;/p&gt;
&lt;p&gt;The average user has spent about 1 hour on the app total.&lt;/p&gt;
&lt;h2 id="what-went-wrong-aka-lessons-learned"&gt;What went wrong, aka lessons learned&lt;/h2&gt;
&lt;h3 id="pre-orders-are-great-if-you-actually-promote-them"&gt;Pre-orders are great (if you actually promote them)&lt;/h3&gt;
&lt;p&gt;The pre-order strategy was smart for working out the kinks with App Store approval. But not promoting it &lt;del&gt;widely&lt;/del&gt; at all? That was dumb.&lt;/p&gt;
&lt;p&gt;I fell into the classical engineer's mistake:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Build it, and they will come.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I didn't publicise the pre-order beyond some posts on this blog. A few days before launch, I directly messaged friends and family, which resulted in a grand total of 4 pre-orders. Two of those were later cancelled.&lt;/p&gt;
&lt;p&gt;Yeah. Not exactly a viral launch.&lt;/p&gt;
&lt;p&gt;Part of it was discomfort with self-promotion. Part of it was simply not knowing where to start.&lt;/p&gt;
&lt;p&gt;If you're going to offer a pre-order, be sure to let people know about it.&lt;/p&gt;
&lt;h3 id="googles-requirements"&gt;Google's requirements&lt;/h3&gt;
&lt;p&gt;Google requires 12 people to actively play your game for 10 days before you can even release an app to the store.&lt;/p&gt;
&lt;p&gt;And if it's a paid app then &lt;strong&gt;&lt;em&gt;they have to buy it&lt;/em&gt;&lt;/strong&gt; to even test it. It's unclear if they have to buy it again when the app store listing goes live, so to be safe I just made it free for a week so that people could download it without having to pay. Unfortunately promo codes just didn't work for this.&lt;/p&gt;
&lt;p&gt;Not just install it - actively play it for 10 days. I didn't know what would happen if someone quit after 2 days or didn't play every day, so I added 15 people to be safe. Getting friends and family to commit to playing for 10 days straight was challenging.&lt;/p&gt;
&lt;p&gt;It's a significant hurdle that slowed down the Android launch. It also meant people who otherwise might have bought the game got it for free.&lt;/p&gt;
&lt;h3 id="promo-codes"&gt;Promo codes&lt;/h3&gt;
&lt;p&gt;I gave 12 promo codes on iOS as a thank you for providing early feedback.&lt;/p&gt;
&lt;p&gt;The kicker: promo code users can't leave reviews on the App Store. These were my most supportive users - the ones who would have left positive reviews - and the platform prevented them from doing so.&lt;/p&gt;
&lt;p&gt;Even though I didnt know this at the time, I would have still given the promo codes.&lt;/p&gt;
&lt;h3 id="android-refunds"&gt;Android refunds&lt;/h3&gt;
&lt;p&gt;Android allows refunds within 2 hours of purchase, no questions asked. Out of the 20 orders I got, I had &lt;strong&gt;17 refunds&lt;/strong&gt;. Ouch.&lt;/p&gt;
&lt;p&gt;When I first saw them, I was confused. The game wasn't broken, so what went wrong?&lt;/p&gt;
&lt;p&gt;My best guess? A combination of things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Most people refunded within 15 minutes, so they probably didn't like the look of it or bought it by mistake.&lt;/li&gt;
&lt;li&gt;Maybe some played longer and felt 30 levels wasn't enough content for the price.&lt;/li&gt;
&lt;li&gt;The description and screenshots might not have communicated what the game actually is and the lack of polish probably didn't help either.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The frustrating part? No feedback. Just money taken back. If they'd told me &lt;em&gt;why&lt;/em&gt; they didn't like it, I could have fixed it for them or future users.&lt;/p&gt;
&lt;h3 id="procrastination"&gt;Procrastination&lt;/h3&gt;
&lt;p&gt;Most people have completed all 30 levels. I didn't realise how hard it would be to add a new theme and how much work it would entail. Some of my previous architectural decisions came back to haunt me.&lt;/p&gt;
&lt;p&gt;After the Android release in July 2025, the project was put on the back burner for six months. Not because of work and life (though that was a factor). I was procrastinating because building new themes felt too hard. Everything was stuffed into MonoBehaviours with very few abstractions. This made it nearly impossible to write automated tests, and adding features meant testing everything every time I made a change.&lt;/p&gt;
&lt;p&gt;Eventually, I bit the bullet and refactored the level selection screen/system and added automated tests. It took over a month. But it gave me confidence to make changes in that area without breaking everything.&lt;/p&gt;
&lt;h3 id="one-negative-review"&gt;One negative review&lt;/h3&gt;
&lt;p&gt;I also got &lt;strong&gt;one&lt;/strong&gt; negative review.  It seemed the person didn't understand how the game worked, and it didn't meet their expectations. That stung, but it was valuable feedback. Probably, if they were on Android, they would have just gotten a refund.&lt;/p&gt;
&lt;p&gt;Based on that review, I updated the description and made the instructions a lot clearer.&lt;/p&gt;
&lt;h2 id="show-me-the-money-numbers"&gt;Show me the &lt;del&gt;money&lt;/del&gt; numbers&lt;/h2&gt;
&lt;p&gt;Let's talk numbers.&lt;/p&gt;
&lt;p&gt;I built this on nights and weekends with help from Manjari.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Total cost:&lt;/strong&gt; About NZD 550 (dev accounts, IDE, etc).&lt;br&gt;
&lt;strong&gt;Total proceeds:&lt;/strong&gt; About NZD 110 (after Apple's and Google's cut but before taxes, etc)&lt;/p&gt;
&lt;p&gt;Forget "retirement money", this is not even "cover your costs money".&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;iOS:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Total Downloads: 29&lt;/li&gt;
&lt;li&gt;Total Orders: 17&lt;/li&gt;
&lt;li&gt;Total Revenue: NZD 127&lt;/li&gt;
&lt;li&gt;Proceeds (after Apple's cut): NZD 98&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Android (launched July 2025):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Total Downloads: 35&lt;/li&gt;
&lt;li&gt;Total Orders: 20, but 17 refunds :(&lt;/li&gt;
&lt;li&gt;Total Revenue: NZD 22&lt;/li&gt;
&lt;li&gt;Proceeds (after Google's cut): NZD 17&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Monthly breakdown:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;iOS Units&lt;/th&gt;
&lt;th&gt;Android Units&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Nov 2024&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dec 2024&lt;/td&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jan 2025&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mar 2025&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;May 2025&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jul 2025&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Aug 2025&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sep 2025&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dec 2025&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;17&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Most sales happened in the first month (no surprise), but I still got sporadic purchases throughout the year. iOS went completely silent from Jul to Nov - probably because I did no marketing and very few updates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Geographic Distribution:&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Territory&lt;/th&gt;
&lt;th&gt;iOS Sales/Total Downloads&lt;/th&gt;
&lt;th&gt;Android Sales/Total Downloads&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;India&lt;/td&gt;
&lt;td&gt;8/13&lt;/td&gt;
&lt;td&gt;1/8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;United States&lt;/td&gt;
&lt;td&gt;7/9&lt;/td&gt;
&lt;td&gt;2/10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New Zealand&lt;/td&gt;
&lt;td&gt;0/5&lt;/td&gt;
&lt;td&gt;0/2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Australia&lt;/td&gt;
&lt;td&gt;1/1&lt;/td&gt;
&lt;td&gt;0/1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canada&lt;/td&gt;
&lt;td&gt;1/1&lt;/td&gt;
&lt;td&gt;0/0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;United Kingdom&lt;/td&gt;
&lt;td&gt;0/0&lt;/td&gt;
&lt;td&gt;0/1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Unsuprisingly, most downloads came from India, USA and New Zealand - those areas are where I focused my (minimal) outreach and gave out promo codes. The download from Canada was unexpected. I didn't speak to anyone there.&lt;/p&gt;
&lt;p&gt;Nearly half of my downloads came from organic App Store search. Not bad for zero marketing efforts.&lt;/p&gt;
&lt;p&gt;Someone even discovered the game in December 2025, a full year after its launch. I only found out from my monthly report, but that was a nice surprise. Even though I don't know what they were searching for, I am glad they bought it.&lt;/p&gt;
&lt;h2 id="shipped-improvements"&gt;Shipped improvements&lt;/h2&gt;
&lt;p&gt;Even though updates have been sporadic, watching my daughter play and looking at the analytics showed me what needed fixing. Some of the highlights from the past year:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Contextual hints:&lt;/strong&gt; Kids were getting stuck. I added clues that unlock as they play, helping them think about the word differently without giving away the answer. Analytics show that this is a very popular feature.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Save progress:&lt;/strong&gt; Kids would start a level, leave, and have to start over. Before I added hints, some of them, including my daughter, would quit the level after attempt 6, and restart it essentially having unlimited tries to figure out the word. Kids are smart, and they will find ways to &lt;del&gt;break your game&lt;/del&gt; game the system. Saving their progress not only closed this loophole but also allowed them to take breaks and pick up where they left off.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web demo:&lt;/strong&gt; In response to the refunds, low purchase volume, and negative feedback, I added a &lt;a href="https://wordxplorer.ankursheel.com/"&gt;web demo&lt;/a&gt; a few months ago so people can try it before committing to buy. I still don't know if it has made any difference.&lt;/li&gt;
&lt;li&gt;Squashing all the bugs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="whats-next"&gt;What's Next?&lt;/h2&gt;
&lt;p&gt;Now that I've refactored some of the code, I can actually add content without spending hours clicking through the screens. I still need to refactor the main game screen though :(&lt;/p&gt;
&lt;p&gt;New theme dropping in February - &lt;strong&gt;body parts&lt;/strong&gt;. It's already in active testing and I'm working out the kinks.&lt;/p&gt;
&lt;p&gt;I'm also going to be adding the things that make it feel like a complete game, not just a prototype that shipped: proper menus, settings, polish. The stuff I cut to hit that December 1st deadline.&lt;/p&gt;
&lt;p&gt;I've figured out a sustainable schedule with a plan to write an update post every month. In fact, one has already gone out in January.&lt;/p&gt;
&lt;h2 id="so.was-it-worth-it"&gt;So… Was It Worth It?&lt;/h2&gt;
&lt;p&gt;Yes. Not because I made a ton of money (I didn't). Not because I have thousands of users (I don't).&lt;/p&gt;
&lt;p&gt;Eventually, this might actually be profitable. Even now I can claim some of the expenses to reduce my tax burden.&lt;/p&gt;
&lt;p&gt;But even if it never makes me a ton of money, I crossed items off my bucket list, got a creative outlet from professional work, and got to see my daughter play something I built for her. You can't put a price tag on that.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Sitting on a side project that's "almost ready"? Ship it. I'd love to hear what happens.&lt;/p&gt;
&lt;p&gt;Lost money on something you built but would do it again? Tell me about it.&lt;/p&gt;
&lt;p&gt;Want to be a beta tester and get updates earlier? Let me know!&lt;/p&gt;
&lt;h2 id="get-wordxplorer"&gt;Get WordXplorer&lt;/h2&gt;
&lt;div class="appstore-badges-container"&gt;
  &lt;a href="https://apps.apple.com/in/app/wordxplorer-guess-the-word/id6504664783" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-app-store-badge.png" alt="Get WordXplorer on App Store"&gt;
  &lt;/a&gt;
  &lt;a href="https://play.google.com/store/apps/details?id=com.glhf.wordleforkids" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-play-store-badge.png" alt="Get WordXplorer on Play Store"&gt;
  &lt;/a&gt;
&lt;/div&gt;    
&lt;p&gt;Want to try before you buy? Check out the &lt;a href="https://wordxplorer.ankursheel.com/"&gt;web demo&lt;/a&gt;&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>WordXplorer Update 10 : Fireworks, Levels, Polish</title>
			<link>https://www.ankursheel.com/blog/wordxplorer-update-10</link>
			<description>Wordle for Kids update - 6 new levels, more fireworks, and smoother transitions. Plus: why I finally added automated tests.</description>
			<guid>https://www.ankursheel.com/blog/wordxplorer-update-10</guid>
			<pubDate>Tue, 06 Jan 2026 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;You can see all the related updates &lt;a href="https://www.ankursheel.com/tags/wordxplorer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It’s been a while since I wrote an update on this blog.&lt;/p&gt;
&lt;p&gt;Not because there were no update. Well, for some time that was true. You know work and life and all that. But the good news is that I have finally figured out a sustainable schedule, and updates have been going out in the app/Play Store. However, they didn't feel "blog-worthy." And let's be honest: once you miss one update, it’s surprisingly easy to miss the next one too.&lt;/p&gt;
&lt;p&gt;Anyway, here’s what’s changed.&lt;/p&gt;
&lt;h2 id="more-fireworks"&gt;More fireworks&lt;/h2&gt;
&lt;p&gt;I added more fireworks on level completion.&lt;/p&gt;
&lt;p&gt;It sounds trivial when I write it out like that. But you can never have too many fireworks.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-10/fireworks.gif" alt="fireworks"&gt;&lt;/p&gt;
&lt;h2 id="scene-transitions"&gt;Scene transitions&lt;/h2&gt;
&lt;p&gt;I also added scene transitions between screens.&lt;/p&gt;
&lt;p&gt;This is another one of those trivial changes. But, it makes the game feel less like a collection of screens and more like... well, a game.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-10/scene_transitioner.gif" alt="scene transitioner"&gt;&lt;/p&gt;
&lt;h2 id="level-select-now-opens-at-your-highest-unlocked-level"&gt;Level select now opens at your highest unlocked level&lt;/h2&gt;
&lt;p&gt;The level selection screen now opens on the page with your highest unlocked level.&lt;/p&gt;
&lt;p&gt;This is mostly just convenience (less clicking is always a win). This wasnt so much of an issue when it was just 3 screens but as I add themes and more levels to the game, this will make it much easier to navigate.&lt;/p&gt;
&lt;h2 id="more-levels"&gt;6 more levels&lt;/h2&gt;
&lt;p&gt;Since there are 12 levels on the level selection screen, ensuring each theme has a multiple of 12 levels makes the transitions much smoother. It's a little design hack that's going to make it much easier to add themes. But, you get 6 more levels while you wait for the next update.&lt;/p&gt;
&lt;h2 id="behind-the-scenes-refactoring-automated-tests"&gt;Behind the scenes: refactoring + automated tests&lt;/h2&gt;
&lt;p&gt;Alongside the visible changes, I’ve been refactoring the code and adding automated tests to make themes possible without turning every future change into a risky one.&lt;/p&gt;
&lt;p&gt;There was a point where I realised I was spending more time manually clicking through the app to make sure I hadn't broken anything than I was actually building new features. You know the drill: change one line of code, spend 20 minutes tapping screens to ensure everything still works.&lt;/p&gt;
&lt;p&gt;It was exhausting. And frankly, it was boring. And worst of all, it was leading me to procrastinate.&lt;/p&gt;
&lt;p&gt;Automated tests give me the confidence to move fast without that constant fear that I'm breaking something. If you’ve ever maintained a side project alone, you probably know exactly what I mean.&lt;/p&gt;
&lt;h2 id="what-theme-should-i-build-next"&gt;What theme should I build next?&lt;/h2&gt;
&lt;p&gt;I’ve been promising this for a while, and it’s finally (almost) here. I’ve made nearly all the changes needed to support more themes. I am just testing it out before I release it to everyone.&lt;/p&gt;
&lt;p&gt;The frontrunner for me right now is &lt;strong&gt;body parts&lt;/strong&gt;. It feels like a good “kid vocabulary” theme, and I think it could lead to levels that are fun without being too hard.&lt;/p&gt;
&lt;p&gt;But, I need your help. If you were picking a theme, what would you want to see?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Body parts&lt;/li&gt;
&lt;li&gt;Animals&lt;/li&gt;
&lt;li&gt;Nature&lt;/li&gt;
&lt;li&gt;Sports&lt;/li&gt;
&lt;li&gt;Transportation&lt;/li&gt;
&lt;li&gt;In the house&lt;/li&gt;
&lt;li&gt;Action words&lt;/li&gt;
&lt;li&gt;Something else&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What would you pick (and why)?&lt;/p&gt;
&lt;h2 id="get-wordxplorer"&gt;Get WordXplorer&lt;/h2&gt;
&lt;p&gt;WordXplorer is available on the iOS App Store&lt;/p&gt;
&lt;div class="appstore-badges-container"&gt;
  &lt;a href="https://apps.apple.com/in/app/wordxplorer-guess-the-word/id6504664783" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-app-store-badge.png" alt="Get WordXplorer on App Store"&gt;
  &lt;/a&gt;
  &lt;a href="https://play.google.com/store/apps/details?id=com.glhf.wordleforkids" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-play-store-badge.png" alt="Get WordXplorer on Play Store"&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Want to try before you buy? Check out our &lt;a href="https://wordxplorer.ankursheel.com/"&gt;web demo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you for being a part of this journey with me! I'm eager to hear your thoughts and feedback. Stay tuned for more updates!&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>Story Points Aren't the Problem</title>
			<link>https://www.ankursheel.com/blog/story-points-arent-problem</link>
			<description>Sprint planning shouldn’t be a time suck. Learn how story points get misused—and how to fix the process for good.</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/story-points-arent-problem-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/story-points-arent-problem</guid>
			<pubDate>Sat, 26 Jul 2025 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;Like many developers, I hate story pointing.&lt;/p&gt;
&lt;p&gt;It feels like I’ve wasted &lt;em&gt;years&lt;/em&gt; of my life in sprint planning sessions that spiral into arguments over whether something is a 2 or a 3. I’ve also sat through too many sprint planning sessions watching teams treat story points as time estimates, and walk away with no more clarity than when they started.&lt;/p&gt;
&lt;p&gt;It all feels likes a performance that gives &lt;del&gt;management&lt;/del&gt; everyone a false sense of control.&lt;/p&gt;
&lt;p&gt;In fact, some people just do away with story points altogether, and I get it. I was once in that camp too.&lt;/p&gt;
&lt;p&gt;But, what I if told you&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;story points aren't the problem.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I’ve noticed three common mistakes that make story points and the whole sprint planning exercise feel like a giant waste of time. Let's see what they are and how we can fix them to make story-pointing not suck.&lt;/p&gt;
&lt;h2 id="mistake-1-treating-story-points-as-a-proxy-for-time"&gt;Mistake #1: Treating Story Points as a Proxy for Time&lt;/h2&gt;
&lt;p&gt;How often have you heard this in a sprint planning session -&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This should take 1 week, so… five story points?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That’s not how story points work. They’re not about time.&lt;/p&gt;
&lt;p&gt;A 3-point story might take one day or more than a week. I know you dont want to hear it but it doesn't matter.&lt;/p&gt;
&lt;p&gt;Story points should reflect the &lt;strong&gt;complexity&lt;/strong&gt; of the task.&lt;/p&gt;
&lt;p&gt;Here’s a better way to think about them:&lt;/p&gt;
&lt;h3 id="point"&gt;1 Point&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Potential Traits:&lt;/strong&gt; No unknowns, low risk, minimal code changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Adding logs to existing code&lt;/li&gt;
&lt;li&gt;Trivial changes behind a feature flag&lt;/li&gt;
&lt;li&gt;Cleaning up a simple feature flag&lt;/li&gt;
&lt;li&gt;Mechanical refactoring&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="points"&gt;2 Points&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Potential Traits:&lt;/strong&gt; Low risk, some minor unknowns, small test updates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Simple changes behind a feature flag&lt;/li&gt;
&lt;li&gt;Creating a new dashboard with existing data&lt;/li&gt;
&lt;li&gt;Cleaning up a complex feature flag&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="points-1"&gt;3 Points&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Potential Traits:&lt;/strong&gt; Some unknowns, moderate risk, might require coordination with others.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fixing a bug with a known root cause&lt;/li&gt;
&lt;li&gt;New functionality that can be feature flagged cleanly&lt;/li&gt;
&lt;li&gt;Work that involves coordination with another developer&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="points-2"&gt;5 Points&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Potential traits:&lt;/strong&gt; Some unknowns, large code changes, lots of new tests, external dependencies&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Examples&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Technical investigation for new features or bugs&lt;/li&gt;
&lt;li&gt;Work that's difficult to feature flag&lt;/li&gt;
&lt;li&gt;Cross-team coordination&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are good candidates to split into smaller tickets once the investigation is done.&lt;/p&gt;
&lt;h3 id="points-3"&gt;8 Points&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Potential traits:&lt;/strong&gt; Many unknowns, risky changes, hard to estimate confidently.&lt;/p&gt;
&lt;p&gt;If you’re estimating something at 8 points, you probably need a spike first. Timebox it, then use what you’ve learned to create smaller, pointable stories.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/story-points-arent-problem/infographic.png" alt="Storypoint Infographic"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: You can download the full sized infographic from &lt;a href="https://www.ankursheel.com/assets/images/posts/story-points-arent-problem/infographic_original.png"&gt;Printable Infographic&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="mistake-2-estimating-in-isolation"&gt;Mistake #2: Estimating in Isolation&lt;/h2&gt;
&lt;p&gt;Ever had a product owner or a tech lead show up to planning with stories already estimated?&lt;/p&gt;
&lt;p&gt;Estimation is a team sport. Different people catch different risks, assumptions, and edge cases. Getting everyone involved builds shared understanding and better team cohesion.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The number matters less than the conversation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here’s what to do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The feature lead fleshes out the ticket ahead of planning.&lt;/li&gt;
&lt;li&gt;They give a 30-second overview during the session and answer questions.
&lt;ul&gt;
&lt;li&gt;No need to dive into every detail - but enough for the team to understand the &lt;strong&gt;why&lt;/strong&gt;, the &lt;strong&gt;approach&lt;/strong&gt;, and have the &lt;strong&gt;confidence&lt;/strong&gt; to estimate complexity.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Then use Planning Poker to uncover different perspectives.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="mistake-3-arguing-over-2-vs-3-points"&gt;Mistake #3: Arguing Over 2 vs 3 Points&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/story-points-arent-problem/two_vs_three.png" alt="two vs three"&gt;&lt;/p&gt;
&lt;p&gt;You know the moment. One person says it’s a 2. Another insists it’s a 3. Suddenly, you’re 20 minutes deep into a conversation that doesn’t matter.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You’re optimizing for precision in a system designed for approximation.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That’s not just wasteful — it completely misses the point (pun unintended).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Timebox these debates.&lt;/strong&gt; If you can't agree in 1-2 minutes, pick the higher number and move on. It's not worth derailing the whole session.&lt;/p&gt;
&lt;p&gt;However, if there’s a big delta — say, someone thinks it’s a 2 and someone else thinks it’s a 5 — that is worth unpacking. Someone’s probably missing something.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="final-thoughts"&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Story points aren't about precision. They're about shared clarity.&lt;/p&gt;
&lt;p&gt;Used well, they build shared context. Used poorly, they fuel endless debates.&lt;/p&gt;
&lt;p&gt;So next time you're estimating ask yourself:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Do we actually understand the scope, complexity, and purpose of this work?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the answer’s yes, the number doesn't matter.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What’s your biggest frustration with story points — and how have you worked around it?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Drop a comment and send this to someone who’s still fighting over 2 vs 3.&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>WordXplorer Update #9: Save your guesses</title>
			<link>https://www.ankursheel.com/blog/wordxplorer-update-9</link>
			<description>WordXplorer Update #9 introduces a convenient save feature that remembers your guessed words when you exit a level, allowing you to pick up right where you left off for uninterrupted gameplay.</description>
			<guid>https://www.ankursheel.com/blog/wordxplorer-update-9</guid>
			<pubDate>Sun, 08 Jun 2025 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;You can see all the related updates &lt;a href="https://www.ankursheel.com/tags/wordxplorer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="save-your-guesses"&gt;Save your guesses&lt;/h2&gt;
&lt;p&gt;Your guesses are now saved, letting you take as long as you need to solve each level without starting over.&lt;/p&gt;
&lt;p&gt;When you return to a level, you’ll see all your previous guesses, allowing you to continue right where you left off. Once you successfully complete a level, all your guesses for that puzzle will be cleared, giving you a fresh start when you decide to replay it.&lt;/p&gt;
&lt;p&gt;Here's how it works in action:&lt;/p&gt;
&lt;div style="position: relative;width: 100%;padding-bottom: 56.25%;margin: 1rem 0;"&gt;
  &lt;iframe src="https://www.youtube.com/embed/R5ZXlpfyUZY" title="Watch the Save State in action" style="position: absolute;width: 100%;height: 100%;left: 0;top: 0;right: 0;" allowfullscreen=""&gt;&lt;/iframe&gt;
&lt;/div&gt;  
&lt;h2 id="bug-fixes"&gt;Bug Fixes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;I've resolved the issue where the keyboard colour changed to white after moving to the next level.&lt;/li&gt;
&lt;li&gt;I've also fixed the problem where the latest level showed up as locked when you went back to the level selection screen after finishing a level.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="get-wordxplorer"&gt;Get WordXplorer&lt;/h2&gt;
&lt;p&gt;WordXplorer is available on the iOS App Store&lt;/p&gt;
&lt;div class="appstore-badges-container"&gt;
  &lt;a href="https://apps.apple.com/in/app/wordxplorer-guess-the-word/id6504664783" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-app-store-badge.png" alt="Get WordXplorer on App Store"&gt;
  &lt;/a&gt;
  &lt;a href="https://play.google.com/store/apps/details?id=com.glhf.wordleforkids" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-play-store-badge.png" alt="Get WordXplorer on Play Store"&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Want to try before you buy? Check out our &lt;a href="https://wordxplorer.ankursheel.com/"&gt;web demo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you for being a part of this journey with me! I'm eager to hear your thoughts and feedback. Stay tuned for more updates!&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>WordXplorer Update #8: New Hint System</title>
			<link>https://www.ankursheel.com/blog/wordxplorer-update-8</link>
			<description>WordXplorer Update 8 introduces a new hint system with contextual clues to help kids learn and solve words more effectively</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/wordxplorer-update-8-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/wordxplorer-update-8</guid>
			<pubDate>Sat, 10 May 2025 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;You can see all the related updates &lt;a href="https://www.ankursheel.com/tags/wordxplorer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="new-hint-system"&gt;New Hint System&lt;/h2&gt;
&lt;p&gt;We're excited to introduce our new hint system! This feature helps players when they're stuck, making the game more accessible while still maintaining the challenge.&lt;/p&gt;
&lt;p&gt;The hint system provides contextual clues about the word.&lt;/p&gt;
&lt;p&gt;Here's how the hints look when locked and unlocked:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;The hint popup at the start of the game, showing all hints are locked&lt;/th&gt;
&lt;th&gt;The hint popup after 2 hints have been unlocked, showing the available clues&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-8/locked_hints.jpg" alt="Locked Hints"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-8/unlocked_hints.jpg" alt="Unlocked Hints"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;And here's how it works in action:&lt;/p&gt;
&lt;div style="position: relative;width: 100%;padding-bottom: 56.25%;margin: 1rem 0;"&gt;
  &lt;iframe src="https://www.youtube.com/embed/RBW15-Eg97E" title="Watch the hint system in action" style="position: absolute;width: 100%;height: 100%;left: 0;top: 0;right: 0;" allowfullscreen=""&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;These clues help kids think about the word in a different way, making the game both educational and fun. They can use them strategically to learn and improve their word-solving skills.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="get-wordxplorer"&gt;Get WordXplorer&lt;/h2&gt;
&lt;p&gt;WordXplorer is available on the iOS App Store&lt;/p&gt;
&lt;div class="appstore-badges-container"&gt;
  &lt;a href="https://apps.apple.com/in/app/wordxplorer-guess-the-word/id6504664783" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-app-store-badge.png" alt="Get WordXplorer on App Store"&gt;
  &lt;/a&gt;
  &lt;a href="https://play.google.com/store/apps/details?id=com.glhf.wordleforkids" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-play-store-badge.png" alt="Get WordXplorer on Play Store"&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Want to try before you buy? Check out our &lt;a href="https://wordxplorer.ankursheel.com/"&gt;web demo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Thank you for being a part of this journey with me! I'm eager to hear your thoughts and feedback. Stay tuned for more updates!&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>Offset vs Cursor Based Pagination</title>
			<link>https://www.ankursheel.com/blog/offset-vs-cursor-based-pagination</link>
			<description>Understand SQL pagination with practical examples, comparing offset and cursor methods to manage datasets efficiently.</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/offset-vs-cursor-based-pagination-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/offset-vs-cursor-based-pagination</guid>
			<pubDate>Mon, 07 Apr 2025 00:00:00 GMT</pubDate>
			<content:encoded>&lt;h2 id="introduction"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;SQL pagination helps manage large datasets by breaking them into smaller, more manageable chunks called 'pages.' It prevents overwhelming applications by retrieving data one page at a time, ensuring smoother performance and a better user experience.&lt;/p&gt;
&lt;p&gt;In this article, I'll discuss two primary SQL pagination methods—offset and cursor-based—and explore an advanced technique for efficiently handling large datasets, highlighting their specific use cases and benefits.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/offset-vs-cursor-based-pagination/cover.png" width="300" alt="A robot holding a book with turning pages, trying to find a specific page"&gt;&lt;/p&gt;
&lt;h2 id="offset-pagination"&gt;Offset Pagination&lt;/h2&gt;
&lt;p&gt;Offset pagination involves skipping a specified number of rows and then taking a fixed number of rows, allowing for flexible data retrieval.&lt;/p&gt;
&lt;h3 id="example"&gt;Example&lt;/h3&gt;
&lt;p&gt;Here's a typical query using offset pagination:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sql"&gt;SELECT *         
FROM product        
WHERE category = 1        
ORDER BY id         
LIMIT @pageSize         
OFFSET $offset;        
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;LIMIT&lt;/code&gt; clause defines how many rows to return, while &lt;code&gt;OFFSET&lt;/code&gt; skips a specified number of rows. &lt;code&gt;ORDER BY&lt;/code&gt; ensures results are consistent.&lt;/p&gt;
&lt;p&gt;Typically, &lt;code&gt;pageSize&lt;/code&gt; and &lt;code&gt;offset&lt;/code&gt; are set based on user input or application logic to control pagination dynamically. For example, if &lt;code&gt;pageSize&lt;/code&gt; is 100 and &lt;code&gt;offset&lt;/code&gt; is 200, the query retrieves rows 200-300.&lt;/p&gt;
&lt;h3 id="advantages"&gt;Advantages&lt;/h3&gt;
&lt;p&gt;Offset pagination allows you to jump directly to a specific set of records, which is useful for applications requiring quick access to specific data or "go to page X" functionality. For instance, you can easily access a specific range like 3000-3100.&lt;/p&gt;
&lt;p&gt;It is easier to implement, making it useful for smaller systems or static datasets like blog archives or product lists.&lt;/p&gt;
&lt;h3 id="disadvantages"&gt;Disadvantages&lt;/h3&gt;
&lt;p&gt;Offset pagination requires scanning all preceding rows to find the starting point. This can be inefficient and slow as the dataset grows. Performance degrades with larger datasets, as scanning more rows leads to slower response times.&lt;/p&gt;
&lt;p&gt;For example, in a query like &lt;code&gt;SELECT * FROM product ORDER BY id LIMIT 100 OFFSET 100000&lt;/code&gt;, Postgres scans and discards 100,000 rows even though only 100 are needed.&lt;/p&gt;
&lt;p&gt;While offset-based pagination is common in legacy systems, its utility in modern systems may be limited compared to cursor-based pagination.&lt;/p&gt;
&lt;h2 id="cursor-based-pagination"&gt;Cursor-based Pagination&lt;/h2&gt;
&lt;p&gt;Unlike offset pagination, cursor-based pagination fetches results using a unique identifier (or a combination of columns), avoiding the need to skip rows.&lt;/p&gt;
&lt;h3 id="example-1"&gt;Example&lt;/h3&gt;
&lt;p&gt;Here's how you might implement cursor-based pagination:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sql"&gt;SELECT *         
FROM product         
WHERE id &amp;gt; $lastId        
    AND category = 1        
ORDER BY id         
LIMIT $pageSize;        
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that, unlike the previous example, this query doesn't use &lt;code&gt;OFFSET&lt;/code&gt;. Instead, we keep track of the &lt;code&gt;id&lt;/code&gt; of the last record retrieved from the previous page and use it in the &lt;code&gt;WHERE&lt;/code&gt; clause to fetch the next set of records.&lt;/p&gt;
&lt;p&gt;To maintain reliable pagination, it's essential to ensure the cursor column is unique and immutable, as changes could disrupt the order of results. A good candidate is a primary key ID or a &lt;code&gt;CreatedTimestamp&lt;/code&gt; column.&lt;/p&gt;
&lt;h3 id="advantages-1"&gt;Advantages&lt;/h3&gt;
&lt;p&gt;Cursor-based pagination is generally more efficient, as it avoids scanning and discarding rows. Instead, it directly jumps to records based on the cursor value. This approach remains efficient even for large offsets because the database can quickly use an index on the cursor column to find the starting point.&lt;/p&gt;
&lt;p&gt;Cursor-based pagination provides stable results even if new records are inserted or deleted between page requests. Each page contains the expected set of records based on the cursor value.&lt;/p&gt;
&lt;h3 id="disadvantages-1"&gt;Disadvantages&lt;/h3&gt;
&lt;p&gt;Cursor-based pagination requires sequential page traversal and is more complex to implement because you must track the cursor value in your application code. This might be less convenient for users who want to navigate directly to a specific page.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; However, we can avoid the need for sequential page traversal by using PageInfo/PageCursor in GraphQL.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We need to be mindful of &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Insecure_Direct_Object_Reference_Prevention_Cheat_Sheet.html"&gt;IDOR (Insecure Direct Object References)&lt;/a&gt;. If IDs are sensitive, we should encrypt cursor values with a random salt.&lt;/p&gt;
&lt;p&gt;It can become quite complex if you need extra features like sorting on multiple columns, etc.&lt;/p&gt;
&lt;h2 id="advanced-cursor-pagination-techniques"&gt;Advanced Cursor Pagination Techniques&lt;/h2&gt;
&lt;p&gt;When dealing with extremely large datasets, an advanced cursor-based technique can further optimise performance.&lt;/p&gt;
&lt;p&gt;In my experience using the basic cursor-based example on a table with 163 million rows, where only 300K rows met the &lt;code&gt;WHERE&lt;/code&gt; clause criteria, the query timed out even with a &lt;code&gt;LIMIT&lt;/code&gt; of 1000. This occurred because the query had to scan too many rows before finding 1000 that matched the criteria.&lt;/p&gt;
&lt;p&gt;Now, you might wonder why it would need to scan so many rows if you have an index. The index's benefit is that it lets the database quickly locate the starting point. Imagine that the first record is in row 1. Now, the second record is after 1 million rows. To reach the limit of 1000, at least 1 million rows will need to be scanned. Even though there is an index, it can (and probably will) result in a timeout because it requires scanning many non-matching rows to find the ones that match.&lt;/p&gt;
&lt;p&gt;In such scenarios, it's crucial to limit the number of rows scanned during each query execution. This can be achieved by adding a constraint that ensures efficient data retrieval, even if the &lt;code&gt;LIMIT&lt;/code&gt; is not fully met.&lt;/p&gt;
&lt;h3 id="example-2"&gt;Example&lt;/h3&gt;
&lt;p&gt;Here's an updated query:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sql"&gt;SELECT *         
FROM product         
WHERE id &amp;gt; $lastId        
    AND id &amp;lt;= $clampId        
    AND category = 1        
ORDER BY id         
LIMIT $pageSize;        
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;clampId&lt;/code&gt; serves as an upper boundary, calculated as &lt;code&gt;lastId&lt;/code&gt; plus a predefined range, to limit the number of rows scanned per query execution.&lt;/p&gt;
&lt;p&gt;For instance, if &lt;code&gt;lastId&lt;/code&gt; is 1000 and the scan limit is 10,000 rows, set &lt;code&gt;clampId&lt;/code&gt; to 11,000. The &lt;code&gt;LIMIT&lt;/code&gt; remains 1,000, ensuring immediate return if 1,000 matches are found or scanning at most 10,000 rows.&lt;/p&gt;
&lt;p&gt;By clamping the range, we can significantly reduce query execution time, making it feasible to handle large datasets without overwhelming the system.&lt;/p&gt;
&lt;h3 id="using-non-sequential-identifiers"&gt;Using Non-sequential Identifiers&lt;/h3&gt;
&lt;p&gt;While in the examples, the &lt;code&gt;id&lt;/code&gt; is assumed to be numeric and sequential, it doesn't need to be to implement cursor-based pagination. We can, for instance, combine multiple fields, e.g., &lt;code&gt;&amp;lt;last_updated_at&amp;gt;&lt;/code&gt; for sorting and &lt;code&gt;&amp;lt;last_id&amp;gt;&lt;/code&gt; as a UUID to get the last item on the current page.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sql"&gt;SELECT *       
FROM product      
WHERE (last_updated_at &amp;lt; $lastUpdatedAt)      
 OR (last_updated_at = $lastUpdatedAt AND last_id &amp;gt; $lastId)      
ORDER BY last_updated_at DESC, last_id      
LIMIT $pageSize;      
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Choosing the right pagination approach ensures optimal application performance and user satisfaction, regardless of dataset size.&lt;/p&gt;
&lt;p&gt;While offset pagination is simpler to implement, it suffers from significant performance degradation at scale. In contrast, cursor pagination maintains consistent performance regardless of page depth.&lt;/p&gt;
&lt;p&gt;However, offset-based pagination allows us to arbitrarily jump to any page. With cursor pagination, we have to traverse pages sequentially or use more complex techniques.&lt;/p&gt;
&lt;p&gt;The choice between these two approaches ultimately depends on your use case. Choose cursor pagination for high-performance needs with large datasets. Opt for offset pagination when dataset size is manageable, and random page navigation is required.&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>WordXplorer #7: New Video &amp; Food Theme</title>
			<link>https://www.ankursheel.com/blog/wordxplorer-update-7</link>
			<description>WordXplorer is now available for preorder on the App Store with special pricing before its December 1st launch. This updates also features a preview video and plans for an Android release.</description>
			<enclosure url="https://www.ankursheel.com/assets/images/preorder-appstore-badge.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/wordxplorer-update-7</guid>
			<pubDate>Tue, 22 Oct 2024 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;You can see all the related updates &lt;a href="https://www.ankursheel.com/tags/wordxplorer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I hope you’re having an awesome day! Since the last post, we’ve been hard at work, appeasing the Apple gods to ensure our game is ready for the App Store.&lt;/p&gt;
&lt;p&gt;And guess what? I’m thrilled to announce that our game has been approved.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://apps.apple.com/us/app/wordxplorer-guess-the-word/id6504664783" target="\_blank"&gt;&lt;img src="https://www.ankursheel.com/assets/images/preorder-appstore-badge.png" alt="Preorder WordXplorer"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="new-video-alert"&gt;🎥 New Video Alert!&lt;/h2&gt;
&lt;p&gt;I am excited to share a sneak preview of our brand-new video. You can catch this exclusive glimpse on our product page. It’s a taste of the adventure that awaits!&lt;/p&gt;
&lt;div style="position: relative;width: 100%;padding-bottom: 56.25%;margin: 1rem 0;"&gt;
  &lt;iframe src="https://www.youtube.com/embed/bAtj9bAYVS0/0" title="WordXplorer Preview Video" style="position: absolute;width: 100%;height: 100%;left: 0;top: 0;right: 0;" allowfullscreen=""&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="exciting-new-theme"&gt;🎨 Exciting New Theme&lt;/h2&gt;
&lt;p&gt;To make things fun and engaging for kids, we’ve decided to theme the words around “Food Items.” There are a few reasons we have chosen this theme as the first one.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We can easily create 25-30 exciting levels for launch.&lt;/li&gt;
&lt;li&gt;Kids are familiar with food items and having all words around this central theme should make it easy for them to get started.&lt;/li&gt;
&lt;li&gt;Most importantly, we believe this theme will be a hit with children.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="special-preorder-pricing"&gt;💰 Special Preorder Pricing&lt;/h2&gt;
&lt;p&gt;You can preorder the game for just USD 3.99. Apple will use this base price and adjust it for your region.&lt;/p&gt;
&lt;p&gt;Remember, once we launch on December 1st, the price will increase to USD 4.99. So, why wait? Secure your copy now!&lt;/p&gt;
&lt;h2 id="how-to-preorder"&gt;🛒 How to Preorder&lt;/h2&gt;
&lt;p&gt;Pre-ordering is simple and ensures you’re among the first to experience the game:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Visit the &lt;a href="https://apps.apple.com/us/app/wordxplorer-guess-the-word/id6504664783"&gt;game’s product page on the App Store&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click on the “Preorder” button.&lt;/li&gt;
&lt;li&gt;Follow the prompts to complete your preorder. By pre-ordering, you lock in the special price and guarantee immediate access on launch day!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Rest assured, you will only be charged once the game officially launches on December 1st. And if you change your mind(I hope you don’t), you can cancel your preorder anytime before launch without penalty.&lt;/p&gt;
&lt;p&gt;For more details, feel free to check out &lt;a href="https://support.apple.com/en-nz/118414"&gt;Apple’s Preorder documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="google-play-progress"&gt;📱 Google Play Progress&lt;/h2&gt;
&lt;p&gt;Exciting news for our Android fans! I have a working proof of concept for the game on Android devices.&lt;/p&gt;
&lt;p&gt;While bringing the game to Google Play is definitely on our radar, our primary focus is ensuring a smooth and successful launch on the App Store.&lt;/p&gt;
&lt;p&gt;Rest assured, expanding to Android is part of our plans. We appreciate your patience and support as we prioritise the App Store release. Stay tuned for more updates!&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="last-chance-for-playable-build"&gt;🕹️ Last Chance for Playable Build&lt;/h2&gt;
&lt;p&gt;This is your final opportunity to check out the latest update to our &lt;a href="https://golden-pony-d2c3f0.netlify.app/"&gt;Playable Web Build&lt;/a&gt; or TestFlight build. Your feedback would mean the world to us! If you’re eager to have the full experience, just let me know, and I’ll send you a TestFlight invite immediately. 😊&lt;/p&gt;
&lt;h2 id="whats-next"&gt;🚀 What’s Next&lt;/h2&gt;
&lt;p&gt;With a hard deadline in sight, we’re focused on adding those final touches to the game. We’re also building out the concept of theming levels into the gameplay to ensure a smooth experience for launch day. I am also trying to get in the Apple Small Business program to reduce the percentage of commission that they charge.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Know someone who’d love to try the game before its official release? &lt;del&gt;Share this &lt;a href="https://tally.so/r/wverVQ"&gt;form&lt;/a&gt; with
them—they’ll thank you!! ✨&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Update 26th December 2024:&lt;/em&gt;&lt;/strong&gt; You can now download the game.&lt;/p&gt;
&lt;div class="appstore-badges-container"&gt;
  &lt;a href="https://apps.apple.com/in/app/wordxplorer-guess-the-word/id6504664783" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-app-store-badge.png" alt="Get WordXplorer on App Store"&gt;
  &lt;/a&gt;
  &lt;a href="https://play.google.com/store/apps/details?id=com.glhf.wordleforkids" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-play-store-badge.png" alt="Get WordXplorer on Play Store"&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Does your child have a favourite four-letter food they’d love to see in WordXplorer? Let me know, and I’ll do my best to add it to the game!&lt;/p&gt;
&lt;p&gt;Thank you for joining us on this journey. I can’t wait for you to dive into the game and share your thoughts!&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>Fun with (Feature) Flags</title>
			<link>https://www.ankursheel.com/blog/fun-feature-flags</link>
			<description>Let’s explore what feature flags are, how they work, and their pros and cons compared to some traditional approaches</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/fun-feature-flags-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/fun-feature-flags</guid>
			<pubDate>Fri, 06 Sep 2024 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;Feature flags give developers the ability to turn features on or off without deploying new code. This flexibility is key for managing the release of new features while allowing for controlled and incremental deployments.&lt;/p&gt;
&lt;p&gt;I still have conversations with several teams that are using development methods that don’t include feature flags. Some of them want to move to feature flags but are unsure how to start while others have never heard of them or don't think it's worth adopting.&lt;/p&gt;
&lt;p&gt;Let’s explore how feature flags work, and their pros and cons compared to some other approaches.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;: This is loosely based on a presentation I had given at FirstAML.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/fun-feature-flags/fun-with-flags.jpg" alt="Flags"&gt;&lt;/p&gt;
&lt;h2 id="other-approaches"&gt;Other Approaches&lt;/h2&gt;
&lt;p&gt;Before diving into feature flags, let’s look at some &lt;del&gt;traditional&lt;/del&gt; ahem alternative approaches I’ve seen teams use.&lt;/p&gt;
&lt;p&gt;To better understand the differences, let’s consider a scenario where you’re working on a new feature that will allow users to edit the title of their uploaded documents.&lt;/p&gt;
&lt;p&gt;This feature requires changes to the frontend, backend, and database and can be broken down into several tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Update the database schema to store the new title.&lt;/li&gt;
&lt;li&gt;Update the backend API to accept the new title.&lt;/li&gt;
&lt;li&gt;Update the backend to save the new title.&lt;/li&gt;
&lt;li&gt;Add an audit trail for the updates.&lt;/li&gt;
&lt;li&gt;Update the backend to return the new title.&lt;/li&gt;
&lt;li&gt;Update the frontend to display the new title.&lt;/li&gt;
&lt;li&gt;Update the frontend to allow users to edit the title.&lt;/li&gt;
&lt;li&gt;Add validation to the backend to ensure the new title is valid.&lt;/li&gt;
&lt;li&gt;Add validation to the frontend to ensure the new title is valid.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="approach-1-feature-branches"&gt;Approach 1: Feature Branches&lt;/h3&gt;
&lt;p&gt;A long, long time ago, when SVN was a thing (and even much later) most teams used &lt;strong&gt;Feature Branches&lt;/strong&gt; to manage new features. Typically, each feature would be developed on a separate branch, tested, and then merged into the &lt;code&gt;main&lt;/code&gt; branch.&lt;/p&gt;
&lt;p&gt;In our example, you would create a branch for the new title feature, and each task would be developed on this branch. Once all tasks are complete, the branch would be merged into
&lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/fun-feature-flags/branch-hell.jpg" alt="Feature Branch Complexity.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Feature branches were popular because they were straightforward to use and possibly because that was the best we had at that time. They still work well for small-scale projects.&lt;/p&gt;
&lt;p&gt;However, in larger teams, feature branches can create technical debt. Tasks may overlap, and keeping branches in sync becomes more challenging, slowing down the development process.&lt;/p&gt;
&lt;p&gt;Here are some other downsides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Since code in feature branches must be fully completed before merging, it often leads to large, complex pull requests with significant changes.&lt;/li&gt;
&lt;li&gt;Common changes like the same typo being fixed in two different branches can cause conflicts.&lt;/li&gt;
&lt;li&gt;Working on features in separate branches can hinder collaboration.&lt;/li&gt;
&lt;li&gt;Rolling a change back is difficult due to the intertwined nature of multiple features in the &lt;code&gt;main&lt;/code&gt; branch.&lt;/li&gt;
&lt;li&gt;Moving on to a new feature before the previous one is merged can result in forgotten branches and ToDo's.&lt;/li&gt;
&lt;li&gt;As branches are long-lived and diverge over time, refactoring becomes challenging.&lt;/li&gt;
&lt;li&gt;Continuous Integration/Continuous Deployment (CI/CD) becomes difficult due to the fragmented nature of feature branches.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most teams I know start by using feature branches when they are just 1 or 2 developers. But as the team grows, managing multiple branches becomes increasingly complex, leading to merge conflicts and lower productivity.&lt;/p&gt;
&lt;h3 id="alternative-2-git-flow"&gt;Alternative 2: Git Flow&lt;/h3&gt;
&lt;p&gt;An evolution of feature branches is &lt;strong&gt;Git Flow&lt;/strong&gt;, a branching model I’ve also used with success for certain projects.&lt;/p&gt;
&lt;p&gt;Git Flow uses two main branches (&lt;code&gt;main&lt;/code&gt; and &lt;code&gt;develop&lt;/code&gt;). Feature branches are created off &lt;code&gt;develop&lt;/code&gt;, and once a feature is stable, it is merged into &lt;code&gt;develop&lt;/code&gt;. When &lt;code&gt;develop&lt;/code&gt; is stable, it is merged into &lt;code&gt;main&lt;/code&gt;, which is always production-ready. A &lt;code&gt;release&lt;/code&gt; branch is created from &lt;code&gt;main&lt;/code&gt; for each release and &lt;code&gt;hotfix&lt;/code&gt; branches are created to fix production issues.&lt;/p&gt;
&lt;p&gt;In our example, you would create one or more feature branches off &lt;code&gt;develop&lt;/code&gt; for the new title feature. Once the feature is complete, it would be merged into &lt;code&gt;develop&lt;/code&gt;. When &lt;code&gt;develop&lt;/code&gt; is stable, it would be merged into &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/fun-feature-flags/git-flow.jpg" alt="Git Flow"&gt;&lt;/p&gt;
&lt;p&gt;Git Flow offers several advantages compared to Feature Branches.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It ensures the main branch remains stable and production-ready, aiding in scheduled release cycles.&lt;/li&gt;
&lt;li&gt;It supports different versions, useful for desktop and mobile apps requiring hotfixes or patches.&lt;/li&gt;
&lt;li&gt;It works well for Waterfall or Waterfall-Pretending-to-be-Agile methodologies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But it’s not without its downsides.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Merge conflicts can still occur in the &lt;code&gt;develop&lt;/code&gt; branch.&lt;/li&gt;
&lt;li&gt;Multiple features might be coupled together, preventing the release of any feature until all are complete.&lt;/li&gt;
&lt;li&gt;Continuous Deployment (CD) becomes challenging as it requires all features in the &lt;code&gt;develop&lt;/code&gt; branch to be stable before merging into &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my experience, Git Flow is less effective for SaaS and applications where supporting older versions isn’t necessary.&lt;/p&gt;
&lt;h2 id="feature-flags"&gt;Feature Flags&lt;/h2&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/fun-feature-flags/sheldon-fun-with-flags.png" alt="Fun with flags"&gt;&lt;/p&gt;
&lt;p&gt;With feature flags, you can deploy code at any time, keeping features behind a switch that you control. This enables a smoother, more flexible development and release process.&lt;/p&gt;
&lt;p&gt;In its simplest form, a boolean flag determines whether a feature is active or not. This flag can be toggled on or off without redeploying the code.&lt;/p&gt;
&lt;h3 id="pros-of-feature-flags"&gt;Pros of Feature Flags&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Production code closely mirrors the development version, reducing integration issues.&lt;/li&gt;
&lt;li&gt;Allows for smaller, isolated changes to be merged, minimizing merge conflict risks.&lt;/li&gt;
&lt;li&gt;Features can be released in line with marketing or launch timelines.&lt;/li&gt;
&lt;li&gt;Smaller pull requests make bug fixes easier, with more confidence in the changes.&lt;/li&gt;
&lt;li&gt;They allow for A/B testing and canary releases, where a feature is gradually rolled out to a subset of users.&lt;/li&gt;
&lt;li&gt;It acts as a kill switch, allowing you to quickly turn off a feature if it causes issues in production.&lt;/li&gt;
&lt;li&gt;Turning a feature on for users carries low risk since it has already been thoroughly tested in a controlled environment.&lt;/li&gt;
&lt;li&gt;Shipping the features to users is a trivial config change.&lt;/li&gt;
&lt;li&gt;Easy to sunset features&lt;/li&gt;
&lt;li&gt;Frontend and backend teams can work in parallel since the feature is not live until the flag is activated.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="cons-of-feature-flags"&gt;Cons of Feature Flags&lt;/h3&gt;
&lt;p&gt;While feature flags offer many benefits, they come with their own set of challenges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The codebase accumulates immediate technical debt with numerous if-else statements and duplicated code paths.&lt;/li&gt;
&lt;li&gt;You have to test both the flag-on and flag-off paths.&lt;/li&gt;
&lt;li&gt;You have to remember to remove the flag and associated code once the feature is fully deployed.&lt;/li&gt;
&lt;li&gt;Inter-dependencies between flags can lead to complex configurations.&lt;/li&gt;
&lt;li&gt;Feature flags on the client side may reveal in-development features.&lt;/li&gt;
&lt;li&gt;It is difficult to apply flags for specific users for changes available before login.&lt;/li&gt;
&lt;li&gt;Managing feature flags at scale can become complex, particularly when dealing with numerous flags across different environments and user segments. Effective management requires robust tooling and practices to keep configurations organized and manageable. However, tools like LaunchDarkly can streamline this process, making it easy to track and control your flags.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="when-to-use-feature-flags"&gt;When to Use Feature Flags&lt;/h3&gt;
&lt;p&gt;Alright, let's play a little game. I'll list a few scenarios, and you tell me if you should use feature flags or not...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Low risk minor bug fix&lt;/li&gt;
&lt;li&gt;Copy changes&lt;/li&gt;
&lt;li&gt;New Feature&lt;/li&gt;
&lt;li&gt;Adding functionality to an existing feature&lt;/li&gt;
&lt;li&gt;Removing a feature&lt;/li&gt;
&lt;li&gt;Refactor&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This was a trick question.&lt;/p&gt;
&lt;p&gt;Feature flags are your safety net for almost every scenario above.&lt;/p&gt;
&lt;p&gt;The only exception is refactoring — where your automated tests should catch any issue. You are writing tests right?&lt;/p&gt;
&lt;h3 id="feature-flags-in-practice"&gt;Feature Flags in Practice&lt;/h3&gt;
&lt;p&gt;To use feature flags, start with a configuration per environment that defines the flags and their state. This could be a simple JSON file or a more complex system like LaunchDarkly.&lt;/p&gt;
&lt;p&gt;Here’s a basic config example in JSON:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-json"&gt;{
  "FeatureFlags": {
    "feature1": {
      "enabled": true
    },
    "feature2": {
      "enabled": false
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having a JSON configuration file per environment, allows you to define and manage feature flags across different environments. By toggling the &lt;code&gt;enabled&lt;/code&gt; status, you can control feature visibility and rollout without redeploying code.&lt;/p&gt;
&lt;p&gt;Initially, the flag would be off in all environments - dev, QA and prod. This allows you to develop the feature in isolation.&lt;/p&gt;
&lt;p&gt;The code has &lt;code&gt;if-else&lt;/code&gt; statements to check if the feature is enabled or not.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;// Check if the feature flag is enabled before executing new logic
if(_featureFlagProvider.IsFeatureEnabled(AvailableFlags.Feature1))
{
    // new logic
}
else
{
    // old logic
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Note: Developing while the feature is on the dev environment can impact other devs.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once the feature is ready, you can turn the flag on in the dev and test environment for QA testing without exposing it to end users.&lt;/p&gt;
&lt;p&gt;After thorough testing, you can activate the feature flag in production. The feature is now live, but since it was already tested in a controlled environment, the risk is minimal.&lt;/p&gt;
&lt;p&gt;Finally, after the feature has been successfully deployed, and you’re confident it’s stable, it’s important to remove the feature flag and any associated code to prevent technical debt.&lt;/p&gt;
&lt;p&gt;In our example, you would create a feature flag for the new title feature. Each task would be developed behind a feature flag in isolated branches. As each task is completed, it would be merged into the &lt;code&gt;main&lt;/code&gt; branch. Once all tasks are complete, the feature flag would be turned on in the test environment for QA testing. After thorough testing, the feature flag would be activated in production, making the feature live.&lt;/p&gt;
&lt;h3 id="best-practices-with-feature-flags"&gt;Best Practices with Feature Flags&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;While embracing duplication might seem counterintuitive, it’s crucial for managing feature flags effectively. This is not the time to worry about keeping your code DRY. Duplication makes it easier to remove flags later.&lt;/li&gt;
&lt;li&gt;Optimize for removal. Code reviews of feature flag removal should be trivial and the reviewer should be just seeing deleted code.&lt;/li&gt;
&lt;li&gt;Define flags with enums or other types rather than strings to simplify management.&lt;/li&gt;
&lt;li&gt;Set up a process to regularly audit and remove outdated flags.&lt;/li&gt;
&lt;li&gt;Maintain a shared configuration for flags affecting both backend (BE) and frontend (FE) teams.&lt;/li&gt;
&lt;li&gt;Allow turning flags on/off using a FE widget tied to a user.&lt;/li&gt;
&lt;li&gt;Consider creating tools to manage feature flags effectively. Automation can help with flag updates and removal.
&lt;ul&gt;
&lt;li&gt;A widget that allows a developer/QA to toggle flags on/off just for themselves in dev/test environments is immensely useful.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;At FirstAML, I developed an open-source &lt;a href="https://github.com/AnkurSheel/FeatureFlagHelper"&gt;helper app that simplified updating feature flag files from the console&lt;/a&gt;.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Abstract the feature flag logic from the rest of the codebase to simplify future changes&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="removal-strategies"&gt;Removal Strategies&lt;/h3&gt;
&lt;p&gt;Old feature flags can clutter your codebase and create headaches down the line. By implementing strategic removal practices, you can keep your code clean and efficient.&lt;/p&gt;
&lt;p&gt;Here are a few strategies to consider:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add a removal task when you introduce a feature flag.&lt;/li&gt;
&lt;li&gt;Add expiration dates to feature flags that either fail a test once expired or alert the team without failing.&lt;/li&gt;
&lt;li&gt;Limit the number of active feature flags in the system so that before adding a new one you have to clean up an older one.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion-are-feature-flags-right-for-you"&gt;Conclusion: Are Feature Flags Right for You?&lt;/h2&gt;
&lt;p&gt;Feature flags are a powerful tool that should be present in every modern teams toolkit. They offer flexibility, reduce risk, and allow for a more controlled release process. Despite their challenges, they provide significant benefits that often outweigh the drawbacks.&lt;/p&gt;
&lt;p&gt;Feature flags can be particularly advantageous for larger teams or projects with multiple stages of development. For smaller teams or projects, they help manage risk and allow for more flexible deployment strategies, reducing the chances of introducing bugs into production.&lt;/p&gt;
&lt;p&gt;When I joined FirstAML, (even though we were just 2 developers at the time) one of the first things I built was a basic feature flag system. This allowed us to test features in isolation, minimizing risks and enhancing our development process by enabling more controlled releases. They’re not just for big teams — they’re for anyone who values agility and controlled risk.&lt;/p&gt;
&lt;p&gt;If you’re not already using feature flags, I highly recommend exploring them. They can be a game-changer for your development process, enabling you to release features with confidence and control.&lt;/p&gt;
&lt;p&gt;For further reading, check out &lt;a href="https://martinfowler.com/articles/feature-toggles.html"&gt;Martin Fowler’s article on feature toggles&lt;/a&gt;.&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>WordXplorer #6: New Look, Major Fixes &amp; App Store News</title>
			<link>https://www.ankursheel.com/blog/wordxplorer-update-6</link>
			<description>New name &amp; icon, major bug fixes, and upcoming App Store release. Test the latest build and give your feedback!</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/wordxplorer-update-6-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/wordxplorer-update-6</guid>
			<pubDate>Mon, 02 Sep 2024 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;You can see all the related updates &lt;a href="https://www.ankursheel.com/tags/wordxplorer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Since we last spoke, it’s been full steam ahead with bug fixes and getting the game ready for the App Store! We’re thrilled to be just around the corner from giving your kids a fun and educational experience they’ll love!"&lt;/p&gt;
&lt;h2 id="new-name-and-icon"&gt;New Name and Icon&lt;/h2&gt;
&lt;p&gt;The name of the game has been updated from wordwhiz to WordXplorer.&lt;/p&gt;
&lt;p&gt;We’ve replaced the generic grey boxes with a vibrant, colorful icon that better reflects the fun and educational nature of WordXplorer.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-6/app_icon.png" alt="App_Icon"&gt;&lt;/p&gt;
&lt;h2 id="bugfixes"&gt;Bugfixes&lt;/h2&gt;
&lt;p&gt;Kids are great testers; they always manage to do things you’d never expect. So, what did they discover this time?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Previously, pressing keyboard keys while a popup was displayed could cause issues, as you couldn’t see the word you were entering. We’ve now disabled the keyboard when a popup is shown to prevent this.&lt;/li&gt;
&lt;li&gt;You could also press keyboard keys after completing a level, but before starting the next. This led to unintended effects, like having a prefilled row when the new level started. The keyboard is now disabled when the level is complete.&lt;/li&gt;
&lt;li&gt;That was not the only problem when a level ended. Did you know, you could press the Next Level button before the popup finished? Unsurprisingly, this caused issues. Now, the next level button only appears after the popup has fully disappeared. It also lets the kids enjoy the fireworks for a tad more time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also fixed feedback about the Next Level button not being centered on the iPad.&lt;/p&gt;
&lt;p&gt;These fixes ensure that your gameplay is smooth and frustration-free, with no more accidental key presses or misaligned buttons on the iPad, making your experience more enjoyable.&lt;/p&gt;
&lt;h2 id="infrastructural-changes"&gt;Infrastructural changes&lt;/h2&gt;
&lt;p&gt;To generate TestFlight and web builds, I have been using a combination of GitHub Actions, GameCI, and Fastlane.&lt;/p&gt;
&lt;p&gt;I’m excited to share that we’re now able to create builds ready for the App Store release. We’re making solid progress and are committed to delivering the final version of the game soon.&lt;/p&gt;
&lt;p&gt;Fastlane can update the App Store metadata, but I haven’t managed to get it working yet. It’s on my list to figure out. For now, we are manually updating the metadata in the portal. This isn’t ideal, but it is a minor issue that won’t affect our overall progress.&lt;/p&gt;
&lt;h2 id="updating-metadata-for-the-app-store"&gt;Updating Metadata for the App Store&lt;/h2&gt;
&lt;p&gt;To get the game ready for the App Store, a lot of metadata needs to be added. This includes the app name, subtitle, and a description.&lt;/p&gt;
&lt;p&gt;We also need to upload at least three screenshots for various device form factors.&lt;/p&gt;
&lt;p&gt;Here's a sneak preview&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-6/screenshot_1.png" alt="Screenshot 1"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-6/screenshot_2.png" alt="Screenshot 2"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-6/screenshot_3.png" alt="Screenshot 3"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;These may end up in the final version, but we are not sure yet.&lt;/p&gt;
&lt;h2 id="submitting-for-review"&gt;Submitting for review&lt;/h2&gt;
&lt;p&gt;Once we updated all the metadata, we decided to submit the game for an App Store review. The intention was not to get the current version released but to ensure we can go through the approval process and be ready when the final version is prepared.&lt;/p&gt;
&lt;p&gt;We’ve encountered some challenges with Apple's approval process, but we're addressing them head-on.&lt;/p&gt;
&lt;p&gt;The 1st hurdle was related to analytics and data capturing. This has been easy enough to address as we are not capturing any PII, and the data that we capture for analytics is aggregated so we don't know anything about any specific individual.&lt;/p&gt;
&lt;p&gt;The next challenge we’re facing is Apple’s concern with our use of "Wordle" in the metadata and screenshots. Apple has guidelines to prevent copycat games and apparently using the Wordle goes against it. This was unexpected as we could see other games in the app store using Wordle. The plan is to resolve this by updating the metadata to remove any references to "Wordle" and providing a small blurb of why it's not just a copy.&lt;/p&gt;
&lt;p&gt;Hopefully, with the changes we’re making, Apple will see that our game is unique and far from a copycat.&lt;/p&gt;
&lt;h2 id="whats-next"&gt;What's Next&lt;/h2&gt;
&lt;p&gt;Aside from getting a build that adheres to Apple’s guidelines and squashing bugs, we’re working on determining the price point and considering the option of preorders.&lt;/p&gt;
&lt;p&gt;Based on survey feedback, we’re leaning towards a price point of NZD 5.99 / USD 2.99 / INR 299 for approximately 20-25 levels.&lt;/p&gt;
&lt;p&gt;We’re also contemplating theming the words in the game. Two themes we’re considering are food and animals. If we proceed with this, we plan to release one theme now and the other later. Do you have a preference for which theme we should choose first?&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="playable-build"&gt;Playable Build&lt;/h2&gt;
&lt;p&gt;We’re excited for you to test out the &lt;a href="https://golden-pony-d2c3f0.netlify.app/"&gt;Playable Web Build&lt;/a&gt;. Share your feedback, and if you want the full experience, just ask for a TestFlight invite—I’ll send it over right away!. 😊&lt;/p&gt;
&lt;p&gt;Know someone who’d love to try the game before its official release? &lt;del&gt;Share this &lt;a href="https://tally.so/r/wverVQ"&gt;form&lt;/a&gt; with
them—they’ll thank you!! ✨&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Update 26th December 2024:&lt;/em&gt;&lt;/strong&gt; You can now download the game.&lt;/p&gt;
&lt;div class="appstore-badges-container"&gt;
  &lt;a href="https://apps.apple.com/in/app/wordxplorer-guess-the-word/id6504664783" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-app-store-badge.png" alt="Get WordXplorer on App Store"&gt;
  &lt;/a&gt;
  &lt;a href="https://play.google.com/store/apps/details?id=com.glhf.wordleforkids" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-play-store-badge.png" alt="Get WordXplorer on Play Store"&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Does your child have a favourite word they’d love to see in WordXplorer? Let me know, and I’ll do my best to add it to the game!&lt;/p&gt;
&lt;p&gt;Thank you for being a part of this journey with me! I’m eager to hear your thoughts and feedback. Stay tuned for more updates!&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>WordXplorer #5: UI Refresh</title>
			<link>https://www.ankursheel.com/blog/wordxplorer-update-5</link>
			<description>WordXplorer Update 5 tweaks the UI to make for a better experience</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/wordxplorer-update-5-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/wordxplorer-update-5</guid>
			<pubDate>Mon, 19 Aug 2024 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;You can see all the related updates &lt;a href="https://www.ankursheel.com/tags/wordxplorer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here's whats new since the last update&lt;/p&gt;
&lt;h2 id="updated-game-screen"&gt;Updated game screen&lt;/h2&gt;
&lt;p&gt;The main game screen now has more negative space, giving it a cleaner look. However, this change means the keyboard buttons are smaller. Give it a try and let me know how it feels!&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center;"&gt;Before&lt;/th&gt;
&lt;th style="text-align: center;"&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-5/old_game_screen.jpg" alt="Old Game Screen"&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-5/new_game_screen.jpg" alt="New Game Screen"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="improved-popups"&gt;Improved Popups&lt;/h2&gt;
&lt;p&gt;Popups are no longer boring grey rectangles. They now match the color scheme of the rest of the game, making everything look more cohesive.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-5/popups.jpg" alt="Popups"&gt;&lt;/p&gt;
&lt;h2 id="enhanced-fireworks"&gt;Enhanced Fireworks&lt;/h2&gt;
&lt;p&gt;Last time, I added support for fireworks, but they were a bit hard to see. Now, the screen dims after you complete a level, so the fireworks really stand out. With explosive sound effects, it creates a much better experience!&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center;"&gt;Before&lt;/th&gt;
&lt;th style="text-align: center;"&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-5/old_fireworks.gif" alt="Old Fireworks"&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-5/new_fireworks.gif" alt="New Fireworks"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="privacy-policy"&gt;Privacy Policy&lt;/h2&gt;
&lt;p&gt;To prepare the game for the App Store, I needed a privacy policy. Luckily, I’m not capturing any personal information, so it was easy to create one using ChatGPT. If you’re interested, you can check it out &lt;a href="https://www.ankursheel.com/personal-projects/wordxplorer/privacy-policy-wordxplorer" target="\_blank"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="playable-build"&gt;Playable Build&lt;/h2&gt;
&lt;p&gt;&lt;del&gt;Test it out by going to &lt;a href="https://golden-pony-d2c3f0.netlify.app/"&gt;Playable Web Build&lt;/a&gt; and let me know what you think
about the game so far. The TestFlight app is still the best way to play, so let me know if you want an invitation. 😊&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Update 26th December 2024:&lt;/em&gt;&lt;/strong&gt; You can now download the game.&lt;/p&gt;
&lt;div class="appstore-badges-container"&gt;
  &lt;a href="https://apps.apple.com/in/app/wordxplorer-guess-the-word/id6504664783" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-app-store-badge.png" alt="Get WordXplorer on App Store"&gt;
  &lt;/a&gt;
  &lt;a href="https://play.google.com/store/apps/details?id=com.glhf.wordleforkids" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-play-store-badge.png" alt="Get WordXplorer on Play Store"&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Does your child have a favourite word they’d love to see in the game? Let me know, and I might add it!&lt;/p&gt;
&lt;p&gt;Thank you all for your support and patience. Stay tuned for more updates!&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>WordXplorer #4: Levels, Fireworks &amp; Fresh New Look</title>
			<link>https://www.ankursheel.com/blog/wordxplorer-update-4</link>
			<description>WordXplorer Update 4 adds deterministic levels and fireworks</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/wordxplorer-update-4-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/wordxplorer-update-4</guid>
			<pubDate>Mon, 05 Aug 2024 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;You can see all the related updates &lt;a href="https://www.ankursheel.com/tags/wordxplorer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It's been a while since the last update, and I wanted to tell you what's been happening. I wanted to get this game out by now, but life events got in the way.&lt;/p&gt;
&lt;h2 id="what-happened"&gt;What happened&lt;/h2&gt;
&lt;p&gt;The partnership that I had for the first game ended. This meant I had to setup new accounts for various third-party services and redo some of the infrastructural work, which took some time.&lt;/p&gt;
&lt;p&gt;After your feedback and some live playtests, it was clear that the game needed something more. Without someone else to help, I was getting overwhelmed with my day job and all the things that needed to be done for wordxplorer. Thankfully, my cousin Manjari stepped in to help with the creative side of things.&lt;/p&gt;
&lt;h2 id="whats-new"&gt;What's New&lt;/h2&gt;
&lt;h3 id="color-matters"&gt;Color Matters&lt;/h3&gt;
&lt;p&gt;Let's face it: The original colours weren't very appealing. The first thing Manjari changed after joining was updating the colours. But don't take my word for it, see for yourself:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: center;"&gt;Before&lt;/th&gt;
&lt;th style="text-align: center;"&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-4/old_instructions.jpg" alt="Old Instructions Screen"&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-4/new_instructions.jpg" alt="New Instructions Screen"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-4/old_game_screen.jpg" alt="Old Game Screen"&gt;&lt;/td&gt;
&lt;td style="text-align: center;"&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-4/new_game_screen.jpg" alt="New Game Screen"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="fireworks"&gt;Fireworks&lt;/h3&gt;
&lt;p&gt;Previously, when you found the right word, there was no celebration - just a plain popup that quickly disappeared. Now, there are fireworks and explosions to celebrate your victory.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-4/fireworks.gif" alt="Fireworks"&gt;&lt;/p&gt;
&lt;h3 id="deterministic-levels"&gt;Deterministic Levels&lt;/h3&gt;
&lt;p&gt;The random word selection felt like playing the lottery. Now, there are levels and they are locked! After you complete one, the next one is unlocked, providing a sense of progress. Plus, your progress is saved, so you don’t have to start from Level 1 every time.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-4/level_screen.jpg" alt="Level Selection Screen"&gt;&lt;/p&gt;
&lt;h3 id="web-build"&gt;Web Build&lt;/h3&gt;
&lt;p&gt;For those who didn’t want to install TestFlight or were not on an Apple device, you can now try the game on your browser. The TestFlight app is still the best way to play, so let me know if you want an invite. 😊&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;del&gt;Test it out by going to &lt;a href="https://golden-pony-d2c3f0.netlify.app/"&gt;Playable Web Build&lt;/a&gt; and let me know what you think
about the game so far.&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Update 26th December 2024:&lt;/em&gt;&lt;/strong&gt; You can now download the game.&lt;/p&gt;
&lt;div class="appstore-badges-container"&gt;
  &lt;a href="https://apps.apple.com/in/app/wordxplorer-guess-the-word/id6504664783" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-app-store-badge.png" alt="Get WordXplorer on App Store"&gt;
  &lt;/a&gt;
  &lt;a href="https://play.google.com/store/apps/details?id=com.glhf.wordleforkids" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-play-store-badge.png" alt="Get WordXplorer on Play Store"&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Does your child have a favourite word they’d love to see in the game? Let me know, and I might add it!&lt;/p&gt;
&lt;p&gt;Thank you all for your support and patience. Stay tuned for more updates!&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>Verifying Method Calls within a class using Mockito Spies</title>
			<link>https://www.ankursheel.com/blog/verifying-method-calls-class-mockito-spies</link>
			<description>How to remove the duplication of test scenarios when one method calls another within the same class</description>
			<guid>https://www.ankursheel.com/blog/verifying-method-calls-class-mockito-spies</guid>
			<pubDate>Mon, 05 Aug 2024 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;in order to get confidence, when one method calls another within the same class with just 1 or more additional parameters, we could write the same test for both the methods. This would lead to a lot of duplicated tests and a cluttered test suite.&lt;/p&gt;
&lt;p&gt;However, Mockito spies can help us in this scenario.&lt;/p&gt;
&lt;h2 id="scenario"&gt;Scenario&lt;/h2&gt;
&lt;p&gt;You want to write tests for a class that contains two public methods, one of which is essentially overloading the other and calling it without adding any additional logic.&lt;/p&gt;
&lt;p&gt;Here's a simplified example to illustrate this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-java"&gt;public class Service {
    public int getTotalPrice(int quantity) {
        // some other code like error checking, etc
        return 5 * quantity;
        
    }

    public int getTotalPrice() {
        return getTotalPrice(1);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, the &lt;code&gt;getTotalPrice()&lt;/code&gt; method without parameters calls the overloaded &lt;code&gt;getTotalPrice(int quantity)&lt;/code&gt; method, supplying a default value.&lt;/p&gt;
&lt;h2 id="enter-the-world-of-spies"&gt;Enter the World of Spies&lt;/h2&gt;
&lt;p&gt;Here's where Mockito spies come into the picture.&lt;/p&gt;
&lt;p&gt;A spy acts as a wrapper around a real object, allowing us to override specific methods with mock behaviour while leaving others intact. You can use this functionality to verify the invocation of an actual method on an object.&lt;/p&gt;
&lt;p&gt;Let's see how you can simplify your tests by using Mockito spies&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-java"&gt;public class MyTests {
    &amp;#64;Test
    public void test() {
        Service spy = Mockito.spy(new Service());
        spy.getTotalPrice();
        verify(spy).getTotalPrice(1);
    }

    // more tests that test `getTotalPrice(int quantity)`
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let's break this down:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Service spy = Mockito.spy(new Service())&lt;/code&gt;:  Create a spy object for &lt;code&gt;Service&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;spy.getTotalPrice()&lt;/code&gt;: Invoke the &lt;code&gt;getTotalPrice&lt;/code&gt; method on the spy object.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;verify(spy).getTotalPrice(1)&lt;/code&gt;: Verify that the overloaded method is invoked on the spy object.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If the overloaded method is not called, then the test would fail, alerting us to a potential issue.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Testing every possible combination of method calls, not only consumes valuable time but also clutters your test suite with redundant tests.&lt;/p&gt;
&lt;p&gt;Mockito spies offer a solution to this problem, allowing you to verify method interactions directly, thus focusing on the behavior rather than the implementation.&lt;/p&gt;
&lt;p&gt;However, it's essential to use Mockito spies judiciously. Spies should primarily be used when you're testing a class's external behavior and its interactions with other classes or methods within itself. Overusing spies can lead to tests that are overly focused on the internal workings of a class, potentially making your tests brittle and less focused on the actual outcomes.&lt;/p&gt;
&lt;p&gt;Happy testing, and may your code always perform as intended, both now and in the future.&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>WordXplorer #3: 100 Words, Help Button &amp; Roadmap</title>
			<link>https://www.ankursheel.com/blog/wordxplorer-update-3</link>
			<description>WordXplorer Update 3 adds a help button and 100 words</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/wordxplorer-update-3-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/wordxplorer-update-3</guid>
			<pubDate>Sat, 03 Feb 2024 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;You can see all the related updates &lt;a href="https://www.ankursheel.com/tags/wordxplorer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Those of you who downloaded the 1st early access version might have noticed an update in the test flight app over the holidays 🎉&lt;/p&gt;
&lt;h2 id="more-words-more-fun"&gt;🚀 More Words, More Fun&lt;/h2&gt;
&lt;p&gt;I am thrilled to announce that the game now boasts a whopping 100 words! 📬&lt;/p&gt;
&lt;h2 id="introducing-the-help-button"&gt;📜 Introducing the Help Button&lt;/h2&gt;
&lt;p&gt;Say goodbye to confusion! Explore the newly added Help Button right on the game screen. No need to restart the app — clarify the colour's meanings and game rules instantly&lt;/p&gt;
&lt;div style="position: relative;width: 100%;padding-bottom: 56.25%;margin: 1rem 0;"&gt;
  &lt;iframe src="https://www.youtube.com/embed/X71OQlezrpE" title="wordxplorer Help Button" style="position: absolute;width: 100%;height: 100%;left: 0;top: 0;right: 0;" allowfullscreen=""&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="public-roadmap-unveiled"&gt;📬 Public Roadmap Unveiled&lt;/h2&gt;
&lt;p&gt;Your voice matters! Check out the new &lt;a href="https://changemap.co/transient-toys/wordxplorer/"&gt;public roadmap&lt;/a&gt;, your hub for suggesting and voting on new features.&lt;/p&gt;
&lt;h2 id="whats-next"&gt;🔮 What's Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;This marks the final free version. We will soon be on the app store as a paid game.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Update 26th December 2024:&lt;/em&gt;&lt;/strong&gt; You can now download the game.&lt;/p&gt;
&lt;div class="appstore-badges-container"&gt;
  &lt;a href="https://apps.apple.com/in/app/wordxplorer-guess-the-word/id6504664783" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-app-store-badge.png" alt="Get WordXplorer on App Store"&gt;
  &lt;/a&gt;
  &lt;a href="https://play.google.com/store/apps/details?id=com.glhf.wordleforkids" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-play-store-badge.png" alt="Get WordXplorer on Play Store"&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Does your child have a favorite word they would like to see in the game? Let me know&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>Level Up Your Pull Requests: The Value of Individual Commits</title>
			<link>https://www.ankursheel.com/blog/level-up-your-pull-requests-value-individual-commits</link>
			<description>Uncover the secrets to effective pull requests. From clear histories to efficient reviews, find out why this is a must for every developer.</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/level-up-your-pull-requests-value-individual-commits-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/level-up-your-pull-requests-value-individual-commits</guid>
			<pubDate>Mon, 27 Nov 2023 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;&lt;em&gt;This is an edited version of an article I originally wrote for the internal blog at Atlassian.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;As a Pull Request(PR) reviewer, my main goal is to be as confident as possible about the outcomes once the PR gets merged. To accomplish this, I want to be able to answer 3 questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Do these changes fulfil the requirements?&lt;/li&gt;
&lt;li&gt;Do these changes improve the current state?&lt;/li&gt;
&lt;li&gt;Could these changes potentially lead to an incident?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Achieving a high level of confidence often proves challenging when dealing with a PR that consists of a single commit with a large diff.&lt;/p&gt;
&lt;p&gt;If you've ever received such a PR, you've likely stared at it, wondering where to begin. This confusion is often followed by your decision to set it aside for later, only to be reminded by the author again.&lt;/p&gt;
&lt;img src="https://media0.giphy.com/media/bGgsc5mWoryfgKBx1u/giphy.gif" width="480" height="480"&gt;
&lt;p&gt;What if I told you that this issue could be resolved with a minor adjustment in the way we create a PR?&lt;/p&gt;
&lt;p&gt;Split the commit into &lt;strong&gt;small&lt;/strong&gt; &lt;strong&gt;individual&lt;/strong&gt; commits that make &lt;strong&gt;logical sense&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The key is to ensure that each commit makes sense on its own and represents a single logical change.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="why-should-you-opt-for-multiple-commits-instead-of-a-single-large-commit"&gt;Why should you opt for multiple commits instead of a single large commit?&lt;/h2&gt;
&lt;p&gt;Some might argue that they review all PRs as one comprehensive diff; therefore, spending time creating smaller commits is a waste of time.&lt;/p&gt;
&lt;p&gt;Leaving apart the fact that having smaller commits does not preclude reviewing a PR as a single diff, breaking down even a small PR into multiple, well-structured commits is still beneficial.&lt;/p&gt;
&lt;h3 id="clear-and-understandable-history"&gt;Clear and Understandable History&lt;/h3&gt;
&lt;p&gt;Multiple small commits create a clear and understandable history.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Just as we aim to follow the single responsibility principle in programming, we should also apply it to our commits.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each commit should represent a single logical change. This makes it easier for any team member to understand the thought process and the steps taken to arrive at the final code.&lt;/p&gt;
&lt;p&gt;It's similar to reading a well-structured book versus a convoluted, rambling essay.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;See “What to Split into its own commit” below.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="improve-debugging-and-trouble-shooting-efficiency"&gt;Improve Debugging and Trouble-shooting Efficiency&lt;/h3&gt;
&lt;p&gt;Small commits come to the rescue when bugs creep into the system.&lt;/p&gt;
&lt;p&gt;With large commits, finding the issue is like searching for a needle in a haystack. However, with small commits, since each commit represents a single logical change, it's much easier to pinpoint the offending code.&lt;/p&gt;
&lt;p&gt;Small commits also work well with tools like &lt;code&gt;git-bisect&lt;/code&gt;, making the debugging process more efficient and less time-consuming.&lt;/p&gt;
&lt;h3 id="increase-code-review-efficiency"&gt;Increase Code Review Efficiency&lt;/h3&gt;
&lt;p&gt;Multiple commits make code review more manageable and effective.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/level-up-your-pull-requests-value-individual-commits/review-twitter.jpg" alt="Twitter screenshot"&gt;&lt;/p&gt;
&lt;p&gt;Reviewers can focus on a single small change at a time, ensuring a more thorough review and reducing the likelihood of overlooking potential issues. It also eases the cognitive load on the reviewer, as they don't have to grasp many changes at once, enabling them to provide more insightful feedback.&lt;/p&gt;
&lt;h3 id="faster-reviews"&gt;Faster Reviews&lt;/h3&gt;
&lt;p&gt;Well-structured commits provide reviewers with natural stopping points.&lt;/p&gt;
&lt;p&gt;If it's a large PR, the reviewer will have to block a chunk of time to review it. But, with individual commits, they might be able to look at the PR in shorter blocks, leading to a faster turnaround time.&lt;/p&gt;
&lt;h3 id="promote-work-transparency"&gt;Promote Work Transparency&lt;/h3&gt;
&lt;p&gt;Multiple commits offer a transparent view of the work progress. Each commit denotes a step forward, indicating productivity and makes it easy to get preliminary reviews on WIPs.&lt;/p&gt;
&lt;p&gt;This ability to get feedback early means that you spend less time going in the wrong direction for too long and avoid expensive rewrites.&lt;/p&gt;
&lt;h3 id="minimises-risk"&gt;Minimises Risk&lt;/h3&gt;
&lt;p&gt;Multiple commits help minimise the risk associated with losing work.&lt;/p&gt;
&lt;p&gt;You always have a saved version to revert to if something goes awry. This is particularly helpful when introducing new features or making significant changes.&lt;/p&gt;
&lt;h3 id="enable-pr-splitting"&gt;Enable PR Splitting&lt;/h3&gt;
&lt;p&gt;Having individual (logical unit) commits will naturally contribute to the ability to split PRs.&lt;/p&gt;
&lt;h3 id="reduce-annotation-needs"&gt;Reduce Annotation Needs&lt;/h3&gt;
&lt;p&gt;Smaller, well-structured commits also diminish the necessity for annotating a PR with comments to help reviewers understand it better.&lt;/p&gt;
&lt;p&gt;Once you have commits that are logical units, it becomes easier to write commit messages that are clear and specific. This allows the reviewer to understand the progression of the changes and sometimes can offer clarity as to why certain changes in the PR were made.&lt;/p&gt;
&lt;h2 id="example"&gt;Example&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; I have blurred out the images since the code and the commit messages itself are not important.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;First&lt;/strong&gt;, Which is more straightforward to understand - A single commit message saying "&lt;em&gt;&lt;strong&gt;fixed XYZ errors"&lt;/strong&gt;&lt;/em&gt; or this commit history?&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/level-up-your-pull-requests-value-individual-commits/commit-history.png" alt="commit history"&gt;&lt;/p&gt;
&lt;p&gt;Unsurprisingly, I prefer the split commit history.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Next&lt;/strong&gt;, compare and see which diff is simpler to review.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note:&lt;/strong&gt; Its the same block of code seen as combined diff view vs commit view.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/level-up-your-pull-requests-value-individual-commits/all-changes-1-commit.png" alt="all changes in 1 commit"&gt;
vs
&lt;img src="https://www.ankursheel.com/assets/images/posts/level-up-your-pull-requests-value-individual-commits/separate-duplication-and-code-changes.png" alt="separate duplication and code changes"&gt;&lt;/p&gt;
&lt;p&gt;Personally, even with the code blurred, I can sense that the 2nd diff is going to be easy to reason about.&lt;/p&gt;
&lt;p&gt;It's also easy to see that although the PR might have a large diff, the actual change is relatively small.&lt;/p&gt;
&lt;h2 id="what-to-split-into-its-own-commit"&gt;What to Split into its own commit&lt;/h2&gt;
&lt;p&gt;Hopefully, by now, you are convinced that individual commits are beneficial.&lt;/p&gt;
&lt;p&gt;But you might be wondering how to split a single giant commit into smaller ones.&lt;/p&gt;
&lt;p&gt;Many types of changes should be split into separate commits. Dare I say that some of them should be their own PR?&lt;/p&gt;
&lt;p&gt;In general, changes belong to two different types of classes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Refactoring&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;These changes are very low risk especially since most IDE’s come with automated refactoring tools.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Behavioural&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;These changes require more careful reviews.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key to breaking up a single commit into smaller commits is identifying the parts needed to deliver a ticket. Some of the more common ones include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Refactoring&lt;/li&gt;
&lt;li&gt;Reformatting&lt;/li&gt;
&lt;li&gt;Deleting unused code&lt;/li&gt;
&lt;li&gt;Test improvements&lt;/li&gt;
&lt;li&gt;Introduction of feature flags&lt;/li&gt;
&lt;li&gt;Functional changes&lt;/li&gt;
&lt;li&gt;Adding Observability&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let's focus on the "&lt;em&gt;Introduction of Feature Flags&lt;/em&gt;" as an example.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;First make the change easy, then make the easy change&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;Kent Beck&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;When working on a ticket, the first step usually involves duplicating existing code and placing it behind a feature flag. This duplication should be its own commit, allowing the reviewer to focus on what has changed in the subsequent commits.&lt;/p&gt;
&lt;p&gt;Remember, you can always squash/reorder commits using interactive rebase (&lt;code&gt;git rebase -i&lt;/code&gt;) or cherry pick
(&lt;code&gt;git cherry-pick&lt;/code&gt;) to make a cohesive story &lt;strong&gt;before&lt;/strong&gt; putting up your changes for review.&lt;/p&gt;
&lt;h2 id="questions"&gt;Questions&lt;/h2&gt;
&lt;h3 id="q-shouldnt-the-refactorings-be-their-own-pr"&gt;Q: Shouldn't the refactorings be their own PR?&lt;/h3&gt;
&lt;p&gt;Ideally, Yes. But, it might not be possible if you work on a legacy monolith with a considerable build time. It becomes essential to balance complexity and speed.&lt;/p&gt;
&lt;p&gt;In this case, combining the refactoring commits into the PR made more sense. If the refactorings were more complex or had a lot of changes, it would be better to split them into their own PR.&lt;/p&gt;
&lt;h3 id="q-is-fix-typo-in-variable-name-too-granular"&gt;Q: Is &lt;code&gt;fix typo in variable name&lt;/code&gt; too granular?&lt;/h3&gt;
&lt;p&gt;In the above screenshot, some might argue that the "&lt;em&gt;fix typo in variable name&lt;/em&gt;" commit should be grouped into another commit as it is too granular.&lt;/p&gt;
&lt;p&gt;However, having it as a separate commit is valuable as it is a refactoring rather than a functional change. It allows the reviewer to quickly identify this as just a typo fix.&lt;/p&gt;
&lt;p&gt;If it was in response to a PR review comment, having it as its own commit makes it easier for the reviewer to check that their comment has been addressed.&lt;/p&gt;
&lt;h3 id="q-what-can-you-understand-from-fix-typo-in-variable-name-or-rename-variable-and-add-some-comments"&gt;Q: What can you understand from “fix typo in variable name” or “rename variable and add some comments”?&lt;/h3&gt;
&lt;p&gt;Both these commits signal to the reviewer that these are not behavioural changes.&lt;/p&gt;
&lt;p&gt;This does not mean that the reviewer should not review these commits, but it lets the reviewer know that it should not take too much cognitive load to review.&lt;/p&gt;
&lt;h2 id="shouldnt-we-have-smaller-prs-not-smaller-commits"&gt;Shouldn't we have smaller PR's not smaller commits?&lt;/h2&gt;
&lt;p&gt;Yes, it would be better to have smaller PRs.&lt;/p&gt;
&lt;p&gt;But, if your team is used to reviewing everything as 1 giant diff, it can be hard to get approval if you split a PR into smaller PRs. It can be hard for people to accept that a lot of those PRs on their own probably wont provide value but also won’t break things due to being disabled through feature flags or for other reasons.&lt;/p&gt;
&lt;p&gt;Breaking a PR with one large commit into smaller individual commits that make logical sense provides a nice stepping stone to be able to split into smaller PR's. It is an relatively easier way to build that muscle.&lt;/p&gt;
&lt;h3 id="q-isnt-the-pr-the-smallest-unit-to-understand-why-a-change-is-being-made-so-individual-commits-are-useless"&gt;Q: Isn't the PR the smallest unit to understand why a change is being made, so individual commits are useless?&lt;/h3&gt;
&lt;p&gt;In an ideal world, yes. But, it's easy to fall into the trap of making multiple changes in the same PR because it takes so much time to deploy a PR to production. Having individual commits gives us a nice balance between complexity and speed.&lt;/p&gt;
&lt;p&gt;Taking the analogy of an article, it's like saying we don't need to have sub-headings because the essay must be consumed as one unit. The subheadings/commits make it easier to consume.&lt;/p&gt;
&lt;p&gt;If you want your PRs to be one single commit on merge, it can be achieved by enabling squash commits on merge. After getting approval, you can also use interactive rebase to squash the commits manually.&lt;/p&gt;
&lt;p&gt;I would still strongly suggest that there is value in keeping the individual commits (as long as each commit is a logical unit) so that you can use tools like &lt;code&gt;git bisect&lt;/code&gt; or even eyeball the commit messages to make it easier to find the underlying culprit. Alternatively, you can merge each commit as an individual PR.&lt;/p&gt;
&lt;h3 id="q-is-there-a-middle-ground-between-having-a-single-commit-and-too-many-small-ones"&gt;Q: Is there a middle ground between having a single commit and “too many” small ones?&lt;/h3&gt;
&lt;p&gt;Yes. You can go overboard with too many small commits, and a balance needs to be achieved.&lt;/p&gt;
&lt;p&gt;Having smaller commits doesn't mean that you show every step or that the commits should reflect the edit history. Each commit should make logical sense on its own.&lt;/p&gt;
&lt;p&gt;I have addressed this with the “What to split” section.&lt;/p&gt;
&lt;h3 id="q-isnt-it-problematic-to-review-individual-commits-given-they-can-often-be-part-of-the-developers-journey-of-changing-their-mind-refactoring-and-gaining-insights"&gt;Q: Isn't it problematic to review individual commits, given they can often be part of the developer's journey of changing their mind, refactoring, and gaining insights?&lt;/h3&gt;
&lt;p&gt;Smaller commits doesn't mean you show every step; each commit should be a logical unit that provides value in production. Otherwise, it's just cruft.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Drop it or Squash it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If the author changes their mind, how does that commit provide value to the reviewer or the system in production? The author should be using interactive rebase to squash or drop those commits before putting them up for review.&lt;/p&gt;
&lt;h3 id="q-do-you-have-any-suggestions-for-preparing-atomic-commits"&gt;Q: Do you have any suggestions for preparing atomic commits?&lt;/h3&gt;
&lt;p&gt;Proper planning and upfront thinking of how to break the PR helps, but it is not always possible. I use interactive rebase, cherry-picking and changesets in IntelliJ liberally.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;If this is something you are interested in knowing more about, let me know in the comments.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="q-what-about-making-changes-based-on-review-comments"&gt;Q: What about making changes based on review comments?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Every review should be a snapshot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once a reviewer has reviewed your PR, you should not be making changes to commits that have been reviewed.&lt;/p&gt;
&lt;p&gt;The (new) commits that you make to address the review comments should follow the same rules as above.&lt;/p&gt;
&lt;p&gt;Writing a commit message like "&lt;em&gt;address PR feedback&lt;/em&gt;" and then dumping all the requested changes in 1 commit is not helpful. TBH, even I have been guilty of doing this at times.&lt;/p&gt;
&lt;p&gt;You dont want the reviewer to have to revisit the commits that they have already reviewed but you also want to make it easy for them to ensure that their comments have been addressed correctly.&lt;/p&gt;
&lt;p&gt;I prefer to prefix such commits with &lt;strong&gt;CR:&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="in-conclusion"&gt;In Conclusion&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;It’s the author’s responsibility to make the code review easy for the reviewer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While it may seem tedious to make frequent small commits and tempting to wait until all the work is completed, the advantages of small commits are significant.&lt;/p&gt;
&lt;p&gt;However, remember that the size of a commit will depend on the context and the nature of the change.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The key is to ensure that each commit makes sense on its own and represents a single logical change.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Breaking a PR with one large commit into smaller individual commits that make logical sense provides a nice stepping stone to be able to split into smaller PR's.&lt;/p&gt;
&lt;p&gt;Is there any reason why we &lt;strong&gt;shouldn't&lt;/strong&gt; be putting in the effort to make smaller commits and writing better commit messages?&lt;/p&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>Unity CI/CD Demystified: Part 4: Deploying WebGL Builds to GitHub Pages</title>
			<link>https://www.ankursheel.com/blog/unity-cicd-deploying-webgl-github-pages</link>
			<description>In Part 4, I show how to deploy a Unity projects to GitHub Pages</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/unity-cicd-deploying-webgl-github-pages-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/unity-cicd-deploying-webgl-github-pages</guid>
			<pubDate>Wed, 07 Aug 2024 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;In Part 1, we finished the &lt;a href="https://www.ankursheel.com/unity-cicd-one-time-setup"&gt;setup to start creating our CI/CD pipeline&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Part 2, we created a workflow to run our &lt;a href="https://www.ankursheel.com/unity-cicd-trigger-events-tests"&gt;automated tests based on some trigger events&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Part 3, we created a &lt;a href="https://www.ankursheel.com/unity-cicd-linux-build"&gt;reusable workflow to build the Unity project&lt;/a&gt; for various platforms.&lt;/p&gt;
&lt;p&gt;In part 4, we will use our reusable workflow to deploy a WebGL build to GitHub Pages.&lt;/p&gt;
&lt;p&gt;Start by updating your &lt;code&gt;.github/workflows/main.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;h2 id="job-1-building-for-webgl"&gt;Job 1: Building for WebGL&lt;/h2&gt;
&lt;p&gt;This job uses our reusable workflow to generate the files needed for hosting the game on a web server.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;buildForWebGL:
  name: Build for WebGL
  needs: test
  if: |
    github.event_name == 'pull_request' 
    || github.event.action == 'published' 
    || (contains(github.event.inputs.release_platform, 'release') 
          &amp;amp;&amp;amp; contains(github.event.inputs.release_platform, 'web'))
  uses: ./.github/workflows/buildWithLinux.yml
  with:
    platform: WebGL
    secrets:
      UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
      UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
      UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;needs&lt;/strong&gt;: This step depends on the successful completion of the &lt;code&gt;test&lt;/code&gt; job, added in Part 2.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;if&lt;/strong&gt;: Defines the conditions for this job to run.
&lt;ul&gt;
&lt;li&gt;push to the main branch or creating a pull request against it.&lt;/li&gt;
&lt;li&gt;GitHub release.&lt;/li&gt;
&lt;li&gt;Manually trigger the workflow with the '&lt;strong&gt;&lt;em&gt;release&lt;/em&gt;&lt;/strong&gt;' and '&lt;strong&gt;&lt;em&gt;web&lt;/em&gt;&lt;/strong&gt;' parameters in the &lt;code&gt;release_platform&lt;/code&gt; field.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;uses&lt;/strong&gt;:Call the reusable workflow from Part 3 with the necessary parameters, setting the &lt;code&gt;platform&lt;/code&gt; to &lt;strong&gt;&lt;em&gt;WebGL&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="job-2-deploying-to-github-pages"&gt;Job 2: Deploying to GitHub Pages&lt;/h2&gt;
&lt;p&gt;This job copies the WebGL artifact to the correct location for &lt;a href="https://pages.github.com/"&gt;GitHub Pages&lt;/a&gt;. Once copied, it triggers a GitHub Pages deployment.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;deployToGitHubPages:
  name: Deploy to GitHub Pages
  runs-on: ubuntu-latest
  needs: buildForWebGL
  if: |
    github.event_name == 'pull_request' 
    || github.event.action == 'published' 
    || (contains(github.event.inputs.release_platform, 'release') 
          &amp;amp;&amp;amp; contains(github.event.inputs.release_platform, 'web'))
  steps:
    - name: Echo Build Version
      run: echo ${{ needs.buildForWebGL.outputs.buildVersion }}

    - name: Checkout Repository
      uses: actions/checkout@v4
      with:
        fetch-depth: 1
        lfs: false

    - name: Download WebGL Artifact
      uses: actions/download-artifact@v4
      with:
        name: build-WebGL
        path: build/WebGL

    - name: Deploy to GitHub Pages
      uses: JamesIves/github-pages-deploy-action@v4
      with:
        folder: build/WebGL/WebGL
        commit-message: Deploy
        single-commit: true

    - name: Cleanup to avoid storage limit
      uses: geekyeggo/delete-artifact@v5
      if: always()
      with:
        name: build-WebGL
        failOnError: false
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;needs&lt;/strong&gt;: This job depends on the successful completion of the &lt;code&gt;buildForWebGL&lt;/code&gt; job.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;if&lt;/strong&gt;:  It follows the same conditions as the &lt;em&gt;buildForWebGL&lt;/em&gt; job.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, we have a series of steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Echo Build Version&lt;/strong&gt;: Prints the build version generated by the &lt;code&gt;buildForWebGL&lt;/code&gt; job.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Checkout Repository&lt;/strong&gt;: Checks out the code repository.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Download WebGL Artifact&lt;/strong&gt;: Get the &lt;strong&gt;&lt;em&gt;build-WebGL&lt;/em&gt;&lt;/strong&gt; artifact produced by the &lt;code&gt;buildForWebGL&lt;/code&gt; job and put it into the &lt;strong&gt;&lt;em&gt;build/WebGL&lt;/em&gt;&lt;/strong&gt; directory.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy to GitHub Pages&lt;/strong&gt;: Deploy the contents of the &lt;strong&gt;&lt;em&gt;build/WebGL/WebGL&lt;/em&gt;&lt;/strong&gt; folder to GitHub Pages.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cleanup to avoid storage limit&lt;/strong&gt;: Delete the &lt;strong&gt;&lt;em&gt;build-WebGL&lt;/em&gt;&lt;/strong&gt; artifact.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="setting-up-github-pages"&gt;Setting up Github Pages&lt;/h2&gt;
&lt;p&gt;Once the workflow for a WebGL build is triggered, a &lt;em&gt;&lt;strong&gt;gh_pages&lt;/strong&gt;&lt;/em&gt; branch will be created. Now you can setup Github pages to showcase your game.&lt;/p&gt;
&lt;p&gt;In the repository on GitHub, navigate to &lt;em&gt;Settings&lt;/em&gt; -&amp;gt; &lt;em&gt;Pages&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Set the source to &lt;strong&gt;&lt;em&gt;Deploy from a branch&lt;/em&gt;&lt;/strong&gt; and set the branch to &lt;code&gt;gh-pages&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/unity-cicd-deploying-webgl-github-pages/repository-settings.png" alt="Repository Settings"&gt;&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this part, we deployed our Unity Project to Github pages. Next, we will generate certificates for iOS deployments.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-workflows/reusing-workflows#calling-a-reusable-workflow"&gt;Calling a reusable workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/actions/github-pages-deploy-action"&gt;Github Pages Deploy Action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/marketplace/actions/delete-artifact"&gt;Delete Artifact Github Action&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>2023 - Q3 Retrospective</title>
			<link>https://www.ankursheel.com/blog/2023-q3-retrospective</link>
			<description>At the start of the quarter, I laid out some high-level goals. Here’s how I did against those goals.</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/2023-q3-retrospective-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/2023-q3-retrospective</guid>
			<pubDate>Mon, 30 Oct 2023 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;At the start of the quarter, I laid out some high-level personal goals. Here’s how I did against those goals.&lt;/p&gt;
&lt;h4 id="goal-publish-3-blog-posts"&gt;Goal: Publish 3 blog posts&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: I published 4 posts&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How it went&lt;/strong&gt;: &lt;span style="color: green;"&gt;SUCCESS&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I published 4 posts.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.ankursheel.com/unity-personal-license-manual-activation-workaround"&gt;Workaround for Unity Personal License Manual Activation Not Supported&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ankursheel.com/cleaning-up-unnecessary-remote-tracking-references"&gt;Cleaning Up Unnecessary Remote-Tracking References&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ankursheel.com/unlock-your-careers-potential-effective-11-meetings"&gt;Unlock your career's potential with effective 1:1 meetings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ankursheel.com/unity-cicd-one-time-setup"&gt;Unity CI/CD Demystified: Part 1: One-Time Setup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also refreshed an old post&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.ankursheel.com/rent-buy-house"&gt;Should I Rent Or Buy a House?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="goal-publish-3-book-summaries"&gt;Goal: Publish 3 book summaries&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: I didnt finish even a single book summary&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How it went&lt;/strong&gt;: &lt;span style="color: red;"&gt;FAILURE&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I need to take out time to write a book summary a month. Maybe I should have spent some time on book summaries instead of the 4th post.&lt;/p&gt;
&lt;h3 id="goal-explore-ideas-for-a-new-game"&gt;Goal: Explore ideas for a new game&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;: I settled on creating a Wordle for Kids and reached out to a few people to gauge interest.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How it went&lt;/strong&gt;: &lt;span style="color: orange;"&gt;MEH&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I created a MVP for a 4 letter wordle clone. I shared a &lt;a href="https://tally.so/r/wverVQ"&gt;form&lt;/a&gt; on social media to gauge interest for a Wordle for Kids game. Although, I did not get as many responses as I would have liked, it was enough to validate that people are interested in having an app that has kid appropriate 4 letter words.&lt;/p&gt;
&lt;h2 id="goals-for-next-month"&gt;Goals for next month&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Publish 3 blog posts on ankursheel.com&lt;/li&gt;
&lt;li&gt;Publish 3 book summaries on discoveriesinbookland.com&lt;/li&gt;
&lt;li&gt;Get WordXplorer in the hands of beta testers and get the 1st release out&lt;/li&gt;
&lt;li&gt;Get 10 more responses to the WordXplorer form&lt;/li&gt;
&lt;li&gt;Lose 5 kgs&lt;/li&gt;
&lt;li&gt;25 consecutive pushups&lt;/li&gt;
&lt;li&gt;50 consecutive squats&lt;/li&gt;
&lt;/ul&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>Unity CI/CD Demystified: Part 3: Build with Linux</title>
			<link>https://www.ankursheel.com/blog/unity-cicd-linux-build</link>
			<description>In Part 3 of our Unity CI/CD series, I show how to create a reusable workflow to build Unity projects for different platforms.</description>
			<guid>https://www.ankursheel.com/blog/unity-cicd-linux-build</guid>
			<pubDate>Wed, 07 Aug 2024 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;In Part 1, we finished the &lt;a href="https://www.ankursheel.com/unity-cicd-one-time-setup"&gt;setup to start creating our CI/CD pipeline&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Part 2, we created a workflow to run our &lt;a href="https://www.ankursheel.com/unity-cicd-trigger-events-tests"&gt;automated tests based on some trigger events&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Part 3, we will create a reusable workflow to build the Unity project for various platforms.&lt;/p&gt;
&lt;p&gt;The jobs in this workflow will run on a Linux VM.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Why Linux?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Its the cheapest box. As we will see in later posts, different platforms need a different OS for deployment. I am looking at you iOS.&lt;/p&gt;
&lt;p&gt;Creating a new workflow definition &lt;code&gt;.github/workflows/buildWithLinux.yml&lt;/code&gt;:&lt;/p&gt;
&lt;h2 id="defining-the-workflow"&gt;Defining the Workflow&lt;/h2&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;name: Build with Linux  
on:  
  workflow_call:   
    inputs:   
      platform:  
        required: true  
        type: string  
      secrets:  
        UNITY_EMAIL:  
          required: true  
        UNITY_PASSWORD:  
          required: true  
        UNITY_LICENSE:  
          required: true  
    outputs:  
      buildVersion:  
        value: ${{ jobs.buildWithLinux.outputs.buildVersion }} 
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;on&lt;/strong&gt;: Specify the events that trigger the workflow.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;workflow_call&lt;/strong&gt;: Set the workflow to be called from other workflows.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;inputs&lt;/strong&gt;: Values passed in from the caller workflow .
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;platform&lt;/strong&gt;: Platform for which the Unity project should be built.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;secrets&lt;/strong&gt;: Secrets passed in from the caller workflow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;outputs&lt;/strong&gt;: Data to pass back to the caller workflow.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;buildVersion&lt;/strong&gt;: The version generated by the job.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-linux-build-job"&gt;The Linux Build Job&lt;/h2&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;jobs:  
  
  buildWithLinux:  
    name: Build in Linux for ${{ inputs.platform }}  
    runs-on: ubuntu-latest  
    outputs:  
      buildVersion: ${{ steps.build.outputs.buildVersion }}  
      steps:  
      - name: Checkout Repository  
        uses: actions/checkout@v4  
        with:  
          fetch-depth: 0  
          lfs: true  
  
      - name: Cache Library  
        uses: actions/cache@v4 
        with:  
          path: Library  
          key: Library-build-${{ inputs.platform }}  
          restore-keys: |  
            Library-build-${{ inputs.platform }}
            Library-    

      - name: Build Unity Project  
        id: build  
        uses: game-ci/unity-builder@v4  
        env:  
          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}  
          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}  
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}  
        with:  
          targetPlatform: ${{ inputs.platform }}  
  
      - name: Upload Build  
        uses: actions/upload-artifact@v4  
        with:  
          name: build-${{ inputs.platform }}  
          path: build/${{ inputs.platform }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here's a breakdown of what's happening in this job:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;outputs&lt;/strong&gt;: Data we want to return back to the caller workflow.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;buildVersion&lt;/strong&gt;: Version generated by the Builder in the &lt;code&gt;build&lt;/code&gt; step below.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;steps:&lt;/strong&gt; This section contains a series of steps to be executed for this job.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Checkout Repository:&lt;/strong&gt; Check out the code
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;fetch-depth&lt;/strong&gt;: Get only the last commit of the branch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;lfs&lt;/strong&gt;: Download files tracked by LFS.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache Library&lt;/strong&gt;: Cache the "Library" directory, to make subsequent runs faster. The &lt;code&gt;key&lt;/code&gt; is unique to each platform.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build Unity Project&lt;/strong&gt;: Build the Unity project for the target platform.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Upload Build&lt;/strong&gt;: Upload the built Unity project as an artifact so that it can be downloaded in later jobs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this part, we created a reusable workflow to build the Unity project for different platforms. Next, we will use this workflow to build and deploy a WebGL build to GitHub pages.&lt;/p&gt;
&lt;p&gt;Happy building!&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-workflows/reusing-workflows#creating-a-reusable-workflow"&gt;Creating a reusable workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-jobs/defining-outputs-for-jobs"&gt;Defining Outputs for a job&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://game.ci/docs/github/builder#configuration-options"&gt;GameCI builder Configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://game.ci/docs/github/builder#outputs"&gt;GameCI builder Output&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>WordXplorer #2: TestFlight Approved, New Colors &amp; Instructions</title>
			<link>https://www.ankursheel.com/blog/wordxplorer-update-2</link>
			<description>WordXplorer Update 2 updates the colors and adds a new instruction page</description>
			<enclosure url="https://www.ankursheel.com/assets/images/social/wordxplorer-update-2-facebook.png" length="0" type="image" />
			<guid>https://www.ankursheel.com/blog/wordxplorer-update-2</guid>
			<pubDate>Mon, 16 Oct 2023 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;You can see all the related updates &lt;a href="https://www.ankursheel.com/tags/wordxplorer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I am thrilled to share some updates for the wordxplorer game! 🎉&lt;/p&gt;
&lt;h2 id="testflight-approval"&gt;🚀 Testflight Approval&lt;/h2&gt;
&lt;p&gt;The first version with around 25 words has received the green light for TestFlight! If you registered as beta tester for iOS, watch your inbox for those invites - they're coming soon! 📬 . If you didnt, you can register by filling &lt;a href="https://tally.so/r/wverVQ"&gt;the form&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="updated-colors"&gt;🌈 Updated Colors&lt;/h2&gt;
&lt;p&gt;I have revamped the colors! Let me know if you have any suggestions on better colors. Share your ideas with me! 🎨&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-2/updated_colors.jpg" alt="Updated Colors"&gt;&lt;/p&gt;
&lt;h2 id="instructions-page"&gt;📜 Instructions Page&lt;/h2&gt;
&lt;p&gt;I have added a new instructions page at the start of the game for people who are new to Wordle.📘&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/wordxplorer-update-2/instructions.jpg" alt="Instructions"&gt;&lt;/p&gt;
&lt;h2 id="whats-next"&gt;🔮 What's Next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;A public Trello board for the roadmap, so beta testers can vote on what they would like to see next.&lt;/li&gt;
&lt;li&gt;More Words&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;Update 26th December 2024:&lt;/em&gt;&lt;/strong&gt; You can now download the game.&lt;/p&gt;
&lt;div class="appstore-badges-container"&gt;
  &lt;a href="https://apps.apple.com/in/app/wordxplorer-guess-the-word/id6504664783" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-app-store-badge.png" alt="Get WordXplorer on App Store"&gt;
  &lt;/a&gt;
  &lt;a href="https://play.google.com/store/apps/details?id=com.glhf.wordleforkids" target="_blank"&gt;
    &lt;img src="https://www.ankursheel.com/assets/images/download-play-store-badge.png" alt="Get WordXplorer on Play Store"&gt;
  &lt;/a&gt;
&lt;/div&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
		<item>
			<title>Unity CI/CD Demystified: Part 2: Trigger Events and Running Tests</title>
			<link>https://www.ankursheel.com/blog/unity-cicd-trigger-events-tests</link>
			<description>In Part 2,  I show how to create a workflow to run our automated tests based on some trigger events</description>
			<guid>https://www.ankursheel.com/blog/unity-cicd-trigger-events-tests</guid>
			<pubDate>Wed, 07 Aug 2024 00:00:00 GMT</pubDate>
			<content:encoded>&lt;p&gt;In Part 1, we finished the &lt;a href="https://www.ankursheel.com/unity-cicd-one-time-setup"&gt;setup to start creating our CI/CD pipeline&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Part 2, we will create a workflow to run our automated tests based on some trigger events.&lt;/p&gt;
&lt;h2 id="update.gitignore"&gt;Update .gitignore&lt;/h2&gt;
&lt;p&gt;Before you create your workflow, you need to ignore the files generated by GameCI. Update the &lt;code&gt;.gitignore&lt;/code&gt; file with these lines:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/[Aa]rtifacts/
/[Cc]odeCoverage/
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="setting-the-trigger-events"&gt;Setting the Trigger Events&lt;/h2&gt;
&lt;p&gt;Now, you need to define when your pipeline should trigger.&lt;/p&gt;
&lt;p&gt;Create &lt;code&gt;.github/workflows/main.yml&lt;/code&gt; and add the following workflow definition:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;name: Test, Build, and Deploy with GameCI
on:
  push:
    branches:
      - main
    paths:
      - 'Assets/**'
      - 'Packages/**'
      - 'ProjectSettings/**'
  pull_request:
    types:
      - opened
      - synchronize
    branches:
      - main
    paths:
      - 'Assets/**'
      - 'Packages/**'
      - 'ProjectSettings/**'
      - '.github/workflows/**'
  release:
    types:
      — published
  workflow_dispatch:
    inputs:
      release_platform:
        description: 'release [ios, web, testflight]'
        required: false
        default: 'release '
jobs:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A lot is going on here, so let's break it down:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;on&lt;/strong&gt;: Specify the events that trigger the workflow.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;push&lt;/strong&gt; -&amp;gt; &lt;strong&gt;branches&lt;/strong&gt; : push event to the "main" branch
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;paths&lt;/strong&gt;: filter to only changes that happen in the Unity project or the workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pull_request&lt;/strong&gt; -&amp;gt; &lt;strong&gt;types&lt;/strong&gt;: pull request is opened or updated against the "main" branch.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;paths&lt;/strong&gt;: filter to only changes that happen in the Unity project or the workflows. &lt;em&gt;(Same as the push event).&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;release&lt;/strong&gt; -&amp;gt; &lt;strong&gt;publish&lt;/strong&gt;: publish a release.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;workflow_dispatch&lt;/strong&gt;: manually trigger the workflow using the GitHub Actions interface.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;input&lt;/strong&gt; -&amp;gt; &lt;strong&gt;release_platform&lt;/strong&gt;: input to specify the platform. Add the default text to "release" so that there is less typing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="building-and-running-tests"&gt;Building and Running Tests&lt;/h2&gt;
&lt;p&gt;Next, add a new job to build and run the &lt;a href="https://docs.unity3d.com/Manual/testing-editortestsrunner.html"&gt;Unity project tests&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-yaml"&gt;jobs:

  test:
    name: Build and Run Tests
    runs-on: ubuntu-latest
    steps:
      # Checkout with lfs
      - name: Checkout Repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 1
          lfs: true

      - name: Cache Library
        uses: actions/cache@v4
        with:
          path: Library
          key: Library-test-${{ hashFiles('Assets/**') }}
          restore-keys: |
            Library-test-${{ hashFiles('Assets/**') }}
            Library-test

      - name: Run Tests
        uses: game-ci/unity-test-runner@v4
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
        with:
          githubToken: ${{ secrets.GITHUB_TOKEN }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let's look at whats happening in this job:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;runs-on:&lt;/strong&gt; The job should run on an lates Ubuntu-based runner.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;steps:&lt;/strong&gt; The steps to execute for this job.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Checkout Repository:&lt;/strong&gt; Check out the code
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;fetch-depth&lt;/strong&gt;: Get only the last commit of the branch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;lfs&lt;/strong&gt;: Download files tracked by LFS.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cache Library&lt;/strong&gt;: Cache the "Library" directory, to make subsequent runs faster.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Run Tests:&lt;/strong&gt; Runs the Unity tests.
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;env&lt;/strong&gt;:  Set the environment variables&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;with&lt;/strong&gt; -&amp;gt; &lt;strong&gt;githubToken&lt;/strong&gt;: Set the GITHUB_TOKEN from the secrets to report the test results.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="set-workflow-permissions"&gt;Set Workflow Permissions&lt;/h2&gt;
&lt;p&gt;To view test results as part of the Github Status check, you need to provide write permissions to the workflow&lt;/p&gt;
&lt;p&gt;Go to &lt;em&gt;Settings&lt;/em&gt; &amp;gt; &lt;em&gt;Actions&lt;/em&gt; &amp;gt; &lt;em&gt;General&lt;/em&gt; &amp;gt; &lt;em&gt;Workflow permissions&lt;/em&gt; and choose &lt;em&gt;Read and write permissions&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.ankursheel.com/assets/images/posts/unity-cicd-trigger-events-tests/workflow_permissions.png" alt="Workflow Permission"&gt;&lt;/p&gt;
&lt;h2 id="preparing-the-project"&gt;Preparing the Project&lt;/h2&gt;
&lt;p&gt;If the project builds in the editor but fails when you run the workflow, its likely because of missing packages.&lt;/p&gt;
&lt;p&gt;Luckily, its a simple fix.&lt;/p&gt;
&lt;h3 id="verify-packages"&gt;Verify Packages&lt;/h3&gt;
&lt;p&gt;Ensure that these entries are present in &lt;code&gt;packages/manifest.json&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;com.unity.2d.sprite&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;com.unity.inputsystem&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;com.unity.test-framework&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;com.unity.textmeshpro&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If any of these packages are missing, add them using the Unity Package Manager. Remember to commit the changes in &lt;code&gt;packages/manifest.json&lt;/code&gt; and &lt;code&gt;packages/package-lock.json&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this part, we set up the trigger events for the workflow and added a job to build and run tests. Next, we will add a job to build the project for different platforms.&lt;/p&gt;
&lt;h2 id="references"&gt;References&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows"&gt;Events that trigger workflows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://game.ci/docs/github/test-runner"&gt;GameCI TestRunner docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded>
			<comments xmlns="http://purl.org/rss/1.0/modules/slash/">0</comments>
		</item>
	</channel>
</rss>