Why We Switched from PHP to Go and How We Built Our Own Framework

This article shares the author's experience migrating a high‑traffic platform from PHP to Go, detailing the challenges of framework selection, layered architecture design, incremental refactoring, and the eventual adoption of go‑kit for scalable microservices.

21CTO
21CTO
21CTO
Why We Switched from PHP to Go and How We Built Our Own Framework

Preface

After working at two companies and contributing to both a PHP framework and a Go tech stack, the author reflects on the problems encountered during the migration and documents the reasoning, analysis, and solutions for introducing Go into the team.

Why We Switched from PHP to Go

In 2015 the platform, originally built entirely with PHP, faced explosive traffic growth, reaching tens of thousands of QPS during peak hours. Scaling by adding machines and increasing php‑fpm workers proved insufficient due to PHP's network model, prompting a temporary Lua workaround and ultimately a decision to adopt Go by the end of 2015.

How We Transitioned from PHP to Go

The team faced typical migration issues: choosing a framework and refactoring PHP projects into Go under heavy workload and limited staff.

Framework selection: internal prototype, popular options (beego, gin, martini) were considered, but concerns about documentation, bugs, and maintenance led to a decision to write a minimal framework in‑house.

Requirements identified:

High‑performance HTTP interfaces.

Comprehensive unit‑testing support.

Extensibility and componentization.

Go's built‑in features satisfied these needs, so the team opted for a bare‑bones implementation while acknowledging that a proper framework would be preferable when resources allow.

Bare‑bones Development Is Not Random

To maintain code consistency, a classic layered architecture was defined: Router layer (HTTP handling), Service layer (business logic), Dao layer (data access), and Entity layer (shared models). The layers interact only through abstract interfaces, avoiding direct coupling. A common utility library (logging, database drivers, etc.) was also maintained.

“All well‑structured object‑oriented architectures have clear layer definitions, each exposing a cohesive service through a controlled interface.” – Booch

Figure 1: Layered architecture diagram.

Refactoring Strategy

With the programming template in place, the team began incremental refactoring, prioritizing interfaces based on business importance. During the transition, a mixed PHP+Go deployment persisted for about a year, with Nginx routing traffic to new Go endpoints. The team warns against attempting a full‑scale rewrite at once; instead, refactor one interface at a time.

Figure 2: Mixed PHP+Go architecture.

Why Introduce go‑kit

As traffic continued to grow, the team needed support for multiple transport protocols (HTTP, Thrift, gRPC) and low‑coupling middleware. go‑kit, a microservice toolkit rather than a full framework, offers a three‑layer design (Transport, Endpoint, Service) that aligns with the existing template and provides protocol‑agnostic middleware such as logging, metrics, tracing, circuit breaking, and rate limiting.

Figure 3: go‑kit architecture.

Integrating go‑kit into Existing Systems

By aligning the existing three‑layer Go template (router, service, dao) with go‑kit's Transport, Endpoint, and Service layers, integration becomes straightforward. The router layer must contain no business logic to allow seamless replacement. If go‑kit is later removed, the Endpoint and Transport layers can be dropped without affecting core services.

Figure 4: Evolution of the architecture.

Efficient Use of go‑kit

Manually writing the three go‑kit layers for each new project can be tedious. The GoKit CLI tool automates generation of service, transport, and endpoint templates, as well as client libraries, dramatically improving productivity.

Figure 5: GoKit CLI feature overview.

Conclusion

The key takeaway is to clearly define requirements before selecting a framework. By adhering to classic design principles—single responsibility, open/closed, dependency inversion, and interface segregation—teams can build flexible, maintainable systems. Avoid blindly following trends; choose solutions that truly fit your needs.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

backend architecturemicroservicesGoframework selectionPHP migrationGo-Kit
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.