Cursor AI and My Coding Workflow

Cursor AI and My Coding Workflow

Cursor AI and My Coding Workflow

Hey everyone, Hugo here!

As a developer at Money Forward, I'm always looking for ways to optimize my workflow and become more efficient. Recently, I stumbled upon Cursor AI, and let me tell you, it’s been a total game-changer. I wanted to share my experience and dive into the technical aspects of how it's impacted my daily work.

Before Cursor AI, I often felt bogged down. Debugging those gnarly, edge-case bugs? Hours. Setting up a boilerplate for new features? Tedious. Keeping up with the latest best practices and framework updates? Exhausting. I’d find myself constantly switching between my IDE, documentation, and Stack Overflow, trying to piece everything together. It felt like my productivity was being chipped away, bit by bit.

Example: Write a method to count number of empty seats on an airplane

class Airplane
 def initialize(total_seats)
   @seats = Array.new(total_seats, nil)  # Initialize all seats as empty
 end
 
 def count_empty_seats
   empty_seats = 0
   @seats.each do |seat|
     empty_seats += 1 if seat.nil?
   end
   empty_seats
 end
 
 def assign_passenger(seat_number, passenger_name)
   @seats[seat_number] = passenger_name if seat_number < @seats.length
 end
end

# Example usage:
airplane = Airplane.new(10)  # Create an airplane with 10 seats
airplane.assign_passenger(0, "John")
airplane.assign_passenger(2, "Mary")
puts "Number of empty seats: #{airplane.count_empty_seats}"  # Output: Number of empty seats: 8

This approach uses straightforward logic that’s easy to follow and doesn’t involve advanced Ruby features, design patterns, or complex structures.

After applying AI suggestions, we see improvements such as:

  • Applying SOLID principles

  • Leveraging Ruby-specific features

  • Adding proper error handling

  • Ensuring data consistency (e.g., seat count starting from 1)

The resulting code structure is as follows:


require 'forwardable'
module Airline
 class Seat
   attr_reader :number, :passenger
   def initialize(number)
     @number = number
     @passenger = nil
   end
   def assign_passenger(passenger_name)
     raise ArgumentError, 'Passenger name cannot be empty' if passenger_name.to_s.strip.empty?
     raise SeatError, 'Seat is already occupied' if occupied?
     @passenger = passenger_name
     self
   end
   def empty?
     @passenger.nil?
   end
   def occupied?
     !empty?
   end
   def to_s
     "Seat #{number}: #{occupied? ? passenger : 'Empty'}"
   end
 end
 class Airplane
   extend Forwardable
   def_delegators :@seats, :size, :each, :map
   class SeatError < StandardError; end
   def initialize(total_seats)
     raise ArgumentError, 'Total seats must be positive' unless total_seats.positive?
     @seats = (1..total_seats).map { |number| Seat.new(number) }
   end
   def count_empty_seats
     @seats.count(&:empty?)
   end
   def count_occupied_seats
     @seats.count(&:occupied?)
   end
   def assign_passenger(seat_number, passenger_name)
     seat = find_seat(seat_number)
     seat.assign_passenger(passenger_name)
   rescue SeatError => e
     handle_seat_error(e, seat_number)
   end
   def seat_status(seat_number)
     find_seat(seat_number).to_s
   end
   def available_seats
     @seats.select(&:empty?).map(&:number)
   end
   def occupied_seats
     @seats.select(&:occupied?).map { |seat| [seat.number, seat.passenger] }.to_h
   end
   def to_s
     "Airplane with #{size} seats (#{count_empty_seats} empty, #{count_occupied_seats} occupied)"
   end
   private
   def find_seat(seat_number)
     @seats[seat_number - 1] || raise(SeatError, "Invalid seat number: #{seat_number}")
   end
   def handle_seat_error(error, seat_number)
     case error
     when SeatError
       puts "Error assigning seat #{seat_number}: #{error.message}"
     else
       raise error
     end
   end
 end
end
Usage:
begin
 # Create an airplane with 10 seats
 airplane = Airline::Airplane.new(10)
 
 # Assign some passengers
 airplane.assign_passenger(1, "John Doe")
 airplane.assign_passenger(3, "Jane Smith")
 
 # Get various information
 puts airplane.to_s
 puts "\nAvailable seats: #{airplane.available_seats.join(', ')}"
 puts "\nOccupied seats:"
 airplane.occupied_seats.each do |seat_number, passenger|
   puts "  #{seat_number}: #{passenger}"
 end
 
 # Try to assign to an occupied seat
 airplane.assign_passenger(1, "Bob Wilson")
 
 # Try to assign to an invalid seat
 airplane.assign_passenger(11, "Invalid Seat")
rescue StandardError => e
 puts "Error: #{e.message}"
end

The code was generated by Cusor AI

This implementation is more robust, maintainable, and follows Ruby best practices. It's suitable for a production environment and can be easily extended with additional features like:

  • Seat classes (economy, business, first)

  • Passenger information management

  • Flight scheduling

  • Seat pricing

  • Reservation system

The code is also improved in the following areas:

  • Better testability

  • Follows the principle of least surprise

  • Enhanced readability and maintainability

The Moment of Discovery: Diving into Cursor AI

I remember seeing Cursor AI mentioned in a developer forum. I was skeptical at first. Another AI tool making big promises? I’d seen plenty of those. But something about it piqued my interest, and I decided to take the plunge. I downloaded it, integrated it with my VS Code setup, and started experimenting.

Cursor AI Code Editor | Paul Stamatiou

Logo of Cursor AI

1. Code Quality: From Buggy to Bulletproof

Cursor AI’s real-time code analysis is incredible. It catches syntax errors, suggests optimizations, and even points out potential security vulnerabilities I might have missed. It’s like having a senior developer constantly doing code reviews alongside me. I've noticed a significant drop in the number of runtime errors and a substantial improvement in the maintainability of my code.

Before:

def calculate_total
 sum = 0
 items.each do |item|
   sum += item.price * item.quantity
 end
 sum
end

After (with Cursor AI's suggestions):

def calculate_total
 items.sum { |item| item.price * item.quantity }
end

2. Time Savings: Automating the Tedious Tasks

Generating test stubs, writing API documentation, refactoring large blocks of code—these tasks used to eat up a huge chunk of my time. Now, Cursor AI handles a lot of this. For example, I can ask it to “generate unit tests for this function,” and it provides a solid starting point. This has freed up my time to focus on more complex logic and problem-solving.

Example: Method to find max number in an array

# The method finds max number in array
def find_max(arr)
 arr.max
end
The unit-test that Cursor AI suggests:
require 'rspec'
# Test suite
RSpec.describe 'find_max' do
 it 'returns the maximum for typical cases' do
   expect(find_max([1, 2, 3])).to eq(3)
   expect(find_max([-1, -5, -2])).to eq(-1)
 end
 it 'handles duplicate and float values' do
   expect(find_max([5, 5, 3])).to eq(5)
   expect(find_max([1.5, 2.7, 2.9])).to eq(2.9)
 end
 it 'raises an error for invalid input' do
   expect { find_max([]) }.to raise_error(NoMethodError)
   expect { find_max(nil) }.to raise_error(NoMethodError)
 end
end

3. Productivity Boost: Navigating with Ease

The AI-powered code navigation is stellar. I can quickly jump to function definitions, find related code, and understand the dependencies between different parts of my project. This has significantly reduced the time I spend just trying to understand the codebase. Plus, the smart code suggestions have helped me explore new patterns and techniques, pushing me beyond my usual coding habits.

Example: ShoppingCart

class ShoppingCart
 attr_reader :items, :total
 def initialize
   @items = []
   @total = 0
 end
 # Add an item to the cart
 def add_item(item)
   @items << item
   calculate_total
 end
 # Remove an item from the cart
 def remove_item(item)
   @items.delete(item)
   calculate_total
 end
 # Calculate the total price
 def calculate_total
   @total = @items.sum { |item| item[:price] }
 end
 # Apply a discount to the total
 def apply_discount(percentage)
   @total = @total * (1 - percentage / 100.0)
 end
end

Usage:

def run_example
 # Create a new shopping cart
 cart = ShoppingCart.new
 # Add some items
 cart.add_item({ name: "Apple", price: 1.99 })
 cart.add_item({ name: "Banana", price: 0.99 })
 cart.add_item({ name: "Orange", price: 1.49 })
 # Show initial total
 puts "Initial total: $#{cart.total}"
 # Apply a 10% discount
 cart.apply_discount(10)
 puts "Total after 10% discount: $#{cart.total}"
 # Remove an item
 cart.remove_item({ name: "Banana", price: 0.99 })
 puts "Total after removing banana: $#{cart.total}"
end
# Run the example
run_example

4. Learning and Growth: Deepening My Knowledge

Cursor AI doesn’t just give me the answer; it often explains why it’s suggesting a particular solution. This has been invaluable for my learning. I've been able to dive deeper into the intricacies of the frameworks and languages I use. It’s like having a tutor on demand. I've discovered new features and best practices I wasn’t even aware of before.

Example: Student

class Student
 # Using attr_accessor instead of separate attr_reader and attr_writer
 # This is a Ruby best practice for simple getter/setter methods
 attr_accessor :name, :grades
 def initialize(name)
   @name = name
   @grades = []
 end
 # Method to add a grade with validation
 def add_grade(grade)
   return false unless grade.between?(0, 100)
   
   @grades << grade
   true
 end
 # Calculate average grade using Ruby's built-in methods
 def average_grade
   return 0 if @grades.empty?
   
   @grades.sum.to_f / @grades.length
 end
 # Get letter grade based on average
 def letter_grade
   case average_grade
   when 90..100 then 'A'
   when 80..89  then 'B'
   when 70..79  then 'C'
   when 60..69  then 'D'
   else 'F'
   end
 end
end

Usage:

def run_student_example
 # Create a new student
 student = Student.new("John Doe")
 # Add some grades
 puts "Adding grades..."
 student.add_grade(85)  # Valid grade
 student.add_grade(92)  # Valid grade
 student.add_grade(105) # Invalid grade (will be rejected)
 student.add_grade(78)  # Valid grade
 # Display results
 puts "\nStudent: #{student.name}"
 puts "Grades: #{student.grades.join(', ')}"
 puts "Average: #{student.average_grade.round(2)}"
 puts "Letter Grade: #{student.letter_grade}"
end
# Run the example
run_student_example

5. Collaboration: Enhancing Team Communication

I’ve found that my code reviews have become much more efficient. With Cursor AI helping me write clearer comments and generate more comprehensive documentation, my teammates can understand my code faster. This has led to more productive discussions and fewer misunderstandings.

Technical Recommendations and Thoughts

For developers who want to:

  • Improve code quality and reduce bug

  • Automate tedious tasks and save time

  • Enhance code navigation and project understanding

  • Deepen their technical knowledge

  • Improve team collaboration

I strongly recommend giving Cursor AI a try. It's been an invaluable tool in my technical arsenal, and I think it could be for you too. If you’re using VS Code, the integration is seamless.

Final Thoughts

Cursor AI has not only changed my workflow but also how I approach coding. I’m more confident, more efficient, and more excited about the work I do. It’s been a powerful ally in my journey as a developer, and I'm eager to see how it evolves in the future. 

For more information, let's Like & Follow MFV sites for updating blog, best practices, career stories of Forwardians at:

Facebook: https://www.facebook.com/moneyforward.vn 

Linkedin: https://www.linkedin.com/company/money-forward-vietnam/ 

Youtube: https://www.youtube.com/channel/UCtIsKEVyMceskd0YjCcfvPg   

More like this

Tech.IT Forward #4 - Topic 2: Measuring and Improving  Development Process Effectiveness
Dec 20, 2024

Tech.IT Forward #4 - Topic 2: Measuring and Improving Development Process Effectiveness

Mastering the ISTQB Foundation Level: Essential Tips and Tricks
Nov 07, 2024

Mastering the ISTQB Foundation Level: Essential Tips and Tricks

Bug Bash? How To Run It?
Jun 15, 2022

Bug Bash? How To Run It?