Backend Development 9 min read

My Journey as a New Backend Engineer: Project Setup, Testing Approaches, and Monitoring at FlowingTalk

Joining a new team and project as a fresh graduate at FlowingTalk, I describe the supportive environment, codebase initialization, various HTTP testing strategies using Go and Gin, the adoption of OpenCensus, Prometheus, and Sentry for monitoring, and how iterative development accelerates my growth as a backend engineer.

Liulishuo Tech Team
Liulishuo Tech Team
Liulishuo Tech Team
My Journey as a New Backend Engineer: Project Setup, Testing Approaches, and Monitoring at FlowingTalk

Context: New Hire, New Team, New Project + Mature Support

As one of the first batch of campus hires selected by FlowingTalk, I was fortunate to join a brand‑new team and a brand‑new project called Sprout. The team grew fourfold in six months, and I wrote the first line in the repository's README . The project started small but with high quality, guided by experienced tech leads and domain owners.

Although the project is new, we stand on the shoulders of giants: we reuse mature company projects, leverage common services that were extracted from older systems before Sprout began, and follow strict development standards such as unit testing and code review, which proved crucial for our backend services.

func init() { Understanding FlowingTalk's Workflow and Code Architecture }

During the early iteration (0.1), I was tasked with building the foundational service code from scratch, guided by my mentor. This helped me grasp the overall workflow, including requirement reviews, development reviews, and scrum ceremonies.

For HTTP interface testing, I explored three approaches:

Approach 1 – Test only the handler function:

// file: user.go
// We use gin as our http framework

func CreateUser(c *gin.Context) {
  // Thank God, we have a new user!
}

// file: user_test.go
func TestCreateUser(t *testing.T) {
  // Only test the logic after the variable `c` has been initialized.
}

Approach 2 – Test from the router level:

// file: router/router.go
type Servlet interface {
  CreateUser(c *gin.Context)
}

type Router struct {
  GinEngine *gin.Engine
}

func NewRouter(s Servlet) *Router {
  engine := gin.New()
  engine.POST("/user", s.CreateUser)
  return &Router{GinEngine: engine}
}

// file: handler/servlet.go
type Servlet struct {}

// file: handler/user.go
func (*Servlet) CreateUser(c *gin.Context) {
  // Thank God, we have a new user!
}

// file: handler/user_test.go
func TestCreateUser(t *testing.T) {
  rr := httptest.NewRecorder()
  c, _ := gin.CreateTestContext(rr)
  servlet := new(Servlet)
  router := router.NewRouter(servlet)
  g := router.GinEngine
  // mock http request here
  c.Request = httpReq
  g.HandleContext(c)
  // check rr.Code and rr.Body
}

While Approach 2 provides realistic HTTP simulation, it can lead to tangled imports and circular dependencies as the number of handlers grows.

Approach 3 – Use a mock Servlet to replace the real one in tests:

// file: router/servlet.go
type Servlet interface {
  User
  Course
}

type User interface {
  CreateUser(c *gin.Context)
}

type Course interface {
  // course handler here
}

// file: router/mock/servlet.go
type Servlet struct {
  router.User
  router.Course
}

// file: handler/user/servlet.go
type Servlet struct {}

// file: handler/user/user_test.go
import (
  mockrouter "router/mock"
  ...
)

func TestCreateUser(t *testing.T) {
  rr := httptest.NewRecorder()
  c, _ := gin.CreateTestContext(rr)
  userServlet := new(Servlet)
  servlet := mockrouter.Servlet{User: userServlet}
  router := router.NewRouter(servlet)
  g := router.GinEngine
  // mock http request here
  c.Request = httpReq
  g.HandleContext(c)
  // check rr.Code and rr.Body
}

Good architecture allows us to replace components with mocks, making business‑logic testing cleaner and more maintainable.

if err != nil { Familiarizing with Bug Tracing and Performance Monitoring }

Before micro‑services, bugs were traced via step‑by‑step debugging or stack traces within a monolithic codebase. In a micro‑service environment, a single feature may involve multiple services, rendering traditional tracing ineffective. FlowingTalk injects OpenCensus , Prometheus , and Sentry middleware to record interface behavior, enabling rapid issue localization with minimal log inspection.

for { Learning from Version Iterations }

As the project evolves, the app matures and new features expose fresh technical gaps. From simple API development to high‑compute asynchronous tasks and service decomposition, each architectural change serves as a valuable learning milestone for fresh graduates.

defer { Becoming a Competent Backend Engineer }

Progressing from version 0.1 to 1.3, I moved from completing tasks to proposing solutions, from writing a few lines of code to expressing intent through code. Rapid product iteration and diverse features push me to grow quickly as an engineer, and I look forward to continuing this journey with FlowingTalk.

FlowingTalk's 2019 spring recruitment and 2020 campus hiring are ongoing; interested candidates can follow future recruitment updates.

backendMonitoringMicroservicestestingGo
Liulishuo Tech Team
Written by

Liulishuo Tech Team

Help everyone become a global citizen!

0 followers
Reader feedback

How this landed with the community

login 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.