<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ash G</title>
    <description>The latest articles on Forem by Ash G (@ash_grover).</description>
    <link>https://forem.com/ash_grover</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F486459%2Fce0ebd23-3b94-49af-89ff-9898f7c747df.jpeg</url>
      <title>Forem: Ash G</title>
      <link>https://forem.com/ash_grover</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ash_grover"/>
    <language>en</language>
    <item>
      <title>AI-Assisted Coding: The Hype vs. The Hidden Risks</title>
      <dc:creator>Ash G</dc:creator>
      <pubDate>Thu, 20 Mar 2025 16:58:06 +0000</pubDate>
      <link>https://forem.com/ash_grover/ai-assisted-coding-the-hype-vs-the-hidden-risks-1560</link>
      <guid>https://forem.com/ash_grover/ai-assisted-coding-the-hype-vs-the-hidden-risks-1560</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6atdwk51pitdwcdy5ha0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6atdwk51pitdwcdy5ha0.jpg" alt="AI" width="800" height="451"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@nahrizuladib" rel="noopener noreferrer"&gt;Nahrizul Kadri&lt;/a&gt; on Unsplash&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;“Vibe coding” or AI-assisted&lt;/strong&gt; coding has become popular in the past few months. It simply means prompting the AI to generate your codebase. If a bug occurs, instead of digging into the code, you tell AI to fix the bug. Some are even claiming it could allow anyone, without any software development training at all, to easily build software.&lt;/p&gt;

&lt;p&gt;Now, AI-assisted coding is fantastic for non-technical founders with basic coding skills, indie developers, and small teams building CRUD apps, MVPs, simple mobile apps or automating repetitive tasks. It accelerates iteration cycles, allowing more people to test ideas with minimal development effort. In tech and startup community circles like HN, Product Hunt etc., there’s often a sample bias, where everyone is in the startup space, using AI tools or building AI agents.&lt;/p&gt;

&lt;p&gt;However, once you move into enterprise applications, especially those dealing with &lt;strong&gt;critical sectors&lt;/strong&gt; like banking, healthcare, cybersecurity and government systems, the stakes are entirely different. Enterprises have regulatory requirements, compliance concerns, and internal security policies that make them extremely cautious. They simply cannot afford to let any third-party AI company touch their codebase, as it poses risks to security, compliance, and long-term maintainability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First&lt;/strong&gt;, there are serious concerns about &lt;strong&gt;protecting intellectual property&lt;/strong&gt; with AI-assisted coding. If you suggest that their code will be sent to a cloud-based LLM, good luck navigating that conversation. They are deeply protective of their proprietary codebases, and sending any part of it to an external LLM(hosted by a third-party) is a non-starter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Second&lt;/strong&gt;, AI frequently produces &lt;strong&gt;bug-ridden code&lt;/strong&gt;, and an oversight by an "experienced" developer is constantly needed to effectively use AI. AI coding assistants work best as &lt;em&gt;enhancements&lt;/em&gt; for experienced developers, not as a replacement. Subtle logic bugs, poor optimization, and architectural inconsistencies can add up and lead to performance degradation, scalability challenges, and hard-to-debug failures that compound over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Third&lt;/strong&gt;, a huge and under-discussed issue. The &lt;strong&gt;security risks&lt;/strong&gt; that AI can possibly introduce into the code are &lt;strong&gt;significant&lt;/strong&gt;. AI models trained on public codebases often &lt;strong&gt;inherit bad security practices&lt;/strong&gt;, which means they are likely to produce insecure code. While this might be tolerable for a fun weekend project, in an enterprise setting, these risks are unacceptable, potentially leading to security vulnerabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fourth&lt;/strong&gt;, unchecked AI usage will accumulate massive technical debt. If you let AI generate code without understanding what each line is doing, the technical debt will accumulate at an alarming rate. When things go awry, you won't know where to start looking to fix them. &lt;strong&gt;In any firm, the ability to debug and refactor existing code is a huge part of a software engineer’s responsibility&lt;/strong&gt;, more so than writing code from scratch. If you’re blindly accepting AI suggestions, your codebase will become an opaque box, resulting in code that is hard to debug and an architecture that will not scale. &lt;/p&gt;

&lt;p&gt;In my software engineering career, I have been taught to write &lt;strong&gt;"every line of code with a purpose."&lt;/strong&gt; You should know why you wrote that line, what it is doing, and how it will affect other parts of the code. AI will not replace strong engineering fundamentals, but it will make good engineers more productive &lt;strong&gt;while amplifying the mistakes of bad ones&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you're a software engineer, it's crucial to be aware of AI's limitations and associated risks. Cautiously explore its potential through side projects or weekend experiments to stay up-to-date with emerging AI technologies. Again, there is absolutely no replacement for strong software engineering fundamentals. If your goal is to progress further in this profession, mastering the ability to understand, navigate, and debug complex code will always be more valuable than relying on AI tools.&lt;/p&gt;

&lt;p&gt;AI-assisted coding is here to stay, but its role in professional software development will depend on the context. Startups and solo founders can reap significant benefits, while enterprises, understandably, will remain skeptical, especially when it comes to security, compliance, and long-term maintainability. &lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;Hi, I’m Ash. With 10 years of experience in software engineering, I’m passionate about using technology to improve efficiency and create real value.&lt;br&gt;
I also built &lt;a href="https://brisqi.com" rel="noopener noreferrer"&gt;&lt;strong&gt;Brisqi&lt;/strong&gt;&lt;/a&gt;, a personal Kanban app designed to help people stay organized and in control.&lt;br&gt;
Outside of work, I spend time hiking in the mountains or snowboarding — nature is where I recharge and find much of my inspiration.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>security</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Achieving More: How software engineers can benefit from Kanban</title>
      <dc:creator>Ash G</dc:creator>
      <pubDate>Sat, 26 Oct 2024 05:12:15 +0000</pubDate>
      <link>https://forem.com/ash_grover/achieving-more-how-software-engineers-can-benefit-from-kanban-29go</link>
      <guid>https://forem.com/ash_grover/achieving-more-how-software-engineers-can-benefit-from-kanban-29go</guid>
      <description>&lt;p&gt;I worked as a Software engineer for more than eight years. I've navigated countless projects, deadlines, and team dynamics. Managing my workload effectively was essential for my productivity and I’ve found Kanban to be an invaluable tool for task management. &lt;/p&gt;

&lt;p&gt;In this blog, I’ll share how software engineers can utilize Kanban to organize projects, enhance focus, and streamline their work. Best of all, no special software is needed to follow a Kanban workflow, a simple Excel sheet with columns and cells can do the job just fine.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of Kanban
&lt;/h3&gt;

&lt;p&gt;Before diving into the specifics, let’s quickly highlight the key benefits of using Kanban for personal task management:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visual Organization&lt;/strong&gt;: Kanban offers a clear visual layout of tasks, making it easy to see what needs to be done at a glance.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Increased Focus&lt;/strong&gt;: Limiting work in progress (WIP) to a &lt;strong&gt;maximum of two tasks&lt;/strong&gt; reduces cognitive load and minimizes distractions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptability&lt;/strong&gt;: Kanban allows for quick adjustments to priorities, enabling effective responses to changing circumstances or urgent tasks.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time Management&lt;/strong&gt;: Kanban simplifies task estimation, making it easier to plan time effectively and allocate resources where they are needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Setting Up the Kanban Board
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Defining the Workflow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Kanban board can be structured into the following lists:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Icebox&lt;/strong&gt;: A collection of new ideas and future tasks for later consideration.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backlog&lt;/strong&gt;: A list of tasks to be implemented.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;To Do&lt;/strong&gt;: Items prioritized for immediate attention.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In Progress&lt;/strong&gt;: Tasks that are currently being worked on.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Review&lt;/strong&gt;: For tasks that require peer feedback.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing&lt;/strong&gt;: For quality assurance checks.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Done&lt;/strong&gt;: The section where completed tasks are stored.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This layout mirrors the software development lifecycle, from initial ideation through testing and completion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Creating Task Cards&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each task card includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Title&lt;/strong&gt;: A clear and concise description of the task.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;:  A detailed overview of the task, including &lt;strong&gt;acceptance criteria&lt;/strong&gt; that outline the specific conditions that must be met for the task to be considered complete.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Due Date&lt;/strong&gt;: A deadline to assist in effective prioritization of tasks.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Labels for Estimation&lt;/strong&gt;: Instead of traditional story points, labels can be used to indicate the estimated effort for each task. The labels represent time estimates as follows:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;0.5d&lt;/strong&gt;: Half a day
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1d&lt;/strong&gt;: One day
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2d&lt;/strong&gt;: Two days
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3d&lt;/strong&gt;: Three days
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1w&lt;/strong&gt;: One week
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2w&lt;/strong&gt;: Two weeks
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1mo&lt;/strong&gt;: One month&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This system provides a clear overview of the time commitment required for each task, allowing for effective workload planning.&lt;/p&gt;

&lt;p&gt;Here’s a screenshot of Kanban lists created in Google Sheets:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivovi61umj1jdmxm47cb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fivovi61umj1jdmxm47cb.png" alt="Kanban example" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Time Blocking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To maintain focus, use time blocking to allocate specific periods for different tasks. For instance, you might dedicate the first two hours of the day to coding new features, followed by a block for addressing bugs or participating in code reviews. This method minimizes context switching, which improves productivity in software development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4: Work in Progress (WIP)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Establish WIP limits for the “In Progress” column, typically setting it to two tasks at a time. This principle is rooted in Lean methodology and helps you avoid multitasking, a common pitfall that can lead to reduced quality and slower progress. By limiting WIP, you can focus on completing tasks before taking on new ones, ensuring a more efficient workflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 5: Breaking Tasks into Smaller Components&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For larger tasks, breaking them down into smaller, manageable chunks is crucial for building momentum. This approach makes it easier to tackle complex projects and keeps motivation high. For example, when implementing a new feature, tasks might include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gather Requirements&lt;/strong&gt;: Understand the specifications.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design UI/UX&lt;/strong&gt;: Create mockups and user flows.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Develop Backend&lt;/strong&gt;: Write the necessary code.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unit Testing&lt;/strong&gt;: Ensure functionality works as intended.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Review&lt;/strong&gt;: Gather feedback from peers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these subtasks becomes its own card on the Kanban board, making it easier to track progress and maintain momentum.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 6: Review progress&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Regularly reviewing the Kanban board is essential for assessing progress and adapting to changing circumstances. During this time, customer requests can be identified and addressed, and tasks can be reprioritized based on new information or shifting needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 7: Recognizing Milestones&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It’s key to celebrate milestones, whether it’s moving an important task to the “Done” column or wrapping up a tough project. Taking a moment to acknowledge these wins boosts motivation and highlights the importance of delivering quality work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Leveraging Kanban for Personal Development
&lt;/h3&gt;

&lt;p&gt;In addition to task management, the Kanban board can be used to track personal development goals. Whether learning a new programming language, exploring a framework, or contributing to open-source projects, creating specific cards for these initiatives ensures that time is set aside for continuous learning. Staying on top of personal growth is important in the fast-changing tech landscape.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final thoughts
&lt;/h3&gt;

&lt;p&gt;Implementing Kanban for personal task management has transformed the way I approach my tasks. Its flexibility, focus on flow, and alignment with Lean principles make it a great fit for handling complex tasks. By using techniques such as time blocking, breaking tasks into smaller components, and employing Kanban color coding alongside time estimation labels, I can manage my workload effectively while maintaining a high standard of quality. If you're looking to boost your productivity and streamline your workflow, consider adopting Kanban. It might be the missing piece for optimizing your personal task management and achieving your professional goals. &lt;/p&gt;

&lt;p&gt;For all my personal projects, I use the offline Kanban app &lt;a href="https://brisqi.com" rel="noopener noreferrer"&gt;Brisqi&lt;/a&gt; for personal task management. This tool provides a level of privacy and control that’s essential for my workflow and having a private space to manage tasks allows me to keep my thoughts and projects secure. &lt;/p&gt;

</description>
      <category>kanban</category>
      <category>productivity</category>
      <category>softwaredevelopment</category>
      <category>learning</category>
    </item>
    <item>
      <title>How I designed an offline-first app. An outline.</title>
      <dc:creator>Ash G</dc:creator>
      <pubDate>Thu, 01 Jul 2021 21:24:27 +0000</pubDate>
      <link>https://forem.com/ash_grover/how-i-designed-an-offline-first-app-an-outline-45c</link>
      <guid>https://forem.com/ash_grover/how-i-designed-an-offline-first-app-an-outline-45c</guid>
      <description>&lt;p&gt;Last week I wrote a &lt;a href="https://dev.to/ash_grover/i-built-my-app-in-react-react-native-and-nextjs-lessons-learned-3f38"&gt;blog post&lt;/a&gt; on how I built my &lt;a href="https://brisqi.com" rel="noopener noreferrer"&gt;app&lt;/a&gt; in React, React Native and NextJS. This blog post gives an insight on how I made it into an offline-first app. There are many ways to build an offline-first app so this is a general outline of how I built it and what worked for me. I use NoSQL database so I use the word 'documents' throughout the blog post, but you can think of them as a record of a table in a SQL database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Offline-first? What does that even mean?
&lt;/h2&gt;

&lt;p&gt;I had to understand what offline-first apps really meant. I found different definitions of it around the internet. Partial offline functionality, partial offline data etc. but I wasn't satisfied with any of those, so I settled with the following definition:&lt;/p&gt;

&lt;p&gt;Offline-first apps are apps which can run and function completely offline or without needing the internet for an &lt;strong&gt;indefinite amount&lt;/strong&gt; of time. To offline-first apps, providing all functionality offline is the &lt;strong&gt;primary objective&lt;/strong&gt; and any online functionality such as syncing to cloud is secondary.&lt;/p&gt;

&lt;p&gt;There's also another category - &lt;strong&gt;offline-tolerant&lt;/strong&gt;. Offline-tolerant apps provide functionality offline for a limited amount of time or provide partial functionality and sooner or later they would require the user to sync data to the cloud. The amount of time is dependent on the type of functionality of the app and how the data is stored. Offline-tolerant apps mostly store partial data in a temporary cache, whereas offline-first apps store all it's data in a dedicated local database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep. Things. Simple.
&lt;/h2&gt;

&lt;p&gt;Offline-first architecture can get overwhelming, so I made sure to keep things as simple or primitive as possible when I started out. I didn't get into conflict resolution strategies or tried to handle poor network connection immediately. I worried about that stuff later.&lt;/p&gt;

&lt;p&gt;I worked with happy path and assumed that there were only two things I need to take care of - &lt;strong&gt;online and offline&lt;/strong&gt;. When the app is offline, &lt;strong&gt;I track actions performed by the user&lt;/strong&gt;. When the app is online - &lt;strong&gt;I replay those actions&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;This might seem a bit different compared to conventional way of doing things which is to track "changes" instead of actions. Tracking actions was so much easier than tracking changes. I don't have to keep a record of hundreds of changes a user might have made to a document in the database. I only track actions and replay them. That's it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's look at the following scenarios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  When the app is online
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;User performs an action (add, modify, delete etc.).&lt;/li&gt;
&lt;li&gt;Store changes in local database.&lt;/li&gt;
&lt;li&gt;Push changes to the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is straightforward. When the app is online, I just push out changes to both local database and server.&lt;/p&gt;

&lt;h3&gt;
  
  
  When the app is offline
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;User performs an action.&lt;/li&gt;
&lt;li&gt;Store changes in local database.&lt;/li&gt;
&lt;li&gt;Track actions in a queue and also store them in the local database.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the app is offline, I track what action(add, modify, delete etc.) was performed and the unique Id of the document so I can retrieve it later from the local database.&lt;/p&gt;

&lt;h3&gt;
  
  
  When the app is back online again
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Get tracked actions.&lt;/li&gt;
&lt;li&gt;Replay those actions one by one skipping local database and push them out to server.&lt;/li&gt;
&lt;li&gt;Retrieve data from the server and merge the data. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I get the actions either from the local database or from the queue if still in memory and call the functions corresponding to those actions one by one. Each of those functions now also know to skip the local database and to call the server API directly. Finally, I retrieve the data from the server and merge it back into the local database (more on this later).&lt;/p&gt;

&lt;p&gt;It all seems doable right? Keeping things simple was key here.&lt;/p&gt;



&lt;h2&gt;
  
  
  How should I detect if something changed?
&lt;/h2&gt;

&lt;p&gt;I needed to figure out how to track what documents changed. I tried following techniques: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Storing timestamps when the document changed and then comparing timestamps&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I didn't go with this one because there were lot issues with this technique. What if a document was changed at the same time from two different devices. It could happen when there are multiple users modifying data or if the date and time of the devices are out of sync(its rare but it can happen).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Versioning documents.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every time a change is made, a new version is created and the latest document along with version history is pushed out. I didn't go with this either as this would've made things too complicated, again I wanted to keep things simple. Git and PouchDB/CouchDB do this and they both do it in a really efficient manner, but I was using Firebase not CouchDB for reasons which are out of scope for this blog post. I needed a new strategy.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Generating a new changeset ID each time a document is changed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Changeset ID is just an ID which changes whenever anything changes in that document. If changeset ID is different, that means something has changed so the document should be updated. This technique was simple enough for me to experiment with and implement so I went ahead with this approach.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conflict resolution strategy
&lt;/h2&gt;

&lt;p&gt;Now, I needed a strategy to handle conflicts. There were two I could think of - either I merge all the changes coming in, or I take last write wins(LRW). I went ahead with last write wins. The strategy you pick is dependent on the type and importance of data you're merging. If you are building a note taking app then merging text data would make sense.&lt;/p&gt;

&lt;p&gt;In my case, I was developing a &lt;strong&gt;personal&lt;/strong&gt; Kanban app and only a single user would be syncing data to other devices. Last write wins made sense in this situation. If something got overwritten, its expected that the user knowingly made the change and would fix the changes if necessary. Its far easier to deal with LRW strategy when syncing data both ways. Keeping things simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  Syncing and merging documents from the cloud
&lt;/h2&gt;

&lt;p&gt;With everything I now had, i.e. unique reference Id for each document, changeset Id to detect a change in the document and LRW strategy, syncing documents with the local database became straightforward. Since I was using Firestore, Firestore query listeners gets called when something changes on the cloud. Think of them as an event listener which are called when Firestore SDK detects a change. If I wasn't using Firestore, I would build some kind of polling mechanism to detect any changes on the server side.&lt;/p&gt;

&lt;p&gt;To sync data, I do two things - &lt;strong&gt;Push first, then pull&lt;/strong&gt;. Push the pending actions in queue to the cloud if there are any, then pull the data from the server. Pushing and then pulling makes things simple as this way the user's data is always up-to-date. The recent changes made by the user don't get overwritten by the changes on the server. This also aligns with my LRW conflict resolution strategy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pushing data to the server
&lt;/h3&gt;

&lt;p&gt;I've already talked about pushing the actions before. You just call the corresponding server API functions and push the changes while skipping local database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pulling data from the server
&lt;/h3&gt;

&lt;p&gt;To pull the data I employed two methods here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Getting all the user's documents from the cloud and comparing them with local database to identify which one got added, modified and deleted, and then updating the local database accordingly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a very broad technique, I made it more efficient by limiting the number of documents I get based on a subset of data, you'd have to figure out based on your needs how you can limit the amount of data. In my case, I was working with Firestore query listeners, each collection would have different query listeners and I wanted to work with minimum amount of listeners as possible so this technique works for me. I use this technique for my desktop app as I want "all user's data" to stay up-to-date.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Only getting added, modified and deleted documents for a collection/table.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This strategy worked when getting all of the user data wasn't necessary. Especially in mobile app, to conserve user's bandwidth, the app would only retrieve data which the user wanted instead of fetching everything.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Merging documents
&lt;/h3&gt;

&lt;p&gt;Merging documents from the cloud to the local database involves adding new documents, updating modified documents or deleting "deleted" documents. Remember, I had unique reference ids and changeset Ids for each document? I would iterate through the both local data and retrieved data(from the cloud) and compare the changeset Ids, and then update the corresponding document in the local database if need be. It was time consuming to write the logic but it wasn't that bad.&lt;/p&gt;

&lt;p&gt;Here's what I did for each case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Detecting new documents&lt;/strong&gt;: If a new document is on the cloud, iterate through local collection, check if reference id exists, if it doesn't, its probably a new document so add it to the local database.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Detecting modified documents:&lt;/strong&gt; Compare the changeset Ids, if changeset Id is different, update the document in the database.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deleting "deleted" documents:&lt;/strong&gt; By "deleted" documents I mean documents which don't exist on the cloud anymore. To delete those documents, for each local document iterate through cloud's data and find out if it doesn't exist, then delete it in the local database.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  That's all for now
&lt;/h2&gt;

&lt;p&gt;That's it for an outline. Using changeset Ids to detect changes made my life a lot easier. I also use them in the mobile app for comparing and updating data on the global state which improved overall performance of the app. There are so many things I didn't mention here as it would make the post too long. Besides if you don't do some research on your own, you won't learn ;)&lt;/p&gt;

&lt;p&gt;Follow me on &lt;a href="https://twitter.com/ash_grover" rel="noopener noreferrer"&gt;&lt;strong&gt;Twitter&lt;/strong&gt;&lt;/a&gt; for behind the scenes of the &lt;a href="https://brisqi.com" rel="noopener noreferrer"&gt;app&lt;/a&gt; I'm building. I love connecting with new people and learning something new.&lt;/p&gt;

&lt;p&gt;All the best!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>javascript</category>
      <category>architecture</category>
    </item>
    <item>
      <title>I built my app in React, React Native and NextJS. Lessons learned.</title>
      <dc:creator>Ash G</dc:creator>
      <pubDate>Thu, 24 Jun 2021 19:47:53 +0000</pubDate>
      <link>https://forem.com/ash_grover/i-built-my-app-in-react-react-native-and-nextjs-lessons-learned-3f38</link>
      <guid>https://forem.com/ash_grover/i-built-my-app-in-react-react-native-and-nextjs-lessons-learned-3f38</guid>
      <description>&lt;p&gt;I developed an offline-first personal Kanban app called &lt;a href="https://brisqi.com" rel="noopener noreferrer"&gt;Brisqi&lt;/a&gt; and launched it for 5 different platforms. I started this project with 2 purposes - to learn React and to build my own offline Kanban app as I always wanted one. I've been working on Brisqi since June last year.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here's the tech stack I used in case you're curious:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;ReactJS + BlueprintJS + custom styling for desktop app.&lt;/li&gt;
&lt;li&gt;React Native + React Native elements + custom styling for Android/iOS App.&lt;/li&gt;
&lt;li&gt;NextJS + BulmaCSS for the website.&lt;/li&gt;
&lt;li&gt;Firebase Auth for authentication + Firestore for the database.&lt;/li&gt;
&lt;li&gt;Google cloud functions - to handle backend operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Electron framework was the obvious choice to make it cross-platform as it has good eco-system around it so I went ahead with it as the underlying framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  Following are the things I learned and followed specific to React, hope its helpful to you:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Start with Context API for state management if your app is small, learn how it works. This will get you use-to the reducer pattern in React. &lt;strong&gt;Don't worry about the performance in the beginning&lt;/strong&gt;, React is smart enough and optimizes rendering for you. Optimize for performance or re-renders only if performance becomes an issue. And only move to Redux if you feel your app needs more than a simple state management.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;Learn Immer and how it works. It's a great library  to &lt;strong&gt;modify state in an immutable way&lt;/strong&gt;. It makes life so much easier by modifying the "draft" of a state directly without the use of spread operators if the state is made of nested objects. It also comes in handy when implementing reducers with Context API. &lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If you move to Redux, use &lt;strong&gt;Redux Toolkit&lt;/strong&gt;. It's a great toolkit made by the same people who made/maintain Redux.&lt;/p&gt;

&lt;p&gt;It states following on their &lt;a href="https://redux.js.org/redux-toolkit/overview" rel="noopener noreferrer"&gt;website&lt;/a&gt;:&lt;br&gt;
&lt;em&gt;"Redux Toolkit is our official, opinionated, batteries-included toolset for efficient Redux development. It is intended to be the standard way to write Redux logic, and we strongly recommend that you use it."&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;This one's subjective I feel. Learn how to use Functional Components and Hooks effectively. All my apps are written using Functional components and Hooks. I personally feel they are &lt;strong&gt;easier to read and understand&lt;/strong&gt;, it certainly helps in avoiding the need of HOC or render props which is a plus for me. If you're starting new projects, start using Functional components and Hooks.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;Optimizing performance in React Native can be a tricky thing to do if you have lot of data to display. If you're using lists, use FlatList instead of iterating over values using map function or similar. Using Redux here can be beneficial to you here so you can avoid unnecessary re-renders. Remember, in Context API, &lt;strong&gt;using useContext within a component will re-render that component and child components everytime unless you use React.memo&lt;/strong&gt; on child components. Check out this Github &lt;a href="https://github.com/facebook/react/issues/15156" rel="noopener noreferrer"&gt;link&lt;/a&gt; to learn more. In Redux, accessing part of state using useSelector hook prevents re-rendering if that part hasn't changed. &lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;Speaking of unnecessary re-renders, learn how to use &lt;strong&gt;React.memo(), useCallback() and useMemo()&lt;/strong&gt; effectively. Learn them, understand them and use them to avoid re-renders if performance becomes a problem. If you're using Redux, learn about &lt;strong&gt;Reselect&lt;/strong&gt; library to create memoized selector functions. All of this helped me a lot in improving performance of Brisqi mobile app. If you're developing on iOS first, you might not see performance issues immediately, test it on Android. In my personal experience, an app written in React Native performs better on iOS than Android. I go by this rule of thumb, if it's performant on Android, it probably performs equally well or better on iOS, but I still test thoroughly on both platforms.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Break components into smaller components if possible&lt;/strong&gt;. Smaller components are re-usable, easier to work with when using React.memo(), easier to manage state in them and code is easier to read and maintain when you come back to it after a couple of months.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use third-party utility libraries sparingly&lt;/strong&gt;. Use them if you think you cannot reproduce that functionality on your own "reliably". For example, I wrote my own Keyboard avoiding/aware view from scratch because - 1) I could simplify it, 2) tweak it according to my needs , 3) adapt it for both Android and iOS platforms and 4) I'd avoid external dependency. I'm not saying that other solutions are not good enough, they might be and some are, but less dependency = more stability because you know the functionality in and out. &lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;For styling/convention, &lt;strong&gt;be consistent&lt;/strong&gt; with whatever you pick. Airbnb style guide can be a good starting point, however I don't follow everything they say. For example - I disagree with them on the usage of single and double quotes. I use double quotes everywhere to be consistent where as they use both single quotes and double quotes.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep things simple&lt;/strong&gt;, don't over-complicate your architecture. Add things as you go along. Similarly, don't prematurely optimize for performance, do it when it becomes an issue.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;NextJS is for websites or multi-page apps and React(CRA or manual setup) is for single page apps. I personally don't try to adapt one into another. Makes things easier that way.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Keep refactoring&lt;/strong&gt; as you find out better approaches of doing things. It's part of the learning process.&lt;/li&gt;
&lt;/ul&gt;



&lt;ul&gt;
&lt;li&gt;Keep learning, don't stop and share your knowledge with others.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Links:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow me on &lt;a href="https://twitter.com/ash_grover" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; for behind the scenes.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://brisqi.com" rel="noopener noreferrer"&gt;Brisqi&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>reactnative</category>
      <category>nextjs</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Little trick to stay motivated and beat procrastination ✨</title>
      <dc:creator>Ash G</dc:creator>
      <pubDate>Thu, 11 Feb 2021 01:53:15 +0000</pubDate>
      <link>https://forem.com/ash_grover/little-trick-to-stay-motivated-and-beat-procrastination-4118</link>
      <guid>https://forem.com/ash_grover/little-trick-to-stay-motivated-and-beat-procrastination-4118</guid>
      <description>&lt;p&gt;Imagine a ball made out of concrete. When you try to push it, it takes tremendous effort to get it rolling. To stop it from moving, you just need to keep nudging in the direction you want and it keeps rolling. You don't need to push it as hard anymore as you did when it was at rest. Now, every time you give it a nudge you keep adding a little more force to it, not too much, just a fractional amount. What happens? It starts rolling faster and faster. The more you do it, the faster it goes, and what does it take? Just a fractional amount of work. Now if you want to stop it from rolling, it takes some effort - this is where you want to be.&lt;/p&gt;

&lt;p&gt;There's a term for this - &lt;strong&gt;Momentum&lt;/strong&gt;. That concrete ball has build up some momentum. Great! now you know how to stay motivated. Kidding! Well that's the gist of it. No, Really!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What about that "tremendous effort" in the beginning? I don't want to do that, isn't there some easy way?&lt;/em&gt; Well there is, just &lt;strong&gt;don't&lt;/strong&gt; put that much effort in the beginning. Yes, you read that right. Don't put that much effort immediately in the beginning. &lt;strong&gt;Put a fractional amount. But, do it consistently.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When I say fractional amount, I mean it. Amount equivalent to the tiny spec of dust in the universe. If you do that, overtime that fractional amount is compounded and you start gaining momentum. &lt;br&gt;
When you start a new project or learn something new. It takes substantial effort to get started. The moment you think about how much you have to do, a huge boulder weighs on your mind and you may incline towards giving up before you even started. The trick? Again, put a fractional amount. &lt;/p&gt;

&lt;p&gt;Let's say you want to start getting into the habit of reading books. You read just one word on the first page and keep the book away. Next time you pick up the book, you read the next two words, then the next three.&lt;br&gt;
This process removes that heavy boulder off your mind because now it's not hard anymore. It's easy as reading few words. Similarly, you can apply this for writing, write one word, then write two more words and so on. Every time you come back, you up your fractional effort by tiny amount. &lt;/p&gt;

&lt;p&gt;Now, we know we are not perfect, there would be times when we would stop putting that effort completely. That's okay! Don't beat yourself for it. Instead, you have pat yourself on the back and tell yourself I needed that break and that you're back again. By doing this, you instantly clear up guilt from the mind and it sets you in a positive mood.  Get back up, start with the fractional amount again. I'm repeating &lt;strong&gt;fractional amount&lt;/strong&gt; over again because it's important you don't forget about it.&lt;/p&gt;

&lt;p&gt;I've been doing this since I became an indie developer and have been consistently doing it. There have been times when I had stopped working for few days. I'd lose momentum, but then I'd start again applying the same technique I mentioned above. In my case, it would be just staring at the code. Not writing. Just looking at the screen and staring at it for 10 minutes. Next time I'd come back, my mind would be thinking about the code I had been looking and I'd start gaining momentum.&lt;/p&gt;

&lt;p&gt;Start with a fractional amount, up it by a notch next time you come back and do it consistently. &lt;/p&gt;

&lt;p&gt;In case you’re wondering, I’m building &lt;a href="https://brisqi.com" rel="noopener noreferrer"&gt;Brisqi&lt;/a&gt; - a personal Kanban app. It’s what I use to plan my day, work and life in general. Feel free to check it out.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>motivation</category>
    </item>
    <item>
      <title>Git remote backups</title>
      <dc:creator>Ash G</dc:creator>
      <pubDate>Mon, 11 Jan 2021 22:47:55 +0000</pubDate>
      <link>https://forem.com/ash_grover/git-remote-backups-8kd</link>
      <guid>https://forem.com/ash_grover/git-remote-backups-8kd</guid>
      <description>&lt;p&gt;As part of my development process, I've made a habit of keeping two remote repositories for every project I work on. One remote repository is on services such as Github, Gitlab etc. and second remote is on a separate/external hard disk.&lt;/p&gt;

&lt;p&gt;It has saved me lot of hassle when I accidentally made some mistakes while committing or shouldn't have committed something in the first place and want to backtrack, and it's always good to have a backup, in case something goes wrong with your computer.&lt;/p&gt;

&lt;h4&gt;
  
  
  So here's how you do it:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Create an empty repository i.e one without a working tree.&lt;/li&gt;
&lt;li&gt;Add the empty repository as a remote from your project's git repository.&lt;/li&gt;
&lt;li&gt;Push your changes to the empty repository.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 1: Create an empty repository i.e one without a working tree
&lt;/h3&gt;

&lt;p&gt;You can create this repository anywhere you like, I usually create it on an external hard disk. Now open your terminal and run following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git init --bare /path/to/external_hdd/remote_backup.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you change the path above.&lt;/p&gt;

&lt;p&gt;The --bare flag tells git to create a repository without a working tree because we won't be working with the files directly. We will only sync our changes with it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2:  Add the empty repository as a remote from your project's git repo.
&lt;/h3&gt;

&lt;p&gt;Add the remote_backup.git as a remote so we can push changes to it, it is just how we push changes to Github or any other git service you use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote add backup /path/to/external_hdd/remote_backup.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great, you can check by running following command that the remote was added correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git remote -v
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Push your changes to the empty repository
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git push backup master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm pushing master branch here, you can push changes from any branch, just like how you would push changes to Github.&lt;/p&gt;

&lt;h4&gt;
  
  
  That's it!
&lt;/h4&gt;

&lt;p&gt;Whenever you make changes, push to both repositories.&lt;/p&gt;

&lt;p&gt;I hope this tip comes in handy, especially to beginners who are starting out. I remember when I first started using git in a professional setting few years ago, I was afraid of making mistakes, but making mistakes is the first step in mastering something. All the best!&lt;/p&gt;

</description>
      <category>git</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
