Make It Work, Make It Right, Make It Fast: How We Built Only Make Waves’ Digital Music E-Commerce Platform (Part 3)

Welcome to Part 3 of our technical series on building Only Make Waves’ digital music e-commerce platform. In Part 1, we adopted the YAGNI principle to lay a simple and maintainable foundation. Part 2 walked through scaling that foundation to handle traffic, file storage, and global reach. Now, in Part 3, we focus on the refinement phase: Make it work, make it right, and make it fast.

This article covers how we debugged edge cases, improved architecture, hardened security, reduced latency, and prepared for continuous delivery. Let’s get into the deep engineering work that turns a good platform into a great one.

Make It Work: Eliminating Edge Case Failures

Improving Purchase Reliability

During heavy usage, we observed rare failures where users would be charged but not receive the music files. We refactored the purchase process to be idempotent and transactional:

def create_purchase
  Purchase.transaction do
    purchase = Purchase.create!(user: current_user, product: product)
    Stripe::Charge.create!(...)
    purchase.deliver_files!
  end
end

Using ActiveRecord::Base.transaction ensured that database and payment actions remained consistent.

Detecting Failures with Observability

We integrated Sentry for exception tracking and Datadog APM for performance metrics. This gave us real-time alerts for uncaught exceptions, slow queries, and failed jobs:

Sentry.capture_exception(e) if e.is_a?(StandardError)

Make It Right: Improving Code Quality & Architecture

Refactoring Domain Logic

Our business logic had begun to leak into controllers. We adopted the Service Object pattern to isolate responsibilities:

class PurchaseProcessor
  def initialize(user, product)
    @user = user
    @product = product
  end

  def call
    # transactionally create purchase
    # process payment
    # deliver files
  end
end

This separation made testing easier and improved code clarity.

Adding Contract Tests for APIs

As our frontend and mobile clients grew, we introduced contract testing using Pact to ensure API stability:

Pact.provider_states_for 'Music Store Frontend' do
  provider_state 'a product exists' do
    set_up do
      Product.create!(title: 'Ocean Waves', price: 9.99)
    end
  end
end

Make It Fast: Advanced Optimizations

Using Edge Caching with CloudFront

To reduce load times, we configured CloudFront to cache song previews and album art at edge locations:

{
  "PathPattern": "/assets/*",
  "ForwardedValues": {
    "QueryString": false,
    "Cookies": { "Forward": "none" }
  }
}

This dropped our average asset load time by 60% in Europe and Asia.

HTTP/2 and Brotli Compression

We upgraded our CloudFront settings to use HTTP/2 and Brotli compression:

curl -I --compressed https://onlymakewaves.com/song/123

This reduced payload sizes and improved parallel loading for better frontend performance.

Async Loading with StimulusJS

We used StimulusJS for small enhancements, like loading download links after page render:

export default class extends Controller {
  connect() {
    fetch(this.data.get("url"))
      .then(res => res.json())
      .then(data => this.element.innerHTML = data.html);
  }
}

Our journey with Only Make Waves proved that with the right mindset and tools, it’s possible to scale without bloat. Part 3 emphasized the importance of quality, performance, and delivery velocity in modern software. From domain modeling to edge caching, we pushed the platform to production-readiness.

Leave a Reply

Your email address will not be published. Required fields are marked *