Go web 11. Refactoring

JINSOO PARK·2021년 10월 28일
0

Go 로 만드는 웹

목록 보기
10/16

리팩토링이란?

  • 외부 동작을 바꾸지 않으면서 내부 구조를 개선하는 방법이다.
  • 코드가 작성된 후에 디자인을 개선하는 작업
  • 모든 것을 미리 생각하기 보다는 개발을 하면서 지속적으로 좋은 디자인을 찾는다.

리팩토링이 필요한 이유

  • 코드의 구조가 망가지는 효과는 누적 된다.
  • 코드의 디자인을 유지하도록 도와준다.
  • 중복을 제거함으로써 각각의 작업에 대한 코드가 오직 한 곳에만 있게 할 수 있다.
  • 소프트웨어의 디자인을 개선시키고 더 이해하기 쉽게 만든다.
  • 버그를 찾도록 도와준다.
  • 프로그램을 빨리 작성하도록 도와준다.
    링크텍스트


리팩토링 해보기

Go web 10에서 만든 app.go는 메모리맵을 가지며 컨트롤 하고 있어서 의존성이 매우 높았기 때문에, 의존성을 끊어내기 위해 분리 시킴

이렇게 함으로써 메모리에 해당하는 부분은 model패키지에서 컨트롤 하게 된다.

1) 큰 틀 잡기

ex) app.go

package app

import (
	"net/http"
	"strconv"
	"web10/model"

	"github.com/gorilla/mux"
	"github.com/unrolled/render"
)

var rd *render.Render

func indexHandler(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "/todo.html", http.StatusTemporaryRedirect)
}

// 리스트를 받아서 제이슨형태로 넘겨줌
func getTodoListHandler(w http.ResponseWriter, r *http.Request) {
	// list := []*model.Todo{}
	// for _, v := range todoMap {
	// 	// map의 인덱스 만큼 반복
	// 	// 키는 받지않고 value만 받음
	// 	list = append(list, v)
	// 	// list에 v값을 어팬드
	// }
	list := model.GetTodos() // model 패키지에서 불러옴
	rd.JSON(w, http.StatusOK, list)
	// json형태로 반환
}

func addTodoHandler(w http.ResponseWriter, r *http.Request) {
	name := r.FormValue("name") // 리퀘스트의 키로 name을 읽음
	todo := model.AddTodo(name)
	// id := len(todoMap) + 1                     // map의 갯수만큼 id
	// todo := &Todo{id, name, false, time.Now()} // 포인터형 구조체 Todo를 생성
	// todoMap[id] = todo                         // todo의 데이터를 맵에 넣음
	rd.JSON(w, http.StatusCreated, todo) // json형태로 반환

}

type Success struct {
	Success bool `json:"success"`
}

func removeTodoHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id, _ := strconv.Atoi(vars["id"])
	ok := model.RemoveTodo(id)
	if ok {
		rd.JSON(w, http.StatusOK, Success{true})
	} else {
		rd.JSON(w, http.StatusOK, Success{false})
	}
	// if _, ok := todoMap[id]; ok {
	// 	delete(todoMap, id)
	// 	rd.JSON(w, http.StatusOK, Success{true})
	// } else {
	// 	rd.JSON(w, http.StatusOK, Success{false})
	// }
}

func completeTodoHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id, _ := strconv.Atoi(vars["id"])
	complete := r.FormValue("complete") == "true"
	ok := model.CompleteTodo(id, complete)
	if ok {
		rd.JSON(w, http.StatusOK, Success{true})
	} else {
		rd.JSON(w, http.StatusOK, Success{false})
	}
	// value 값에서 complete의 값을 받음
	// if todo, ok := todoMap[id]; ok { // 맵에 있는지 확인
	// 	todo.Completed = complete                // 맵에 있는경우 변경
	// 	rd.JSON(w, http.StatusOK, Success{true}) //제이슨 값으로 변환후 true 반환
	// } else {
	// 	rd.JSON(w, http.StatusOK, Success{false})
	// } // 맵에 없을 경우 false 반환
}

// func addTestTodos() {
// 	todoMap[1] = &Todo{1, "Buy a milk", false, time.Now()}
// 	todoMap[2] = &Todo{2, "Exercise", true, time.Now()}
// 	todoMap[3] = &Todo{3, "Home Work", false, time.Now()}
// }

func MakeHandler() http.Handler {
	// todoMap = make(map[int]*Todo)

	rd = render.New()
	r := mux.NewRouter()

	r.HandleFunc("/todos", getTodoListHandler).Methods("GET")
	r.HandleFunc("/todos", addTodoHandler).Methods("POST")
	r.HandleFunc("/todos/{id:[0-9]+}", removeTodoHandler).Methods("DELETE")
	r.HandleFunc("complete-todo/{id:[0-9]+", completeTodoHandler)
	r.HandleFunc("/", indexHandler)

	return r
}

ex) model.go

package model

import "time"

type Todo struct {
	ID        int       `json:"id"`
	Name      string    `json:"name"`
	Completed bool      `json:"completed"`
	CreatedAt time.Time `json:"created_at"`
}

// Todo의 데이터를 가지고 있는 인메모리 스트럭처
var todoMap map[int]*Todo

func GetTodos() []*Todo {
	return nil
}

func AddTodo(name string) *Todo {
	return nil
}

func RemoveTodo(id int) bool {
	return nil
}

func CompleteTodo(id int, complete bool) bool {
	return false
}

2) 틀에 맞춰 정리하기

ex) app.go

package app

import (
	"net/http"
	"strconv"
	"web10/model"

	"github.com/gorilla/mux"
	"github.com/unrolled/render"
)

var rd *render.Render

func indexHandler(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "/todo.html", http.StatusTemporaryRedirect)
}

// 리스트를 받아서 제이슨형태로 넘겨줌
func getTodoListHandler(w http.ResponseWriter, r *http.Request) {

	list := model.GetTodos() // model 패키지에서 불러옴
	rd.JSON(w, http.StatusOK, list)
	// json형태로 반환
}

func addTodoHandler(w http.ResponseWriter, r *http.Request) {
	name := r.FormValue("name") // 리퀘스트의 키로 name을 읽음
	todo := model.AddTodo(name)

	rd.JSON(w, http.StatusCreated, todo) // json형태로 반환

}

type Success struct {
	Success bool `json:"success"`
}

func removeTodoHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id, _ := strconv.Atoi(vars["id"])
	ok := model.RemoveTodo(id)
	if ok {
		rd.JSON(w, http.StatusOK, Success{true})
	} else {
		rd.JSON(w, http.StatusOK, Success{false})
	}
}

func completeTodoHandler(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	id, _ := strconv.Atoi(vars["id"])
	complete := r.FormValue("complete") == "true"
	ok := model.CompleteTodo(id, complete)
	if ok {
		rd.JSON(w, http.StatusOK, Success{true})
	} else {
		rd.JSON(w, http.StatusOK, Success{false})
	}
}

func MakeHandler() http.Handler {

	rd = render.New()
	r := mux.NewRouter()

	r.HandleFunc("/todos", getTodoListHandler).Methods("GET")
	r.HandleFunc("/todos", addTodoHandler).Methods("POST")
	r.HandleFunc("/todos/{id:[0-9]+}", removeTodoHandler).Methods("DELETE")
	r.HandleFunc("complete-todo/{id:[0-9]+", completeTodoHandler)
	r.HandleFunc("/", indexHandler)

	return r
}

ex) model.go

package model

import (
	"time"
)

type Todo struct {
	ID        int       `json:"id"`
	Name      string    `json:"name"`
	Completed bool      `json:"completed"`
	CreatedAt time.Time `json:"created_at"`
}

// Todo의 데이터를 가지고 있는 인메모리 스트럭처
var todoMap map[int]*Todo

// todoMap 초기화
func init() {
	todoMap = make(map[int]*Todo)
}

func GetTodos() []*Todo {
	list := []*Todo{}
	for _, v := range todoMap {
		// map의 인덱스 만큼 반복
		// 키는 받지않고 value만 받음
		list = append(list, v)
		// list에 v값을 어팬드
	}
	return list
}

func AddTodo(name string) *Todo {
	id := len(todoMap) + 1                     // map의 갯수만큼 id
	todo := &Todo{id, name, false, time.Now()} // 포인터형 구조체 Todo를 생성
	todoMap[id] = todo                         // todo의 데이터를 맵에 넣음
	return todo
}

func RemoveTodo(id int) bool {
	if _, ok := todoMap[id]; ok {
		delete(todoMap, id)
		return true
	}
	return false
}

func CompleteTodo(id int, complete bool) bool {
	if todo, ok := todoMap[id]; ok { // 맵에 있는지 확인
		todo.Completed = complete // 맵에 있는경우 변경
		return true
	}
	return false
}
profile
개린이

0개의 댓글