Source: The 3 Laws of Writing Readable Code

Law 1: Avoid Deeply Nested Logic

  • logic is harder to understand
func main(){
	if !isMaintenancePeriod {
		if isAuthenticatedUser {
			if isAuthorizedUser {
				for _. product := range cart {
					// Core Logic
					switch product.Type() {
						case "alcohol":
							total += alcoholTax
						case "electronics":
							total += electronicsTax
						default:
							total += generalTax
					}
				}
			}else {
				log.Fatalf("user not authorized")
			}
		}else {
			log.Fatalf("invalid user credentials")
		}
	}else {
		log.Fatalf("feature unabailable")
	}
}

Solutions

Inversion

Catch the error conditions earlier and only allow the core logic code to execute if all else is good

func main(){
	if isMaintenancePeriod {
		log.Fatalf("feature unabailable")
	}

	if !isAuthenticatedUser {
		log.Fatalf("invalid user credentials")
	}

	if !isAuthorizedUser {
		log.Fatalf("user not authorized")
	}

	for _. product := range cart {
		// Core Logic
		switch product.Type() {
			case "alcohol":
				total += alcoholTax
			case "electronics":
				total += electronicsTax
			default:
				total += generalTax
		}
	}
}
func main(){
	if isMaintenancePeriod {
		log.Fatalf("feature unabailable")
	}

	// Easier to read, but at the cost of only one log message. Weigh the tradeoff.
	if !isAuthenticatedUser || !isAuthorizedUser {
		log.Fatalf("user not authorized")
	}

	for _. product := range cart {
		// Core Logic
		switch product.Type() {
			case "alcohol":
				total += alcoholTax
			case "electronics":
				total += electronicsTax
			default:
				total += generalTax
		}
	}
}

Extraction

func main(){
	if isMaintenancePeriod {
		log.Fatalf("feature unabailable")
	}

	if !isValidUser() {
		log.Fatalf("user not authorized")
	}

	for _. product := range cart {
		calculateTaxes(product)
	}
}

//seperating out the code makes it easier to understnad.
func isValidUser() bool {
	return isAuthenticatedUser && isAuthorizedUser
}

func calculateTaxes(product product) {
	// Core Logic
	switch product.Type() {
		case "alcohol":
			total += alcoholTax
		case "electronics":
			total += electronicsTax
		default:
			total += generalTax
	}
}

Law 2: Avoid Duplication

func getUser(w http.REsponseWriter, r *http.Request) {
	userID := r.URL.Path[len("/user/"):]

	cacheMux.Lock()
	user, found := cache[userID]
	cacheMux.Unlock()

	if !found {
		query := "SELECT user_name, email FROM useres WHERE user_id = ?"
		stmt, _ := db.Prepare(query)

		var u User
		_ = stmt.QueryRow(userID).Scan(&u.Username, &u.Email)

		cacheMux.Lock()
		cache[userID] = u
		cacheMux.Unlock()

		user = u
	}

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(user)
}

func getUsers(w http.REsponseWriter, r *http.Request){
	var requestBody RequestBody
	json.NewDecoder(r.Body).Decode(&requestBody)
	userIDs := requestBody.UserIDs
	var users []User

	for _, userID := range userIDs {
		cacheMux.Lock()
		user, found := cache[userID]
		cacheMux.Unlock()

		if !found {
			query := "SELECT user_name, email FROM useres WHERE user_id = ?"
			stmt, _ := db.Prepare(query)

			var u User
			_ = stmt.QueryRow(userID).Scan(&u.Username, &u.Email)

			cacheMux.Lock()
			cache[userID] = u
			cacheMux.Unlock()

			user = u
		}

		users = append(users, user)
	}

	writeResponse(w, user)
}

Create a function for both parent functions to use.

func getUser(w http.REsponseWriter, r *http.Request) {
	userID := r.URL.Path[len("/user/"):]
	user := getSingleUser(userIDs)

	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(user)
}

func getUsers(w http.REsponseWriter, r *http.Request){
	var requestBody RequestBody
	json.NewDecoder(r.Body).Decode(&requestBody)
	userIDs := requestBody.UserIDs
	var users []User

	for _, userID := range userIDs {

		user := getSingleUser(userIDs)
		users = append(users, user)
	}

	writeResponse(w, user)
}

// Function to replace gettign User
func getSingleUser(userID string) User {
	cacheMux.Lock()
	user, found := cache[userID]
	cacheMux.Unlock()

	if !found {
		query := "SELECT user_name, email FROM useres WHERE user_id = ?"
		stmt, _ := db.Prepare(query)

		var u User
		_ = stmt.QueryRow(userID).Scan(&u.Username, &u.Email)

		cacheMux.Lock()
		cache[userID] = u
		cacheMux.Unlock()

		user = u
	}

	return user
}

//Function to replace Writing Response
func writeResponse(w http.ResponseWriter, response interface{}) {
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(users)
}

Takeaways

  • Code is easier to read through
  • easier to maintain as it only needs to be touched in place
  • modular and able to be moved around if needed

Law 3: Don’t User Cryptic Naming

type P struct {
	N string
	P float64
}

func main() {
	ps := []P{
		{"Apple", 0.50},
		{"Banana", 0.25},
		{"Orange", 0.75},
		{"Pear", 0.30},
	}

	t := 0.08
	var tc float64 = 0

	for _, P := range ps {
		tc += p.P + (p.P * t)
	}

	sc := tc / flaot64(len(ps))

	fmt.Println(tc)
	fmt.Println(ac)
}

Pick any naming convention and use it!

type Product struct {
	Name string
	Price float64
}

func main() {
	proudcuts := []Product{
		{"Apple", 0.50},
		{"Banana", 0.25},
		{"Orange", 0.75},
		{"Pear", 0.30},
	}

	tax := 0.08
	var totalCost float64 = 0

	for _, product := range products {
		totalCost += product.Price + (product.Price * tax)
	}

	averageCost := totalCost / flaot64(len(ps))

	fmt.Println(totalCost)
	fmt.Println(averageCost)
}