Meet Corvin: How Do You Switch from Frontend to Backend?

image of backend developers and tech department at adjoe

Being able to work in the frontend and the backend helps me understand where bottlenecks or potential sources for errors lie. I can also create new features that need the frontend and the backend on my own. Corvin Grigutsch

Meet Corvin Grigutsch, a full-stack developer and an adjoe original – one of the first hires as a mobile developer intern back in 2014. He worked directly with mentor Co-Founder and CTO Carlo Szelinsky to develop adjoe’s Playtime SDK.

After graduating in Computer Science and Mathematics from the University of Göttingen, Corvin switched his focus to the adjoe’s backend development. This came after seven years of part-time work in frontend Android development at adjoe. Keen to move forward in a data science role and expand his universal development skills, the developer made it his mission to master the backend system. For example, by working with Go language, gRPC, and Protobuf.

Developing the SDK from the Ground Up

As part of adjoe’s Frontend Development team, Corvin and his colleagues had to design an SDK from the ground up that was as easy as possible for publishers to integrate into their app’s Android development framework. Easy, how? Here are three examples.

  • Ensuring publishers need to call as few functions as possible to use the SDK
  • Making the SDK easily accessible and understandable by hosting it on a Maven server and writing documentation
  • Keeping the file size of the built SDK as low as possible

Corvin and his colleagues assisted adjoe’s Supply team in directly interacting with and onboarding hundreds of new partners – and, worked together with Carlo to guide partners through the installation process.

Navigating Android Limitations in the SDK

Developing the Playtime SDK from the ground up meant realizing different tasks, such as:

  • Creating the user interface in JavaScript and porting it to other languages
  • Setting up the CI pipeline
  • Writing wrappers to port the SDK to other mobile frameworks and languages – for example, ReactNative, Unity, and Flutter

These tasks were not without their challenges. For example, Corvin and the Tech team needed to ensure all wrappers were compatible with the libraries they used as well as Android API versions 16 and above. But the largest obstacle was the background execution limitations imposed by Android. Android’s restrictive frameworks, designed to extend battery life, posed complications for usage tracking implementation. 

But where there’s a will, there’s an API. Corvin used combinations of Android’s APIs for background work, such as services, the AlarmManager, and the JobScheduler to overcome these restrictions.

Getting to Grips with Go, gRPC, and Protobuf

Working in adjoe’s frontend is no easy ride, but the backend system was completely new territory for Corvin. The full-stack developer had to familiarize himself with:

  • Go language
  • new technologies including Terraform, AWS, Kubernetes, gRPC, and Protobuf
  • different SDK variants (Playtime and adjoe Advance)
  • the management of data for the dashboards

With the assistance of mentor Seb Jakobs, adjoe’s Tech Lead – as well as Go Playground and Go Tour – Corvin mastered Go within a few weeks. He started by learning about types, structs, and interfaces before moving onto more advanced topics like channels and Goroutines.

Switching from JSON to Protobuf

One of Corvin’s first projects with his team in the backend has also been to help handle traffic that is 100 times higher than Playtime traffic. To enable this traffic increase and facilitate users making more requests, Corvin performed a switch from JSON to Protobuf as the main message protocol to save bandwidth and increase performance. As binary and field names are not included in the message, this makes the message size smaller relative to JSON. This message protocol is already in place for new projects at adjoe.

So, let’s take you through how Corvin handles a request to create a user. 

First, you need to create a user with an HTTP server that accepts a JSON request.

{
  "first_name": "Max",
  "last_name": "Mustermann",
  "age": 30,
  "city": "Hamburg",
  "postal_code": "20099",
  "company": "adjoe"
}

To create a Protobuf message, you first define the schema.

message CreateUserRequest {
  required string first_name = 1;
  required string last_name = 2;
  required int32 age = 3;
  required string city = 4;
  required string postal_code = 5;
  required string company = 6;
}
```

Then, you define the service.

service CreateUserService {
  rpc CreateUser(CreateUserRequest) returns CreateUserResponse {};
}
```

You can use Buf, for example, to create the Go client for the gRPC service. After this, you can create the server in Go.

type UserServer struct {
	protobuf.UnimplementedCreateUserServiceServer
}

func main() {
	listener, _ := net.Listen("tcp", ":81")
	server := grpc.NewServer()
	userServer := &UserServer{}
	protobuf.RegisterCreateUserServiceServer(server, userServer)
	server.Serve(listener)
}
```

After this step, you then implement the server.

func (u *UserServer) CreateUser(ctx context.Context, req *protobuf.CreateUserRequest) (*protobuf.CreateUserResponse, error) {
	fmt.Printf(
		"%s %s from %s is %d years old and works at %s\n",
		*req.FirstName,
		*req.LastName,
		*req.City,
		*req.Age,
		*req.Company,
	)
	var result string
	if *req.Company == "adjoe" {
		result = "ok"
	} else {
		result = "failed"
	}
	return &protobuf.CreateUserResponse{
		Result: &result,
	}, nil
}
```

You can subsequently run the application and make a request to the server – for example, with Kreya.

And there you have it: This is the complete code.

* main.go
package main

import (
	"context"
	"fmt"
	"net"

	"google.golang.org/grpc"

	protobuf "grpc/test/v1"
)

func main() {
	listener, _ := net.Listen("tcp", ":81")
	server := grpc.NewServer()
	userServer := &UserServer{}
	protobuf.RegisterCreateUserServiceServer(server, userServer)
	server.Serve(listener)
}

type UserServer struct {
	protobuf.UnimplementedCreateUserServiceServer
}

func (u *UserServer) CreateUser(ctx context.Context, req *protobuf.CreateUserRequest) (*protobuf.CreateUserResponse, error) {
	fmt.Printf(
		"%s %s from %s is %d years old and works at %s\n",
		*req.FirstName,
		*req.LastName,
		*req.City,
		*req.Age,
		*req.Company,
	)
	var result string
	if *req.Company == "adjoe" {
		result = "ok"
	} else {
		result = "failed"
	}
	return &protobuf.CreateUserResponse{
		Result: &result,
	}, nil
}
```
* service.proto
```protobuf
syntax = "proto2";
package grpc.test.v1;

option go_package = "grpc/test/v1";

service CreateUserService {
  rpc CreateUser (CreateUserRequest) returns (CreateUserResponse) {}
}

message CreateUserRequest {
  required string first_name = 1;
  required string last_name = 2;
  required int32 age = 3;
  required string city = 4;
  required string postal_code = 5;
  required string company = 6;
}

message CreateUserResponse {
  required string result = 1;
}

```

Now, within this code, Corvin has managed to create a user in Protobuf and subsequently reduced bandwidth. The JSON request is 109 bytes, whereas the size of the Protobuf message is only 42 bytes.

Fresh out of School to Full-Time Full-Stack Developer

Only a couple of Corvin’s colleagues at adjoe have made the leap from frontend to backend development. But knowing the necessary languages and technologies used in both the frontend and the backend gives these developers a completely holistic view of company projects. Corvin knows exactly where data comes from and where it is created (for example, the usage in the frontend) as well as where the data goes and where it is consumed (to which table it is written and which checks it has to pass).

In 2021 the full-stack developer rose to the challenge of learning these backend technologies and languages from scratch. But his next task is already in the pipeline: Corvin will focus on analyzing the bids and optimizing the bidder. This will help improve ad recommendations for adjoe’s users and boost the company’s business.

Move From Latest Hire to High-Flyer

View All Vacancies