<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ayush Kaushik</title>
    <description>The latest articles on DEV Community by Ayush Kaushik (@ayushkaushik).</description>
    <link>https://dev.to/ayushkaushik</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F414784%2Fcecc842a-8acb-4302-8cc2-9311bbb50a9b.jpg</url>
      <title>DEV Community: Ayush Kaushik</title>
      <link>https://dev.to/ayushkaushik</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ayushkaushik"/>
    <language>en</language>
    <item>
      <title>Spec-Driven Refactoring: What I Learned from Handing an 800-Line Java Monolith to AI</title>
      <dc:creator>Ayush Kaushik</dc:creator>
      <pubDate>Tue, 20 Oct 2026 16:41:03 +0000</pubDate>
      <link>https://dev.to/ayushkaushik/spec-driven-refactoring-what-i-learned-handing-an-800-line-java-monolith-to-ai-57dc</link>
      <guid>https://dev.to/ayushkaushik/spec-driven-refactoring-what-i-learned-handing-an-800-line-java-monolith-to-ai-57dc</guid>
      <description>&lt;p&gt;With AI models and coding tools getting increasingly powerful, it feels developers are stuck in two contradictory narratives:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Developers are finished.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI will not replace developers, but a developer who understands how to use AI will replace one who doesn't.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Between the bold predictions and endless "X technology is dead" Youtube videos, I wanted to see what AI-assisted development looked beyond a greenfield demo.&lt;/p&gt;

&lt;p&gt;What would it feel like with a mature codebase with existing behaviour, some questionable design decisions, and most importantly a developer who had to live with the consequences. So I decided to experiment on myself...&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1 - Setting Up the experiment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Why a Brownfield Project?
&lt;/h3&gt;

&lt;p&gt;When I explored AI-assisted development, I found &lt;strong&gt;TONS&lt;/strong&gt; of information online. But most of tutorials were focused on greenfield projects.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A greenfield project starts from scratch, giving you the freedom to establish its architecture and structure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is useful, but it wasn't what I wanted. The hard part of software development isn't always creating something new. Sometimes it is opening a project two years later and asking:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Why on earth did I write it this way?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That was the experiment I wanted. So, I chose one of my first university programming assignments, written when I was still learning object-oriented programming. Having started with &lt;strong&gt;C&lt;/strong&gt;, I was more accustomed to procedural programming, and that experience influenced how I approached the assignment. It is pretty evident from how I originally wrote this assignment:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Ayush-Kaushik/estoresearch-refactored/commit/544a6c366b891d2007fb7273805c2db253be59d1" rel="noopener noreferrer"&gt;Link to original source code&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The application itself was fairly simple. It was a console-based electronic store application where a user could store and query books and electronics. When the program ended, the catalog was written to a file.&lt;/p&gt;

&lt;p&gt;Simple enough.&lt;/p&gt;

&lt;p&gt;Except the application had validation rules, product-specific behaviour, search functionality, and persistence to account for. And all of it lived in a &lt;strong&gt;single 800+ line God class&lt;/strong&gt; that drove the entire application. The code worked, but its design left plenty of room for improvement. That made it a good candidate for testing whether AI could help refactor an existing codebase without breaking its behaviour.&lt;/p&gt;

&lt;h3&gt;
  
  
  What was I Actually Trying to Learn?
&lt;/h3&gt;

&lt;p&gt;I went into the experiment with a few questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does AI-assisted development deliver a meaningful return on investment, beyond simply generating code faster?&lt;/li&gt;
&lt;li&gt;How much of my development workflow should AI actually own?&lt;/li&gt;
&lt;li&gt;Would AI become the central piece of my programming workflow or would it remain what the name suggests: &lt;strong&gt;a Co-pilot&lt;/strong&gt; (Ba dum tss!)&lt;/li&gt;
&lt;li&gt;And, of course: &lt;strong&gt;will it replace me!?&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this experiment, I used free tier of GitHub Copilot in auto mode. Mostly because I wanted to measure its usefulness before paying for it. There was another constraint that became increasingly important later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tokens&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But we'll get to that.&lt;/p&gt;

&lt;h3&gt;
  
  
  Before I Let AI Loose on the Codebase
&lt;/h3&gt;

&lt;p&gt;Luckily, I had created a README when I submitted the assignment. It documented the application's intended behaviour and gave me something valuable: &lt;strong&gt;context&lt;/strong&gt;. Back then, the README was something I wrote to avoid losing marks. Little did I know I was doing my future self a favour.&lt;/p&gt;

&lt;p&gt;Before refactoring anything, I needed a baseline to check whether the application still behaved as expected. I started by looking for &lt;strong&gt;seams&lt;/strong&gt;: places where I could isolate or control parts of the application's behaviour without rewriting the surrounding code.&lt;/p&gt;

&lt;p&gt;I learned this concept from Michael Feathers' &lt;em&gt;Working Effectively with Legacy Code&lt;/em&gt;. Seams gave me opportunities to isolate behaviour and introduce tests before making larger changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Establishing a Behavioural Baseline with Gherkin
&lt;/h3&gt;

&lt;p&gt;I chose Gherkin and Cucumber for my behavioural tests. I'd worked with Gherkin before, although not in Java, so the concepts were familiar even if the setup wasn't. Gherkin lets you describe application behaviour using a simple Given-When-Then structure. Cucumber connects those scenarios to executable tests.&lt;/p&gt;

&lt;p&gt;For example, a product search scenario might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gherkin"&gt;&lt;code&gt;  &lt;span class="kn"&gt;Scenario&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; Operator runs the program, adds a book, then searches by name
    &lt;span class="nf"&gt;Given &lt;/span&gt;a new catalog file
    &lt;span class="nf"&gt;When &lt;/span&gt;the operator starts E-Search
    &lt;span class="err"&gt;When the operator adds products with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;productID&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;year&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;          &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;price&lt;/span&gt;  &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;authors&lt;/span&gt;  &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;publisher&lt;/span&gt;       &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="nv"&gt;manufacturer&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;
      &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;book&lt;/span&gt;        &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;123456&lt;/span&gt;    &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;2023&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Learning&lt;/span&gt; &lt;span class="n"&gt;Java&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;45.99&lt;/span&gt;  &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Jane&lt;/span&gt; &lt;span class="n"&gt;Doe&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;Education&lt;/span&gt; &lt;span class="n"&gt;Press&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;              &lt;span class="p"&gt;|&lt;/span&gt;
    &lt;span class="nf"&gt;And &lt;/span&gt;the operator searches for products named &lt;span class="s"&gt;"Learning Java"&lt;/span&gt;
    &lt;span class="nf"&gt;Then &lt;/span&gt;the search result should contain 1 products
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The goal was to treat the application as a black box: provide input, observe the output and verify that the result matched the expected behaviour.&lt;/p&gt;

&lt;p&gt;Setting up the tests was another task I could have delegated to Copilot. Instead, I watched a tutorial at 2x speed and set up the project myself. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;These tests would become my baseline for evaluating the refactor. I could have asked Copilot to generate them, too, but I wanted to define the expected behaviour independently of the AI doing the refactoring. Otherwise, I risked testing the AI's interpretation of the requirements rather than the application's intended behaviour.&lt;/p&gt;

&lt;h3&gt;
  
  
  Static Analysis with SonarQube
&lt;/h3&gt;

&lt;p&gt;Behavioural tests weren't enough. They could help me detect changes in tested behaviour, but they wouldn't tell me everything about the resulting code's maintainability or static quality. I also used SonarQube to assess the code. This gave me a second perspective on the refactoring: not just whether the application still worked, but whether the code itself had improved. This was one area where I let AI assist me, &lt;strong&gt;and the results were impressive&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2 - The Experiment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Day 1: I had to figure out how to tell AI what I Actually Wanted
&lt;/h3&gt;

&lt;p&gt;This was where things became interesting. I knew what I wanted to improve but I didn't necessarily know the best implementation. That distinction turned out to be extremely important. I started researching how people were structuring AI-assisted development and eventually landed on a &lt;strong&gt;spec-driven approach&lt;/strong&gt; (spec is short for specification).&lt;/p&gt;

&lt;p&gt;Instead of telling AI: "Refactor this class.", I would define the desired outcome, the constraints, the behaviour that must remain intact, and the boundaries of the change. Then I would let AI figure out the implementation.&lt;/p&gt;

&lt;p&gt;I created a &lt;strong&gt;.spec&lt;/strong&gt; folder at the root of the project and a &lt;strong&gt;refactoring&lt;/strong&gt; section inside it. Each refactoring had a number prefix corresponding to the GitHub issue or piece of work. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;./spec/refactoring/1-extract-file-reading.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each specification followed a lightweight structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Goal

...

Current Implementation

...

Desired Implementation

...

Behaviour to Preserve

...

Acceptance Criteria

...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I kept the format flexible. Not every refactoring required every section and you'll notice that in my rafactoring files as well. Heck, even the file naming was loose, I kept the prefix consistent but the phrase that followed was for humans to quickly understand its purpose.&lt;/p&gt;

&lt;p&gt;Template wasn't the core piece. The important part was that I was starting to separate &lt;strong&gt;what I wanted&lt;/strong&gt; from &lt;strong&gt;how I wanted it implemented&lt;/strong&gt;. That was a subtle shift. And initially, I didn't fully understand it.&lt;/p&gt;

&lt;p&gt;My first attempts were messy. I was still thinking like a developer who was writing the code myself. I would describe something I wanted changed and then mentally jump ahead to the implementation. But if the point was to have AI perform the implementation, I had to stop doing that. Instead, I needed to become much better at describing the problem. I know this sounds obvious but it wasn't.&lt;/p&gt;

&lt;p&gt;The more I worked this way, the more I realized that it was an extension of what I was already doing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spending a good amount of time just thinking and defining the problem before implementing it.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;If I can't clearly describe what I want changed, how am I expecting an AI model to correctly implement it? This became one of the first major lessons from the experiment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI doesn't remove the need for clear and critical thinking. It increases the value of it.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Day 2: I Had to Stop Designing Every Detail
&lt;/h3&gt;

&lt;p&gt;This was one of the strangest parts of the experiment. I had to unlearn the reflex to design the implementation before handing the work to AI. Normally, I'd see a problem and immediately start thinking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I'll create this class, move that responsibility there, inject this dependency, change this method..."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even if Copilot was going to write the code, I was still making all the design decisions. So I started describing refactorings in terms of their intended outcome, boundaries, and behaviour that needed to remain intact. I left the implementation open where I could.&lt;/p&gt;

&lt;p&gt;I didn't bother with the traditional "As a user, I want..." format. A concise description and a refactoring specification were enough for the kind of work I was doing. The difficult part was figuring out &lt;strong&gt;which details were genuine constraints and which were simply my first idea for a solution.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;If I specified every class and method, I was effectively asking Copilot to implement a design I'd already made. If I described the desired outcome and relevant boundaries instead, it had room to propose a different approach. That didn't mean blindly accepting whatever it generated. I still had to evaluate whether its approach made sense.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The challenge wasn't just telling AI what to do. It was knowing what I needed to decide myself, and what I could leave open for AI to solve.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Day 3 - The Workflow Started Taking Shape
&lt;/h3&gt;

&lt;p&gt;As I continued, a repeatable workflow emerged:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqufgxpdg0b117nnd4pu0.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqufgxpdg0b117nnd4pu0.png" alt="AI assisted refactoring workflow" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was very different from simply asking AI to write code. The specification became the thing I iterated on. If the AI produced code I didn't like, my first instinct was no longer:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Let me fix this code."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Instead, it became:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Did I give it enough information to make the decision I wanted?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sometimes the answer was yes: the AI simply made a poor implementation choice. Sometimes the answer was no and the specification was missing an important constraint. That distinction was incredibly useful.&lt;/p&gt;

&lt;h3&gt;
  
  
  Day 4: AI Was Smart, but It Was Also Gullible
&lt;/h3&gt;

&lt;p&gt;By this point, I'd started thinking about AI differently. Copilot could understand the existing architecture, make changes across multiple files, and implement fairly substantial refactorings. But capability wasn't the same as reliability.&lt;/p&gt;

&lt;p&gt;I started thinking of it as a very smart but gullible developer. It could move quickly, generate a lot of code, and propose approaches I wouldn't have considered. But it could also confidently head in the wrong direction if it misunderstood what I wanted.&lt;/p&gt;

&lt;p&gt;My role didn't disappear. &lt;strong&gt;The work shifted.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of writing every part of the implementation myself, I spent more time understanding the architecture, evaluating design decisions, reviewing changes, and checking that existing behaviour was preserved. I also had to revisit my specifications when they left too much room for misinterpretation. In some ways, I became more involved in the system, not less. &lt;strong&gt;I was delegating implementation, not engineering judgment.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Day 5: The Process Finally Clicked
&lt;/h3&gt;

&lt;p&gt;By around Day 5, the process had started to feel natural. I was getting more comfortable breaking refactoring work into smaller changes and giving Copilot enough context to implement them without prescribing every detail.&lt;/p&gt;

&lt;p&gt;Something interesting was happening: &lt;strong&gt;the codebase was getting smaller, while the documentation was growing.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The giant &lt;strong&gt;EStoreSearch&lt;/strong&gt; class, which had originally contained a lot of responsibilities, was gradually being broken apart. Meanwhile, the specifications documenting each change and the reasoning behind it were piling up.&lt;/p&gt;

&lt;p&gt;I didn't want that documentation to become another thing I had to maintain manually. With help from AI, I worked out how to organize the project's specs and documentation into a Docusaurus site. I then set up &lt;strong&gt;GitHub Actions&lt;/strong&gt; to build the site and publish it to &lt;strong&gt;Cloudflare Pages&lt;/strong&gt; whenever changes were made. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://estoresearch.pages.dev/" rel="noopener noreferrer"&gt;Live Documentation&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The code was becoming simpler, and I was building a clearer record of how and why it was changing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One of the biggest benefits wasn't just having AI generate code faster. It was having to make my understanding of the system explicit—and leaving behind documentation that I could use long after the experiment.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/Ayush-Kaushik/estoresearch-refactored" rel="noopener noreferrer"&gt;Link to refactored code&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What didn't go according to plan
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Token Limit Problem
&lt;/h3&gt;

&lt;p&gt;Remember that I was using the free tier of GitHub Copilot. That meant I had to be selective about what I delegated.&lt;/p&gt;

&lt;p&gt;In theory, I could ask AI to analyze the entire codebase, explain the architecture, implement a change, review its own work, and explain every decision. In practice, that wasn't always worth the usage or the time. Sometimes, fixing a small mistake myself took ten seconds. Explaining it to Copilot, waiting for another response, and reviewing the change could take several minutes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI doesn't need to be involved in every step of development.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I started weighing the cost of delegating a task against the cost of doing it myself. That wasn't a failure of AI-assisted development. It was part of learning where the tool actually provided value.&lt;/p&gt;

&lt;p&gt;AI is a tool. It doesn't get bonus points for being involved in everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  Context Became a Problem
&lt;/h3&gt;

&lt;p&gt;As I became more comfortable with the workflow, I started paying more attention to the context Copilot used. I had old README files, outdated documentation, and remnants of the original architecture sitting alongside specifications describing the intended changes.&lt;/p&gt;

&lt;p&gt;Some documents described how the system used to work. Others described how I wanted it to work. Without a clear distinction, they could give the AI conflicting signals.&lt;/p&gt;

&lt;p&gt;I began cleaning up outdated documentation and thinking more carefully about which files should be treated as authoritative. A specification describing desired behaviour serves a different purpose from an implementation note, and historical documentation shouldn't automatically be treated as current guidance.&lt;/p&gt;

&lt;p&gt;I was learning that documenting a project wasn't just about recording information. It was also about making clear &lt;strong&gt;which information to trust, and for what purpose.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Garbage context can produce garbage decisions just as easily as garbage code can.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  My Tests Caught What Copilot Missed
&lt;/h3&gt;

&lt;p&gt;Even with specifications and a defined workflow, Copilot didn't always get things right. In one instance, I had explicitly documented the behaviour that needed to be preserved and the boundaries of the refactoring. Yet Copilot still produced a change that failed to account for an expected behaviour. When I questioned it, it acknowledged that it had missed the relevant documentation.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Filx44ijgle0vb4n05i21.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Filx44ijgle0vb4n05i21.png" alt="Refactoring prompt" width="800" height="638"&gt;&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmi4bku3xnk9omz1669cd.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fmi4bku3xnk9omz1669cd.png" alt="AI Response" width="800" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I reran the prompt, and it produced a correct implementation on the next attempt. But the more important part of this experience wasn't that Copilot made a mistake. It was that &lt;strong&gt;my independently written end-to-end tests caught the regression before I merged the change.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I didn't have to rely on Copilot to recognize its own mistake. I had an independent way to verify the behaviour That was the value of establishing a behavioural baseline before starting the refactoring: I could evaluate the result against expected behaviour instead of simply trusting that the generated code looked reasonable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keeping the Specs in Sync
&lt;/h3&gt;

&lt;p&gt;There was another trade-off I hadn't fully anticipated: the specifications could become stale, too. As the refactoring progressed, I had to keep the code and specifications aligned. If I changed an implementation detail without changing the intended behaviour, the specification might remain valid. But if I wanted to change what the application actually did, I needed to revisit the specification as well.&lt;/p&gt;

&lt;p&gt;That added discipline, but it also introduced friction. I couldn't write a specification once and treat it as permanent documentation. It had to evolve alongside the code.&lt;/p&gt;

&lt;p&gt;The process also made me more deliberate about behavioural changes. Rather than quietly changing what the application did while refactoring, I had to recognize that I was changing the expected behaviour and update the specification accordingly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The specification wasn't just a way to guide the implementation. It became another part of the system I had to maintain.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So, Did AI Replace Me?
&lt;/h2&gt;

&lt;p&gt;Partially, yes.&lt;/p&gt;

&lt;p&gt;AI took over parts of the work I used to do myself. It handled boilerplate, navigated the existing codebase, and turned well-defined specifications into working implementations. Tasks that would have required me to write every change by hand could now start with a conversation and a specification.&lt;/p&gt;

&lt;p&gt;But I still had to decide what was worth changing, what behavior needed to be preserved, and whether the generated code was actually an improvement.&lt;/p&gt;

&lt;p&gt;And the more I used AI, the more I realized something: &lt;strong&gt;getting code written was only one part of the job.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The harder part was understanding the system well enough to know what to ask for, giving AI the right constraints, and having independent ways to verify its work. Even my specifications became something I had to maintain. I wasn't simply handing work off; I was taking responsibility for a different set of decisions.&lt;/p&gt;

&lt;p&gt;I started this experiment wanting to understand how useful AI could be at refactoring an old codebase. I came away with a better understanding of how I wanted to approach software development itself: define the problem, make the intended behavior explicit, change one thing at a time, and verify the result.&lt;/p&gt;

&lt;p&gt;AI did take work off my plate. It also made the quality of my thinking more consequential.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It didn't eliminate the need for an engineer. It changed where I needed to be one.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;But with that being said, I would still manually program for recreational purposes just because I enjoy doing it. Sure, it may not be the most efficient use of my time because what I would spend programming 4 hours may be done in a couple of minutes or even seconds. But its the act of actively being involved in writing code, compiling, running it and seeing that it worked gives a great feeling which does get lost when AI takes over some of the steps.&lt;/p&gt;

&lt;p&gt;I was most efficient when I was performing spec driven refactoring but had most fun when I wrote the tests myself.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>softwareengineering</category>
      <category>refactoring</category>
    </item>
    <item>
      <title>Safely Collect User Feedback with Cloudflare Workers + Slack</title>
      <dc:creator>Ayush Kaushik</dc:creator>
      <pubDate>Sun, 28 Sep 2025 21:21:33 +0000</pubDate>
      <link>https://dev.to/ayushkaushik/safely-collect-user-feedback-with-cloudflare-workers-slack-1hco</link>
      <guid>https://dev.to/ayushkaushik/safely-collect-user-feedback-with-cloudflare-workers-slack-1hco</guid>
      <description>&lt;p&gt;TL;DR → Don’t expose API keys in frontend. Instead, use serverless functions (Cloudflare Workers) to safely handle user feedback and add a layer of security against bad actors.&lt;/p&gt;

&lt;h2&gt;
  
  
  So... I Revisited My Portfolio
&lt;/h2&gt;

&lt;p&gt;You know that feeling when you revisit your old projects and wonder what you were thinking? Yeah, I had that moment while reviewing my portfolio site (&lt;a href="https://dev.to/ayushkaushik/react-github-awesome-portfolio-website-3gi"&gt;React + GitHub = Professional Portfolio Website&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Upon reviewing my existing work, I discovered a glaring security risk! I injected Firebase API keys into the react app to push user feedback directly into Firestore... with &lt;strong&gt;no read and write restrictions&lt;/strong&gt;. &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%2Fmjbfx4pgxasds18lbb0s.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%2Fmjbfx4pgxasds18lbb0s.jpg" alt=" " width="575" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This meant anyone can read/ write to my FireStore without restriction. Moreover, I wasn’t really notified when new feedback was submitted, so I missed out on important messages.&lt;/p&gt;

&lt;p&gt;My goals were to make following improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remove security defect and receive notifications.&lt;/li&gt;
&lt;li&gt;The new solution must be low cost/ free since this is a hobby project.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Let's get to work 👷‍♂️🏗️
&lt;/h2&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%2F2njn9km8kar8lcxmkd2l.gif" 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%2F2njn9km8kar8lcxmkd2l.gif" alt=" " width="498" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove the vulnerable code
&lt;/h3&gt;

&lt;p&gt;I ripped out the &lt;code&gt;Contact me&lt;/code&gt; section. That's where I initialized Firebase app instance and exposed API keys via good old &lt;code&gt;REACT_APP&lt;/code&gt; route to a vulnerable Firestore instance. I also deleted the firestore project so the credentials embedded into my code cannot be misused.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Key learning: Never inject sensitive data into frontend code&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Explore options for Serverless functions
&lt;/h3&gt;

&lt;p&gt;To securely handle user feedback without exposing API keys, I explored  &lt;a href="https://blog.hubspot.com/website/serverless-functions#what-is-a-serverless-function" rel="noopener noreferrer"&gt;serverless functions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since this is a hobby project, I wanted a free solution. I started exploring different options and stumbled upon &lt;a href="https://developers.cloudflare.com/workers/" rel="noopener noreferrer"&gt;CloudFlare Workers&lt;/a&gt; which offers up to 1000,000 invocations per day &lt;a href="https://developers.cloudflare.com/workers/platform/pricing/" rel="noopener noreferrer"&gt;source&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Honestly, if my portfolio form ever reaches that many feedback or collaboration requests, I’d consider it a great problem to have — and only then would I think about paying for extra capacity. 💵💵 &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%2Fwnipr337oz5i58c1fny2.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%2Fwnipr337oz5i58c1fny2.jpg" alt=" " width="576" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;**Or if a bad actor decides to run a Denial of Service attack on my function then I'll use up my daily request limit and will have to wait for the limit to reset.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Workflow
&lt;/h3&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%2Fgsqxaler2ure4srorywk.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%2Fgsqxaler2ure4srorywk.png" alt=" " width="799" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, the game plan is, the &lt;code&gt;Contact me&lt;/code&gt; form submission invokes a serverless function that receives request, verifies the data and perform the required action. Thus, the sensitive keys remain on the server-side only, not visible to the user, making them much harder to compromise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cloudflare Worker Setup
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://developers.cloudflare.com/workers/development-testing/" rel="noopener noreferrer"&gt;Full guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also checkout my code for contact-worker: &lt;a href="https://github.com/Ayush-Kaushik/portfolio-backend/tree/main/Cloudflare/contact-worker" rel="noopener noreferrer"&gt;Contact Worker Source Code&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For testing, I followed this article to perform behavioural tests on my function locally before I could really deploy it for the world to use: &lt;a href="https://blog.cloudflare.com/workers-vitest-integration/" rel="noopener noreferrer"&gt;Behavioural tests with vitest&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To deploy the worker, I used GitHub workflows and passed the required keys via secrets.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can checkout my workflow file: &lt;a href="https://github.com/Ayush-Kaushik/portfolio-backend/blob/main/.github/workflows/deploy-workers.yml" rel="noopener noreferrer"&gt;GitHub Workflow&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With the backend ready and deployed, you can modify the Frontend to send requests to the function.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Ensure your serverless function handles preflight requests. Without this, CORS may block requests from the browser. You can check how I handled it here: &lt;a href="https://github.com/Ayush-Kaushik/portfolio-backend/blob/fa6ce246a4497ae7d250dc54e891369cc90d6b4c/Cloudflare/contact-worker/src/index.ts#L21" rel="noopener noreferrer"&gt;CORS Support&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Pass all the credentials via Dashboard as secret
&lt;/h3&gt;

&lt;p&gt;Go to Cloudflare Dashboard &amp;gt; Compute Workers &amp;gt; Workers and Pages &amp;gt; Select the worker you deployed &amp;gt; Settings &amp;gt; Variables and Secrets&lt;/p&gt;

&lt;p&gt;Define all the secrets here.&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%2Fpyofvqjug1mprdft786l.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%2Fpyofvqjug1mprdft786l.png" alt=" " width="699" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The benefit of defining secrets instead of environment variables is it doesn't get overwritten when worker is redeployed via GitHub workflow. The wrangler.toml file doesn't take precedence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Setup Slack bot and Channel
&lt;/h3&gt;

&lt;p&gt;To relay message from worker to slack, we will need a slack bot. There are tons of tutorials and videos online about the setup. Here is the one I followed: &lt;a href="https://www.youtube.com/watch?v=SbUv1nCS7a0" rel="noopener noreferrer"&gt;Send Message to Slack with a Node.js Script&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Again, you can reference my worker implementation to understand how I enabled it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Front end contact form
&lt;/h4&gt;

&lt;p&gt;The submission process remains the same. The difference lies in how the request from frontend is handled and responded to.&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%2F3e85s2c4sqd84u42p4a2.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%2F3e85s2c4sqd84u42p4a2.png" alt=" " width="800" height="558"&gt;&lt;/a&gt;&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%2Ft21auqb3fz4efru4qdvc.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%2Ft21auqb3fz4efru4qdvc.png" alt=" " width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Message received in Slack channel
&lt;/h4&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%2Fzahgsieb8bncit3v8scq.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%2Fzahgsieb8bncit3v8scq.png" alt=" " width="800" height="311"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Benefits of this approach
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;With Cloudflare workers, I have increased visibility into where the requests are originating from so I can promptly respond to bad actors and block them if required.&lt;/li&gt;
&lt;li&gt;I have more control over kind of data I accept, any malicious data can be stopped at worker before relaying it to Slack as a message.&lt;/li&gt;
&lt;li&gt;Credentials are stored as secrets so bad actors will have a hard-time deducing them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Future improvements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rate limiting is a paid feature provided by Cloudflare so I will need added protection against DDOS attacks. I will come up with my own rate limiting design to handle such cases (if they occur).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope this article gave you some insights into security practice and technologies used! &lt;/p&gt;

&lt;p&gt;Feel free to comment below if you have more ideas on improving my strategy and feedback 😊😊&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>serverless</category>
      <category>programming</category>
    </item>
    <item>
      <title>Introducing NeighborsNetwork: Your Neighborhood’s Social Hub Built on Wix!</title>
      <dc:creator>Ayush Kaushik</dc:creator>
      <pubDate>Sun, 27 Oct 2024 03:17:24 +0000</pubDate>
      <link>https://dev.to/ayushkaushik/introducing-neighborsnetwork-your-neighborhoods-social-hub-built-on-wix-3c58</link>
      <guid>https://dev.to/ayushkaushik/introducing-neighborsnetwork-your-neighborhoods-social-hub-built-on-wix-3c58</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/wix-2024-10-16"&gt;Wix Studio Challenge: Community Edition&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Community Platform
&lt;/h2&gt;

&lt;p&gt;Platform name: &lt;strong&gt;NeighborsNetwork 🏠&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In today’s digital age where everyone is digitally connected, I always wondered why shouldn't we have a dedicated digital space for neighborhoods to thrive! So, I came up with the idea of NeighborsNetwork 🏠.&lt;/p&gt;

&lt;p&gt;My aim is to create an inclusive online platform where residents of a community can connect, share information, and engage effortlessly. I will showcase how Neighbors Network was built using &lt;strong&gt;WixStudio&lt;/strong&gt;, highlighting its key features and design choices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🗣️ &lt;strong&gt;General Forum&lt;/strong&gt;&lt;br&gt;
A digital bulletin board where HOA admins and members post community-wide updates. It includes but not limited to announcing improvements, new regulations, or events. The General Forum keeps everyone in the loop.&lt;/p&gt;

&lt;p&gt;🌐 &lt;strong&gt;Community Circles&lt;/strong&gt;&lt;br&gt;
An informal space where members can create and join interest-based groups, connect on shared interests, and collaborate on projects or events. I pre-created some groups like gardening circle and neighborhood watch group but you can try it out yourself and create more!&lt;/p&gt;

&lt;p&gt;📇 Resident Directory&lt;br&gt;
A directory for residents who wish to be reachable by their neighbors. &lt;/p&gt;

&lt;p&gt;💬 Members Chat&lt;br&gt;
A one-to-one or group chat that allows members to send messages to each other.&lt;/p&gt;

&lt;p&gt;🎉 Local Events Management&lt;br&gt;
NeighborsNetwork lets members create, manage, and sign up for community events. So if you're planning neighborhood barbecue, holiday gathering, or volunteer event, create an event and let your neighbors know about it!&lt;/p&gt;

&lt;p&gt;Secure, Simple Navigation&lt;br&gt;
Just like how other famous social media platforms prioritize security, NeighborsNetwork is built with security in mind. Only registered users can access the platform, ensuring a private experience for the community.&lt;/p&gt;


&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://anonprogrammer305.wixstudio.com/neighbornet" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fstatic.wixstatic.com%2Fmedia%2F11062b_5666ab8edbab4ef08b1a9766fac59429f000.jpg%2Fv1%2Ffill%2Fw_100%2Ch_56%2Cal_c%2Cq_80%2Cusm_0.66_1.00_0.01%2Cblur_3%2Cenc_avif%2Cquality_auto%2F11062b_5666ab8edbab4ef08b1a9766fac59429f000.jpg" height="56" class="m-0" width="100"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://anonprogrammer305.wixstudio.com/neighbornet" rel="noopener noreferrer" class="c-link"&gt;
            Home | My Site
          &lt;/a&gt;
        &lt;/h2&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.wix.com%2Ffavicon.ico" width="192" height="192"&gt;
          anonprogrammer305.wixstudio.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Home Page:&lt;br&gt;
NeighborsNetwork is secure by design, preventing access to any pages without proper login.&lt;br&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%2F78jrjld9e2gup96vcpna.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%2F78jrjld9e2gup96vcpna.png" alt=" " width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simple Navigation Menu:&lt;br&gt;
Only essential menu items are displayed, ensuring a simple, intuitive navigation experience for all users.&lt;br&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%2Fc8v29qwyntml6vq2kdrc.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%2Fc8v29qwyntml6vq2kdrc.png" alt="Simple Navigation Menu Screenshot" width="799" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;General Forum:&lt;br&gt;
A dedicated space for important announcements from HOA admins to all residents, fostering open, formal discussions.&lt;br&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%2F9jju4fak66xy883nmp5g.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%2F9jju4fak66xy883nmp5g.png" alt="General Forum Screenshot" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Community Circles:&lt;br&gt;
Residents can create and join interest-based circles to meet and interact more casually.&lt;br&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%2F8clsrnb2jh6qs97k9ojh.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%2F8clsrnb2jh6qs97k9ojh.png" alt="Community Circles Screenshot" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Event Management and Signup:&lt;br&gt;
Members can organize, view, and sign up for local events with ease.&lt;br&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%2Fsrko7h9vs34n9do4xn8i.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%2Fsrko7h9vs34n9do4xn8i.png" alt="Event Management and Signup Screenshot" width="800" height="561"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Members Chat:&lt;br&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%2Fb9p937i2we1ddvdhiak1.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%2Fb9p937i2we1ddvdhiak1.png" alt="Members Chat Screenshot" width="422" height="647"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Development Journey
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Velo APIs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;GeoLocation API&lt;/strong&gt;: Most of the heavy lifting was done by no-code apps anyway but I did find some unique use cases for Velo API. First is the GeoLocation provider API. I utilized it to find users location and show them their current weather based on it.&lt;/p&gt;

&lt;p&gt;I created a custom GetWeather method in public directory which contacts an &lt;em&gt;open source weather API&lt;/em&gt; and based on the location collection from WiX API, I was able to get the correct weather. This becomes handy when users are trying to plan an event and want to see what the weather might be like!&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%2Fm0f2uza4ss78ikjj2d5v.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%2Fm0f2uza4ss78ikjj2d5v.png" alt=" " width="432" height="490"&gt;&lt;/a&gt;&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%2Fl00znk2d6z0u47o79hs1.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%2Fl00znk2d6z0u47o79hs1.png" alt=" " width="409" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Animation API:&lt;/strong&gt; I learned how to animate logos and built a small zoom in  and out animation for the logo on main menu bar. It is very subtle since I didn't want to distract user's attention from site by becoming too intrusive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wix Apps
&lt;/h3&gt;

&lt;p&gt;I'll be honest, if I were to design all the features from scratch then I would've made this submission next year 😂&lt;/p&gt;

&lt;p&gt;What I liked about Wix Studio are the wide collection of apps which require simple installation and minimal setup to become production ready.&lt;/p&gt;

&lt;p&gt;I have listed all the apps and their usages below:&lt;br&gt;
&lt;strong&gt;Wix Members Area&lt;/strong&gt;: I used this to manage user accounts, login and signup. Before knowing about menu page permissions, I tried to programmatically add the permissions. But it also allowed me to show specific pages based on user's login status.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wix Groups&lt;/strong&gt;: I used this for building Community Circles. When I was planning to build the Platform, the idea of managing community and posts seemed daunting at first. But I was able to quickly get it up and running with this app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wix Events and Tickets&lt;/strong&gt;: I used this for Events page. This is again a very feature rich app and I was able to create recurring events with ease as a demo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wix Chat&lt;/strong&gt;: I used it for members only chat feature. At first, I thought this feature only allowed site visitors to send message to the admin. But it went above and beyond and let me securely add a chat feature which only works once user logs in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wix Forum&lt;/strong&gt;: I used it for the main General Forum section. I didn't need to make much changes here as it already included features I required from  get go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wix Blogs&lt;/strong&gt;: I used it along with forums to allow users to create and post blog articles.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wix Logo Maker&lt;/strong&gt;: I used the AI feature to build the logo.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>wixstudiochallenge</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>React + GitHub = Professional Portfolio Website</title>
      <dc:creator>Ayush Kaushik</dc:creator>
      <pubDate>Thu, 26 Nov 2020 05:12:32 +0000</pubDate>
      <link>https://dev.to/ayushkaushik/react-github-awesome-portfolio-website-3gi</link>
      <guid>https://dev.to/ayushkaushik/react-github-awesome-portfolio-website-3gi</guid>
      <description>&lt;p&gt;&lt;b&gt;tldr; I have documented how to use ReactJS, SCSS, and GitHub to quickly build and host your portfolio website.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I believe that a portfolio website is an incredible way to showcase your skills and creativity. So to get inspiration for my portfolio I did what most people would do, started digging through different programming subreddits 😛&lt;/p&gt;

&lt;p&gt;After looking at countless portfolios, I found some neat examples. However, as I started building my website, I realized that there were so many aspects and requirements that I didn't plan beforehand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where to host the website (for free)?&lt;/li&gt;
&lt;li&gt;How to make it responsive with different screen sizes?&lt;/li&gt;
&lt;li&gt;How to organize information?&lt;/li&gt;
&lt;li&gt;How to make it self-updating (partially)?&lt;/li&gt;
&lt;li&gt;How to add images to my project?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most importantly how to organize the content so you could not only build the website but extend it as you add new and exciting projects to your list of accomplishments 🚀&lt;/p&gt;

&lt;p&gt;This motivated me to document my website building process from start to finish and hopefully, it'll give you some ideas to start your own portfolio website. &lt;/p&gt;

&lt;h1&gt;
  
  
  Pre-requisites
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;GitHub account&lt;/li&gt;
&lt;li&gt;CSS experience as it'll help you to grasp SCSS faster&lt;/li&gt;
&lt;li&gt;ReactJs knowledge&lt;/li&gt;
&lt;li&gt;Dropbox account for image hosting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you need help with any of the above, I have linked some resources and video tutorials below 🤝&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;p&gt;Step 1: Setup React Project&lt;br&gt;
Step 2: Setup GitHub Repository&lt;br&gt;
Step 3: Setup dropbox for hosting&lt;br&gt;
Step 4: Organize Components&lt;br&gt;
Step 5: Styling with SASS&lt;br&gt;
Step 6: Deploy for free&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Setup React Project
&lt;/h2&gt;

&lt;p&gt;Run the following command to create-react-app:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npx create-react-app portfolio&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;This will setup the complete react project with all the required files. To run your development server, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm run start&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;Usually, your server opens a tab on your default browser and runs the application on &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Awesome! Now lets set up our repository so we can use GitHub pages to host our website and keep our work someplace safe 🔒&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Setup GitHub Repository
&lt;/h2&gt;

&lt;p&gt;Setting up the repository is pretty straight forward. Make sure you flag the repository as &lt;code&gt;public&lt;/code&gt; since it'll be needed for hosting.&lt;/p&gt;

&lt;p&gt;Follow this &lt;a href="https://docs.github.com/en/free-pro-team@latest/github/getting-started-with-github/create-a-repo" rel="noopener noreferrer"&gt;link&lt;/a&gt; for setup.&lt;/p&gt;

&lt;p&gt;Now link it to the React project that we set up locally. Using terminal, &lt;code&gt;cd&lt;/code&gt; into the project and enter: &lt;br&gt;
&lt;code&gt;git init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, get the link for your newly created git repository and enter the following command (replace the URL with your repository URL):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git remote add origin git@github.com:username/new_repo&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will connect your local portfolio instance to a remote repository. At this point, you can start pushing your code and we'll utilize the &lt;code&gt;gh-pages&lt;/code&gt; npm package to build and deploy the portfolio website on GitHub pages.&lt;/p&gt;

&lt;p&gt;If you have any questions, please feel free to comment below and we can figure out any issues 🙂&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Setup Dropbox for hosting images
&lt;/h2&gt;

&lt;p&gt;You can totally skip this step if you are planning on using a different method for hosting images. I was trying to find something free and stumbled upon an efficient way of using dropbox for creating a publicly accessible URL for my images.&lt;/p&gt;

&lt;p&gt;Here are the steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log into your dropbox account&lt;/li&gt;
&lt;li&gt;Create a new folder&lt;/li&gt;
&lt;li&gt;Now upload your images in this folder&lt;/li&gt;
&lt;/ul&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%2Fi%2Fv90jr12nbtmdv73c4bbe.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%2Fi%2Fv90jr12nbtmdv73c4bbe.png" alt="Alt Text" width="800" height="25"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click on the ellipsis as shown in the image and click share:&lt;/li&gt;
&lt;/ul&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%2Fi%2F059vj75teab9haj3lq3n.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%2Fi%2F059vj75teab9haj3lq3n.png" alt="Alt Text" width="359" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A pop-up will appear with a sharing link at the bottom. Leave it to default options ('anyone can view') and copy the sharable link.&lt;/li&gt;
&lt;/ul&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%2Fi%2F3qlcoi2otuja4krz7uul.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%2Fi%2F3qlcoi2otuja4krz7uul.png" alt="Alt Text" width="538" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We're almost there, now if you enter this link in a new tab, you'll notice that the image is opened in dropbox viewer but we need a raw image that could be used on the website.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;https://www.dropbox.com/s/shdjsdhjsdjshdsjh/0.jpeg?dl=0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the shareable URL replace &lt;code&gt;?dl=0&lt;/code&gt; with &lt;code&gt;?raw=1&lt;/code&gt; and visit the link again. You'll notice its actual raw image being displayed! 💃&lt;/p&gt;

&lt;p&gt;You can upload as many images and use their links in the &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tag of your react application to render images in your portfolio!&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 4: Organize Components
&lt;/h2&gt;

&lt;p&gt;I used the following directory layout to organize the components and styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src
│
└───components
└───constants
└───context
└───pages
└───styles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;components: This directory contains components specific to each page/ view&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;constant: The information that remains somewhat similar unless small changes are required is placed here. For example, I placed constant information for &lt;code&gt;experience&lt;/code&gt; in the following format:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const EXPERIENCE = [
    {
        "workTitle": "",
        "description": [],
        "timeline": "",
        "image": "",
        "company": {
            "name": "",
            "link": ""
        }
    },
    {
        "workTitle": "",
        "description": [],
        "timeline": "",
        "image": "",
        "company": {
            "name": "",
            "link": ""
        }
    }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I organized data into JSON to render this information easily in the presentational components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;context: All the context files were organized in this directory. One of the main reasons I used React context hooks is to prevent the need for passing information (props) from parent to child to grandchild to great-grandchild..... 🥱😴&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; * I used to pass information from one component to the next when was a rookie, but this made data handling in my projects a nightmare. Instead, I have now started using context hooks. For a formal explanation follow this &lt;a href="https://reactjs.org/docs/context.html" rel="noopener noreferrer"&gt;link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; * Now that you have read about context and how it's used, I'll show you how I used it to make my program self-updating in the next section.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;pages: I used this directory to organize main views of the website - such as projects, experience, contact me, etc. So this is a large container that holds presentational components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;styles: Since I used SCSS for styling, I created different files that hold information to style the functional components.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Styling with SASS 💁‍♀️💁‍♂️
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Very Important: Always design for mobile-first, You'll thank yourself later!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The reason why I decided to switch to SASS from CSS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It became very difficult to manage and organize the CSS code as the project size increased&lt;/li&gt;
&lt;li&gt;I was failing the DRY (Don't Repeat Yourself) principle as the number of components increased since they used the same CSS classes with minor changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;SASS&lt;/code&gt; is a preprocessor scripting language that is compiled and interpreted into Cascading stylesheets. Here are the benefits that I found:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I was able to split the CSS code into more meaningful files and import them into a single index.scss file&lt;/li&gt;
&lt;li&gt;I used variables to define values for colors, font-size etc. in the index.scss and used it in other files. This helped me to quickly make changes since there was a single point of change now.&lt;/li&gt;
&lt;/ul&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%2Fi%2Fvo5cu8x7a6tstfg2jntd.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%2Fi%2Fvo5cu8x7a6tstfg2jntd.png" alt="Alt Text" width="580" height="950"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best part, It forced me to plan out how to style my components and follow the DRY principle. For example, I used _Layout.scss, _Card.scss where I defined the common layout which was used in different views.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I would highly recommend reading the &lt;a href="https://sass-lang.com/documentation/syntax" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Deploy our Portfolio
&lt;/h3&gt;

&lt;p&gt;I was finding a way to deploy my website to GitHub pages and came across this &lt;a href="https://dev.to/yuribenjamin/how-to-deploy-react-app-in-github-pages-2a1f"&gt;post&lt;/a&gt; written by Ibrahim Ragab.&lt;/p&gt;

&lt;p&gt;Hence, I used the &lt;a href="https://www.npmjs.com/package/gh-pages" rel="noopener noreferrer"&gt;gh-pages&lt;/a&gt; npm package to deploy the application on GitHub.&lt;/p&gt;

&lt;p&gt;** Important: I created my website without react-routers, so if you are planning to add different pages, you might need to make changes to &lt;code&gt;gh-pages&lt;/code&gt; configuration accordingly **&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install the gh-pages npm package as a dev dependency:
&lt;code&gt;npm install --save-dev gh-pages&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Update your scripts in package.json to add two more key-value pairs: &lt;code&gt;predeploy and deploy&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&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%2Fi%2Fv8kwfzjuqovdpgn3v58h.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%2Fi%2Fv8kwfzjuqovdpgn3v58h.png" alt="Alt Text" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Test out if our react-app deploys as expected.
&lt;code&gt;npm run deploy&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This will build our react application and deploy it on the public GitHub repository under gh-pages branch.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Now go to your remote repository and go to settings and scroll down all the way to ** GitHub Pages ** section. You will see the source dropdown. Select the dropdown and choose &lt;code&gt;gh-pages&lt;/code&gt; branch to serve the latest built code to your GitHub pages.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you go to the link, the website should be visible. Now, you can work on your website locally and redeploy it to add new updates. &lt;/p&gt;

&lt;p&gt;** Make sure you push your work to one of the other branches **&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How to make your website self-updating?
&lt;/h3&gt;

&lt;p&gt;I am sure as you learn new skills and create new and exciting projects, You would want to update your website to showcase these projects. What if I told you, your website will automatically update itself to show your new projects and articles 👽👽&lt;/p&gt;

&lt;p&gt;Here's how I did it for mine:&lt;/p&gt;

&lt;h3&gt;
  
  
  Showcasing GitHub projects:
&lt;/h3&gt;

&lt;p&gt;GitHub has (API)[&lt;a href="https://developer.github.com/v3/" rel="noopener noreferrer"&gt;https://developer.github.com/v3/&lt;/a&gt;] that can be used to extract different information about our public repositories (in JSON format). I created a ProjectContext file that accesses the &lt;code&gt;projects&lt;/code&gt; endpoint using a GET Axios request. Then I passed down this information via the ProjectProvider. The functional component takes this data, loop through it and display is nicely using SCSS style: &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%2Fi%2Fls5g5ji145kwvagt4jtf.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%2Fi%2Fls5g5ji145kwvagt4jtf.png" alt="Alt Text" width="800" height="679"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Showcasing Dev.To Articles
&lt;/h3&gt;

&lt;p&gt;Same as GitHub API, DEV.to also has an API that can be used to brief details about an article. I created another context file and provided information to my functional components. &lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Zz6eOVaaelI" rel="noopener noreferrer"&gt;SASS tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Ke90Tje7VS0&amp;amp;t=2968s" rel="noopener noreferrer"&gt;React tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=5LrDIWkK_Bc" rel="noopener noreferrer"&gt;React useContext hook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/nataliedeweerd/how-to-use-the-dev-to-api-5gl3"&gt;How to use dev.to API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.github.com/v3/" rel="noopener noreferrer"&gt;GitHub API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>portfolio</category>
      <category>react</category>
      <category>github</category>
      <category>css</category>
    </item>
    <item>
      <title>Firebase Auth + React</title>
      <dc:creator>Ayush Kaushik</dc:creator>
      <pubDate>Sun, 11 Oct 2020 21:36:32 +0000</pubDate>
      <link>https://dev.to/ayushkaushik/firebase-auth-react-1dj</link>
      <guid>https://dev.to/ayushkaushik/firebase-auth-react-1dj</guid>
      <description>&lt;p&gt;Hi! I recently learned how to enable authentication in my React application via Firebase. The process is somewhat straight forward once you connect the dots but it took me some time to find those dots and connection :p&lt;/p&gt;

&lt;p&gt;So I thought to myself, why not document it so you can also enable authentication in your application! :)&lt;/p&gt;

&lt;p&gt;I would really appreciate your feedback to improve this post. Lets get started: &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Setup Firebase Project
&lt;/h3&gt;

&lt;p&gt;Before integrating Firebase into our React project, I'll go over configuring a project in Firebase for Authentication. Go to &lt;a href="https://firebase.google.com/" rel="noopener noreferrer"&gt;Firebase&lt;/a&gt; and click on &lt;code&gt;Go to console&lt;/code&gt; button on top right corner.&lt;/p&gt;

&lt;p&gt;You'll be redirected to your list of firebase projects. Create a new project. I'll name mine "test".&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%2Fi%2Fp7ftiquekxk4q8krl01m.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%2Fi%2Fp7ftiquekxk4q8krl01m.png" alt="Create new project" width="660" height="592"&gt;&lt;/a&gt;&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%2Fi%2Fg8qy3iy4grp41l3hwikf.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%2Fi%2Fg8qy3iy4grp41l3hwikf.png" alt="Naming project" width="800" height="588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After entering a suitable name for your project, click &lt;code&gt;Continue&lt;/code&gt; and you'll be redirected to &lt;code&gt;enable Google analytics&lt;/code&gt; page. It's up to you to enable/disable this as it does not affect our setup.&lt;/p&gt;

&lt;p&gt;Now wait for Firebase to perform its magic and setup your project...&lt;/p&gt;

&lt;p&gt;When the project is ready, we'll be redirected to the project console. On the sidebar, you'll see a number of menu items:&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%2Fi%2F4ou647k2jas0muomjplo.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%2Fi%2F4ou647k2jas0muomjplo.png" alt="Alt Text" width="494" height="846"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select Develop menu item and you'll see a list of sub-menu items:&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%2Fi%2Fqxwj4vhopa0dh9rvjzn7.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%2Fi%2Fqxwj4vhopa0dh9rvjzn7.png" alt="Alt Text" width="458" height="718"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To enable authentication, we'll need to setup a sign-in method. Click on &lt;code&gt;authentication&lt;/code&gt; menu-item and you'll be redirected to Authentication page. Click on &lt;code&gt;Sign-in method&lt;/code&gt; and you'll be directed to the sign-in tab:&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%2Fi%2Fgil9gd08ctw7bj6tq5tz.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%2Fi%2Fgil9gd08ctw7bj6tq5tz.png" alt="Alt Text" width="800" height="615"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll notice that all the sign-in methods are disabled. We'll enable &lt;code&gt;Email/Password&lt;/code&gt; method for our React application. When you scroll down, you'll notice the Authorized domain section where you can add domains for oAuth redirect. &lt;/p&gt;

&lt;p&gt;and thats it! we have setup our project but how will we connect this project to our React application?&lt;/p&gt;

&lt;p&gt;Glad you asked, that'll be done by fetching the configuration details. Before we do that, we'll need to setup a web app in firebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Setup Firebase Web-App
&lt;/h3&gt;

&lt;p&gt;To setup the web app, we'll need to go to homepage of our console, click on the &lt;code&gt;Project Overview&lt;/code&gt; menu-item in the side-bar.&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%2Fi%2Fbtsy5x7in2fnxlcvnll0.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%2Fi%2Fbtsy5x7in2fnxlcvnll0.png" alt="Alt Text" width="476" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the main dashboard page, select the &lt;code&gt;&amp;lt;/&amp;gt;&lt;/code&gt; button as highlighted below:&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%2Fi%2Fcc83exvjzw7b9cstw4g6.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%2Fi%2Fcc83exvjzw7b9cstw4g6.png" alt="Alt Text" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Clicking on this button will slide-in a window with title: &lt;code&gt;Add Firebase to your web app&lt;/code&gt;. I'll name mine &lt;code&gt;test-app&lt;/code&gt;. If you would like to use firebase for hosting your application, you can check the box. However, I'll not cover that step in this post.&lt;/p&gt;

&lt;p&gt;When you click on &lt;code&gt;Register app&lt;/code&gt; button, you'll be presented with two script tags containing important configuration that'll help us to connect the firebase project to the React application.&lt;/p&gt;

&lt;p&gt;It'll look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- The core Firebase JS SDK is always required and must be listed first --&amp;gt;
&amp;lt;script src="https://www.gstatic.com/firebasejs/7.23.0/firebase-app.js"&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries --&amp;gt;

&amp;lt;script&amp;gt;
  // Your web app's Firebase configuration
  var firebaseConfig = {
    apiKey: "XXXXXX",
    authDomain: "XXXXX",
    databaseURL: "XXXXXX",
    projectId: "XXXXXX",
    storageBucket: "XXXXXX",
    messagingSenderId: "XXXXXX",
    appId: "XXXXXXX"
  };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect! Now we have the necessary credentials needed to enable firebase authentication in our React app. Next up we'll configure our React app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Enable Firebase Auth in React App
&lt;/h3&gt;

&lt;p&gt;I'll skip over the steps where you have done &lt;code&gt;create-react-app&lt;/code&gt;, created your application and can do &lt;code&gt;npm run start&lt;/code&gt; to get it running.&lt;/p&gt;

&lt;p&gt;We'll start with installing the firebase package. Use the terminal to go inside the root directory of your react app and type following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   npm install --save firebase
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3a: Setup .env file
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Create a .env file and place it in the root directory of your React project. 
&lt;strong&gt;Important:&lt;/strong&gt; Make sure you have added the file in .gitignore since the content of .env file is confidential.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REACT_APP_API_KEY=XXX
REACT_APP_AUTH_DOMAIN=XXX
REACT_APP_DATABASE_URL=XXX
REACT_APP_PROJECT_ID=XXX
REACT_APP_STORAGE_BUCKET=XXX
REACT_APP_MESSAGING_SENDER_ID=XXX
REACT_APP_APP_ID=XXX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value of these keys is the configuration data that we collected from &lt;code&gt;step 2&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3b: Create Firebase Component
&lt;/h4&gt;

&lt;p&gt;Create a component named Firebase.js that will be used to initialize our Firebase instance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import firebase from "firebase/app";
import "firebase/auth";

const config = {
    apiKey: process.env.REACT_APP_API_KEY,
    authDomain: process.env.REACT_APP_AUTH_DOMAIN,
    databaseURL: process.env.REACT_APP_DATABASE_URL,
    projectId: process.env.REACT_APP_PROJECT_ID,
    storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
    messagingSenderId: process.env.REACT_APP_MESSAGING_SENDER_ID,
};

firebase.initializeApp(config);
export const auth = firebase.auth();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3c: Utilize Firebase auth via React Context
&lt;/h3&gt;

&lt;p&gt;React allows sharing of data globally among component tree via context. We'll create an Auth context component that'll handle all the functions related to authentication: Sign-in, Sign-out and Sign-up&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, {createContext, useEffect, useState} from 'react';
import {auth} from "../components/Firebase";

export const AuthContext = createContext(null);

export const AuthProvider = (props) =&amp;gt; {
    const [userState, setUserState] = useState(null);
    const [authPending, setAuthPending] = useState(true);

    const signIn = (username, password) =&amp;gt; {
        return auth.signInWithEmailAndPassword(username, password);
    }

    const signUp = (username, password) =&amp;gt; {
        return auth.createUserWithEmailAndPassword(username, password);
    }

    const signOut = () =&amp;gt; auth.signOut();

    useEffect(() =&amp;gt; {
        return auth.onAuthStateChanged((userAuth) =&amp;gt; {
            console.log(userAuth);
            setUserState(userAuth);
            setAuthPending(false);
        })
    }, [])

    if (authPending) {
        return (
            &amp;lt;div style={{
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
                height: "100vh"}}
            &amp;gt;
                &amp;lt;div&amp;gt;Authentication in progress&amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
        )
    }

    return (
        &amp;lt;AuthContext.Provider value={{
            signIn: signIn,
            signUp: signUp,
            signOut: signOut,
            userState: userState
        }}&amp;gt;
            {props.children}
        &amp;lt;/AuthContext.Provider&amp;gt;
    )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we need to provide the global data and functions via &lt;code&gt;AuthProvider&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;This is our index.js file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import {AuthProvider} from "./context/AuthContext";

ReactDOM.render(
    &amp;lt;React.StrictMode&amp;gt;
        &amp;lt;AuthProvider&amp;gt;
            &amp;lt;App/&amp;gt;
        &amp;lt;/AuthProvider&amp;gt;
    &amp;lt;/React.StrictMode&amp;gt;,
    document.getElementById("root")
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! Now you can use these functions in your application for authentication.&lt;/p&gt;

</description>
      <category>react</category>
      <category>firebase</category>
      <category>authentication</category>
      <category>stepbystep</category>
    </item>
  </channel>
</rss>
