Chapter 51 — SQL Transactions & Connection Management
Question
Given below is a code snippet that:
Demonstrates the basic structure of a database transaction.
Demonstrates
Begin,Commit, andRollback.Demonstrates why an error should cause a transaction to be rolled back.
Demonstrates the intended all-or-nothing nature of a transaction.
What should be the output of the following code?
package main
import (
"database/sql"
"fmt"
)
func transfer(tx *sql.Tx) error {
fmt.Println("debit account")
fmt.Println("credit account")
err := fmt.Errorf("credit failed")
if err != nil {
fmt.Println("rollback")
return err
}
return tx.Commit()
}
func main() {
db := (*sql.DB)(nil)
_ = db
tx := (*sql.Tx)(nil)
err := transfer(tx)
if err != nil {
fmt.Println("transaction failed")
return
}
fmt.Println("transaction committed")
}Answer
debit account
credit account
rollback
transaction failedStep-by-step explanation
txrepresents a database transaction.transferbegins by performing the conceptual debit operation.It then performs the conceptual credit operation.
An error is deliberately created with
fmt.Errorf.Because
err != nil, the function reports"rollback"and returns the error.mainreceives the error and prints"transaction failed"."transaction committed"is never reached.
How to read the important code
if err != nil {"if err is not equal to nil, open curly brace."
A transaction is a group of database operations treated as one unit.
The usual pattern is:
Begin → operations → Commit
↓
error
↓
RollbackIn real Go code, you normally use db.Begin() to start a transaction and tx.Commit() or tx.Rollback() to finish it.
Key takeaway
A transaction should leave the database in a consistent state: either the intended group of changes succeeds, or the changes are rolled back.
Chapter 52 — Authentication & Authorization
Question
Given below is a code snippet that:
Demonstrates the difference between authentication and authorization.
Checks whether a user is logged in.
Checks whether the authenticated user has permission to perform an action.
Demonstrates a simple role-based access check.
What should be the output of the following code?
package main
import "fmt"
type User struct {
Name string
Role string
}
func canDelete(user *User) bool {
if user == nil {
return false
}
return user.Role == "admin"
}
func main() {
user := &User{
Name: "Ravi",
Role: "editor",
}
fmt.Println("authenticated:", user != nil)
fmt.Println("can delete:", canDelete(user))
user.Role = "admin"
fmt.Println("can delete:", canDelete(user))
}Answer
authenticated: true
can delete: false
can delete: trueStep-by-step explanation
userpoints to aUsercontaining Ravi's information.user != nilconfirms that a user object exists.Therefore, the first authentication check prints
true.Ravi's initial role is
"editor".canDeletereturnsfalsebecause only"admin"is allowed to delete.The role is changed to
"admin".The second authorization check therefore returns
true.
How to read the important code
return user.Role == "admin""return user dot Role is equal to double quote admin double quote."
Authentication asks:
"Who are you?"
Authorization asks:
"Are you allowed to do this?"
For example, logging in successfully is authentication; being allowed to delete another user's account is authorization.
Key takeaway
Authentication identifies the user; authorization decides what that user is allowed to do.
Chapter 53 — Secure Go Programming
Question
Given below is a code snippet that:
Demonstrates parameterized SQL.
Demonstrates why user input should not be directly concatenated into SQL.
Keeps user-controlled data separate from SQL syntax.
Demonstrates a safer database-query pattern.
What should be the output of the following code?
package main
import "fmt"
func buildQuery(username string) (string, []any) {
query := "SELECT id, name FROM users WHERE username = ?"
args := []any{username}
return query, args
}
func main() {
query, args := buildQuery("admin' OR '1'='1")
fmt.Println(query)
fmt.Println(args)
}Answer
SELECT id, name FROM users WHERE username = ?
[admin' OR '1'='1]Step-by-step explanation
usernamecontains input supplied by a user.The SQL query contains
?as a placeholder.The username is placed separately inside
args.Therefore, the username is treated as data rather than being inserted into the SQL command itself.
Even though the input contains SQL-looking characters, it remains one argument.
In actual database code, the database driver binds the argument to the placeholder.
How to read the important code
query := "SELECT id, name FROM users WHERE username = ?""query colon equals double quote SELECT id comma name FROM users WHERE username equals question mark double quote."
A parameterized query separates:
SQL command
+
user-provided dataInstead of constructing SQL like:
"... WHERE username = '" + username + "'"you use placeholders and arguments.
Key takeaway
Never blindly concatenate untrusted user input into SQL; use parameterized queries.
Chapter 54 — Configuration & Environment Variables
Question
Given below is a code snippet that:
Demonstrates reading an environment variable.
Demonstrates providing a default value.
Demonstrates how configuration can change without changing source code.
Uses a realistic application configuration pattern.
What should be the output of the following code?
package main
import (
"fmt"
"os"
)
func getPort() string {
port := os.Getenv("PORT")
if port == "" {
return "8080"
}
return port
}
func main() {
os.Setenv("PORT", "9000")
fmt.Println("server port:", getPort())
}Answer
server port: 9000Step-by-step explanation
os.Setenv("PORT", "9000")creates or changes thePORTenvironment variable for this process.getPort()callsos.Getenv("PORT").It receives
"9000".Because the value isn't empty, the function returns
"9000".main()prints the configured port.
How to read the important code
port := os.Getenv("PORT")"port colon equals os dot Getenv, open parenthesis double quote PORT double quote, close parenthesis."
An environment variable is a value supplied by the operating environment rather than hard-coded into the program.
Common production configuration includes:
PORT
DATABASE_URL
API_KEY
LOG_LEVELSensitive values such as passwords and API keys should generally not be hard-coded into source code.
Key takeaway
Configuration should normally be external to your application code so the same program can run in different environments.
Chapter 55 — Logging & Observability
Question
Given below is a code snippet that:
Demonstrates structured logging with
log/slog.Adds useful context to a log message.
Demonstrates different log levels.
Shows how logs can help understand what a backend service is doing.
What should be the output of the following code?
package main
import (
"log/slog"
"os"
)
func main() {
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
logger.Info("request completed",
"method", "GET",
"path", "/users",
"status", 200,
)
logger.Error("database unavailable",
"retry", 3,
)
}Answer
The exact formatting can vary slightly by Go version and handler configuration, but the important output is:
level=INFO msg="request completed" method=GET path=/users status=200
level=ERROR msg="database unavailable" retry=3Step-by-step explanation
slog.NewTextHandlercreates a text-format log handler.slog.Newcreates a logger using that handler.logger.Inforecords an informational event."method","path", and"status"provide structured context.logger.Errorrecords an error event."retry", 3tells us that three retries are associated with the error.In a production service, these contextual fields make logs much easier to search and analyze.
How to read the important code
logger.Info("request completed", "method", "GET")"logger dot Info, open parenthesis double quote request completed double quote, comma double quote method double quote, comma double quote GET double quote, close parenthesis."
Observability means making a running system understandable from its external behavior, commonly through:
logs
metrics
traces
Key takeaway
Good logs don't merely say that something failed—they provide enough context to understand what happened.
Chapter 56 — Graceful Shutdown
Question
Given below is a code snippet that:
Demonstrates the basic shutdown sequence of a server.
Uses
contextto signal cancellation.Demonstrates cleanup before the program exits.
Shows the order in which shutdown operations occur.
What should be the output of the following code?
package main
import (
"context"
"fmt"
)
func server(ctx context.Context) {
fmt.Println("server started")
<-ctx.Done()
fmt.Println("shutdown signal received")
fmt.Println("server stopped")
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
go server(ctx)
cancel()
fmt.Println("application exiting")
}Answer
application exitingStep-by-step explanation
context.WithCancelcreates a context and acancelfunction.go server(ctx)startsserverin a goroutine.cancel()signals cancellation.However, the main goroutine does not wait for
serverto finish.mainimmediately prints"application exiting".The program can terminate before the server goroutine gets a chance to print its messages.
Therefore, you cannot safely depend on the server's output appearing here.
How to read the important code
ctx, cancel := context.WithCancel(context.Background())"ctx comma cancel colon equals context dot WithCancel, open parenthesis context dot Background, open parenthesis close parenthesis, close parenthesis."
A context carries cancellation and request-related information through function calls.
cancel()"cancel, open parenthesis close parenthesis."
This signals:
"The work using this context should stop."
Key takeaway
Graceful shutdown means signaling running work to stop and then waiting for cleanup to finish before the process exits.
Chapter 57 — Dependency Injection & Application Design
Question
Given below is a code snippet that:
Demonstrates dependency injection.
Uses an interface to separate business logic from a concrete dependency.
Injects a dependency into a service.
Demonstrates why this design makes code easier to test.
What should be the output of the following code?
package main
import "fmt"
type UserStore interface {
FindName(id int) string
}
type MemoryStore struct{}
func (MemoryStore) FindName(id int) string {
return "Ravi"
}
type UserService struct {
store UserStore
}
func (s UserService) Greeting(id int) string {
return "Hello, " + s.store.FindName(id)
}
func main() {
store := MemoryStore{}
service := UserService{store: store}
fmt.Println(service.Greeting(10))
}Answer
Hello, RaviStep-by-step explanation
UserStoredefines the behavior required byUserService.MemoryStoreimplementsFindName, so it satisfiesUserStore.UserServicestores aUserStorerather than depending directly onMemoryStore.storeis injected intoUserServicewhen the service is created.Greeting(10)asks the injected store for the user's name.The store returns
"Ravi".The final result is
"Hello, Ravi".
How to read the important code
service := UserService{store: store}"service colon equals UserService, open curly brace, store colon store, close curly brace."
Dependency injection means:
Instead of a component creating everything it needs itself, those dependencies are supplied to it.
This is especially useful for replacing a real database with a fake or test implementation.
Key takeaway
Dependency injection keeps components loosely connected and makes testing and maintenance easier.
Chapter 58 — Clean Go Code & Idiomatic Go
Question
Given below is a code snippet that:
Demonstrates an idiomatic Go function.
Uses early return for an error condition.
Uses clear naming.
Demonstrates the common Go pattern of returning a value and an error.
What should be the output of the following code?
package main
import (
"errors"
"fmt"
)
func divide(a, b float64) (float64, error) {
if b == 0 {
return 0, errors.New("cannot divide by zero")
}
return a / b, nil
}
func main() {
result, err := divide(10, 2)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("result:", result)
}Answer
result: 5Step-by-step explanation
divide(10, 2)receives10and2.b == 0is false.The function returns
10 / 2, which is5.It also returns
nilas the error because no error occurred.err != nilis false, so the error branch is skipped.The result is printed.
How to read the important code
func divide(a, b float64) (float64, error)"func divide, open parenthesis a comma b float64 close parenthesis, open parenthesis float64 comma error close parenthesis."
This function returns two values:
result
errorGo commonly uses this pattern:
value, err := someFunction()
if err != nil {
// handle error
}Idiomatic Go means writing code in the style that is natural, conventional, readable, and maintainable in the Go ecosystem.
Key takeaway
Idiomatic Go favors simple code, clear names, explicit error handling, and straightforward control flow.
Chapter 59 — Go Project Architecture
Question
Given below is a code snippet that:
Demonstrates separation between HTTP handling, business logic, and data access.
Uses interfaces to keep layers independent.
Demonstrates a simple dependency flow.
Shows a miniature version of how a real backend can be organized.
What should be the output of the following code?
package main
import "fmt"
type UserRepository interface {
GetName(id int) string
}
type Repository struct{}
func (Repository) GetName(id int) string {
return "Ravi"
}
type UserService struct {
repo UserRepository
}
func (s UserService) GetUserName(id int) string {
return s.repo.GetName(id)
}
type Handler struct {
service UserService
}
func (h Handler) Handle(id int) {
name := h.service.GetUserName(id)
fmt.Println("HTTP response:", name)
}
func main() {
repo := Repository{}
service := UserService{repo: repo}
handler := Handler{service: service}
handler.Handle(1)
}Answer
HTTP response: RaviStep-by-step explanation
Repositoryrepresents the data-access layer.UserRepositorydefines what the service needs from the repository.UserServicerepresents business logic.Handlerrepresents the HTTP-facing layer.The repository is injected into the service.
The service is injected into the handler.
handler.Handle(1)starts the flow.The handler asks the service for the user's name.
The service asks the repository.
The repository returns
"Ravi".The handler prints the simulated HTTP response.
How to read the important code
handler := Handler{service: service}"handler colon equals Handler, open curly brace, service colon service, close curly brace."
The simplified flow is:
HTTP Handler
↓
Service / Business Logic
↓
Repository / DatabaseThe important idea is separation of responsibilities:
Handler → deals with HTTP requests/responses.
Service → contains application/business logic.
Repository → deals with storing and retrieving data.
Key takeaway
Good Go architecture separates responsibilities so individual parts can be changed, tested, and maintained without rewriting the whole application.
Chapter 60 — Building Production-Ready REST APIs
Question
Given below is a code snippet that:
Demonstrates a realistic HTTP handler.
Decodes JSON from a request.
Validates input.
Returns a JSON response.
Uses an appropriate HTTP status code for invalid input.
What should be the output of the following code?
package main
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
)
type User struct {
Name string `json:"name"`
}
func createUser(w http.ResponseWriter, r *http.Request) {
var user User
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil || user.Name == "" {
http.Error(w, "invalid user", http.StatusBadRequest)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(user)
}
func main() {
body := strings.NewReader(`{"name":"Ravi"}`)
req := httptest.NewRequest(http.MethodPost, "/users", body)
rec := httptest.NewRecorder()
createUser(rec, req)
fmt.Println("status:", rec.Code)
fmt.Println("body:", strings.TrimSpace(rec.Body.String()))
}Answer
status: 201
body: {"name":"Ravi"}Step-by-step explanation
The request body contains JSON:
{"name":"Ravi"}.httptest.NewRequestcreates a test HTTP request.httptest.NewRecordercaptures the handler's response.json.NewDecoder(r.Body).Decode(&user)reads the JSON into theUserstruct.user.Namebecomes"Ravi".The validation succeeds because the name isn't empty.
The handler sets the response content type to JSON.
http.StatusCreatedis201, which indicates that a resource was created.json.NewEncoder(w).Encode(user)writes the user as JSON.The recorder captures that response, allowing
main()to print it.
How to read the important code
json.NewDecoder(r.Body).Decode(&user)"json dot NewDecoder, open parenthesis r dot Body close parenthesis, dot Decode, open parenthesis ampersand user close parenthesis."
r.Bodycontains the request body.Decodereads JSON and puts the result intouser.&usergives the decoder the address ofuser, allowing it to modify it.
w.WriteHeader(http.StatusCreated)"w dot WriteHeader, open parenthesis http dot StatusCreated close parenthesis."
201 Created is a standard HTTP status meaning that a resource was successfully created.
Key takeaway
A production REST API must correctly handle requests, validate input, return appropriate HTTP status codes, and produce predictable response formats.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.