๐๊ฐ์ธํ๋ก์ ํธ Refactoring
์์ ์ ์
๋ฌด๋ณด๊ณ ๊ด๋ฆฌ (BSMG)
๋ผ๋ ํ ์ดํ๋ก์ ํธ๋ฅผ ์งํํ์๋ค.
golang๊ณผ ์นํด์ง๊ธฐ ์ํด ์งํํ๋ ์์
๋ฌผ์ด์๋๋ฐ, ๋ค์ ๋ณด๋ ๋๋ฌด ์ค๊ตฌ๋๋ฐฉ์ด๋ผ ์ด์ฐธ์ ๊ณต๋ถํ๋ ๋ง์์ผ๋ก Refactoring์ ํด๋ณด๊ณ ์ ํ๋ค.
๐ก ๋ณ๊ฒฝ์
์ฝ๋์ ๋ชจ๋ํ
- ์ด์ ์ฝ๋๋ handler์์ DB์ ์ฟผ๋ฆฌ ์ ๋ฌ ์ฝ๋๊น์ง ํ ๊ณณ์ ๋ชฐ๋นตํ์๋ค.
์ด์ ์ฝ๋
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// ์ฃผ๊ฐ ์
๋ฌด๋ณด๊ณ ์นดํ
๊ณ ๋ฆฌ setting
func setWeekRptCategoryRequest(writer http.ResponseWriter, request *http.Request) *WebErrorResult {
var err error
// ๋ถ์ ๊ฐ์ ์ธ๊ธฐ
queryString := "SELECT COUNT(*) FROM bsmgPart"
var count int
_ = db.QueryRow(queryString).Scan(&count)
var result BsmgTreeResult
result.Result.ResultCode = 1
if count > 0 {
result.PartTreeList = make([]*PartTree, count)
}
queryString = "SELECT part_idx,part_name FROM bsmgPart WHERE part_idx != 0" // ๊ด๋ฆฌ์๋ ์ ์ธ
rows, err := db.Query(queryString)
if err != nil {
fmt.Println("์ฟผ๋ฆฌ๋ฌธ ์ค๋ฅ", err)
return &WebErrorResult{http.StatusOK, ErrorInvalidParameter}
}
defer rows.Close()
var ii = 0
for rows.Next() {
var part_idx sql.NullInt32
var part_category sql.NullString
err := rows.Scan(&part_idx, &part_category)
if err != nil {
fmt.Println("์๋ฒ ๋ณ์ DB ๋ฐ์ดํฐ ํ ๋น ์ค๋ฅ", err)
return &WebErrorResult{http.StatusOK, ErrorInvalidParameter}
}
result.PartTreeList[ii] = &PartTree{}
result.PartTreeList[ii].Label = part_category.String
result.PartTreeList[ii].Value = "1-" + strconv.Itoa(int(part_idx.Int32))
result.PartTreeList[ii].Parent = "1"
ii++
}
result.PartTreeList[ii] = &PartTree{}
result.PartTreeList[ii].Label = "๋ถ์๋ณ ์ฃผ๊ฐ ์
๋ฌด๋ณด๊ณ "
result.PartTreeList[ii].Value = "1"
result.PartTreeList[ii].Parent = "0"
result.Result.ResultCode = 0
responseMsg, _ := json.Marshal(result)
sendResultEx(writer, request, http.StatusOK, responseMsg)
return nil
}
๊ธฐ์กด์ ์ด๋ฐ ์ฝ๋๋ค์ ๋ชจ๋ ๋ชฉ์ ์ ๋ง๊ฒ ๋๋์ด ๋ชจ๋์์ ๋ถ๋ฌ์ค๋๋ก ๋ณ๊ฒฝํ์๋ค.
๋ณ๊ฒฝํ ์ฝ๋
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// ์ฃผ๊ฐ ์
๋ฌด๋ณด๊ณ ์นดํ
๊ณ ๋ฆฌ ์ ๋ณด
func getPartTree(c echo.Context) (err error) {
log.Println("getPartTree")
var apiResponse define.BsmgTreeResult
server, _ := c.Get("Server").(*server.ServerProcessor)
server.Mutex.Lock()
defer server.Mutex.Unlock()
apiResponse.PartTreeList, err = server.DBManager.DBGorm.MakePartTree()
if err != nil {
log.Printf("%v \n", err)
apiResponse.Result.ResultCode = define.ErrorDataBase
return c.JSON(http.StatusOK, apiResponse)
}
apiResponse.Result.ResultCode = define.Success
return c.JSON(http.StatusOK, apiResponse)
}
๋ชจ๋ํ์ ๋ํด ๊ฐ์ด๊น์ด ์ดํดํ์ง ๋ชปํ๋ ๊ฒ ๊ฐ๋ค. ๋ถ๋ฆฌ์ํค๋๋ผ ์ ๋ง ํ๋ค์๋ค.
ํ๋ ์์ํฌ ์ฌ์ฉ
- ํ๋ ์์ํฌ๋ฅผ ๋ฌด์กฐ๊ฑด์ ์ผ๋ก ์จ์ผํ๋ ๊ฑด ์๋์ง๋ง, ๊ฐ๋ฐ์ ํ์ํ ๋ง์ ๊ธฐ๋ฅ์ ํธํ๊ฒ ์ ๊ณตํ๋ ์ธก๋ฉด๊ณผ ์ฝ๋์ ๊ฐ๊ฒฐ์ฑ์ ์ํด์ ์ฌ์ฉํ๊ณ ์ถ์๋ค.
Mutex๋ฅผ ํตํ ์ํธ ๋ฐฐ์
- ๋ณ๊ฑฐ์๋ ์ฝ๋๋ก ์ธํด ๋ฐ๋๋ฝ์ ๋ฌด์์์ ์ค์ ๋ก ๊ฒช์ด๋ดค๋ค. Mutex๋ ์กฐ์ฌํ ๋ค๋ค์ผ๊ฒ ๋ค๋ ๊ตํ์ ์ป์๋ค.
์ํธํ ์ ์ฉ
- ๊ธฐ์กด์๋ ๋น๋ฐ๋ฒํธ ๋ฑ์ ๊ฐ์ธ์ ๋ณด๋ฅผ ๊ทธ๋ฅ ์ ์ฅํ์๋ค. ์ด๋ฒ์๋ SHA256๋ฐฉ์๋ณด๋ค ๋ณด์์ฑ์ด ์ข์๊ฒ์ผ๋ก ์๋ ค์ง argon2 ์ํธํ ๋ฐฉ์์ ์จ๋ณด์๋ค.
JWT ์ฌ์ฉ
- ์ธ์ ์ด ์๋ JWT๋ฅผ ์ฌ์ฉํด๋ณด๊ณ ์ถ์๋ค.
- ํ ํฐ์ ํ๋๋ง ๋ง๋ค๋ค๊ฐ, AccessToken, RefreshToken 2๊ฐ์ ํ ํฐ์ ๋ง๋๋ ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝํ์๋ค.
Nginx ์ฌ์ฉ
- ๋ฆฌ๋ฒ์ค ํ๋ก์๋ฅผ ์ํด Nginx๋ฅผ ๊ฑฐ์ณ์ API์๋ฒ๋ก ๊ฐ๋๋ก ํ์๋ค.
๋์ปค๋ฅผ ํตํ ์ปจํ ์ด๋๋ก ๋ฐฐํฌ
- ์๋น์ค๋ฅผ ์ค์ ๋ก ๋์ปค ์ด๋ฏธ์งํํ์ฌ ๋ฐฐํฌ๊น์ง ํด๋ณด๋ ๊ณผ์ ์ ํ๊ณ ์ถ์๋ค.
- ์ด ๊ณผ์ ์์ ๋ฌด์ํ ์ํ์ฐฉ์ค๋ฅผ ๊ฒช๊ฒ ๋์๋ค.. ๋จ์ ๋ก์ปฌ ๊ฐ๋ฐํ๊ฒฝ์์ ์คํ, ๋ก์ปฌ์์ ์ปจํ
์ด๋๋ก ์คํ, ํด๋ผ์ฐ๋ ์๋ฒ์ ๋ฐฐํฌ๊น์ง ๊ณ ๋ คํด์ผ ํ ์ ์ด ๋ง์ ๊ณต๋ถ๋ฅผ ๋ง์ด ํด์ผํ๋ค.
๐ญ ์์ฝ๊ณ ๋ฏธํกํ ์
TDD
- ํ ์คํธ ๊ธฐ๋ฐ ๊ฐ๋ฐ์ ๋ํด ์์๋ณด๊ธฐ๋ ํ๊ณ , ์ด๋ฒ์๋ ๊ทธ๋ฐ์์ผ๋ก ํด๋ด์ผ์ง ํ์ง๋ง, ๋ง์ ์์ฑ์ด ์ฝ์ง ์์ ๋๋ฝํ๊ธฐ ์ผ์ค์๋ค.
- ๋ํ, TDD๋ ์๋ฌด๊ฒ๋ ์๋ ์ผ์ด์ค๋ถํฐ ์ฐจ๊ทผ์ฐจ๊ทผ ๋จ๊ณ๋ฅผ ๋ฐ์๊ฐ๋ฉฐ ๊ฐ๋ฐํด ๋๊ฐ์ผํ๋๋ฐ, ์ต๊ด์ ์ผ๋ก ๊ธฐ๋ฅ ๊ฐ๋ฐ -> ํ ์คํธ ์ฝ๋ ์์ฑ์ด ๋์๋ค.
- Github Actions๋ฅผ ํตํ WorkFlow๋ฌธ์๋ฅผ ์์ฑํ๋ฉฐ, ์ด๋ถ๋ถ์ด ์ฐธ ์์ฌ์ ๋ค.
ํ ์คํธ ์ฝ๋๋ง ์ ์ง๋จ์ผ๋ฉด, ๋น๋ ์ค๋ฅ, ๊ธฐ๋ฅ ์ค๋ฅ๋ฅผ ์๋ ํ ์คํธํ ์ ์์์ ํ ๋ฐ..
์ค๋ ๋์ ์ฌ์ฉ
- go๋ฃจํด๊ณผ ์ฑ๋๋ง์ ํตํด์ go๋ง์ ์ฅ์ ์ ๊ฐํํด๋ณด๋ ค ํ๋ค. ํ์ง๋ง ๊ธฐ์กด ๊ธฐ๋ฅ์์
์ฃผ๊ฐ ์ ๋ฌด๋ณด๊ณ ์๋ ์์ฑ
๋ง๊ณ ๋ ํ ๋งํ ๊ธฐ๋ฅ์ด ์์๋ค.
DB์์ ์ด ๊ทธ๋๋ง ๊ณ ๋ ค๋์์ด์๋๋ฐ, DB์ ๊ทผ ์ Mutex๋ฅผ ์ฌ์ฉํ์ฌ ์ํธ๋ฐฐ์ ๋ฅผ ํ๋ ๋ณ๋ ฌ์ฒ๋ฆฌ์ ์๋ฏธ๊ฐ ์๋ค๊ณ ํ๋จํ๋ค. - ์ถํ ๋ ํน์ ์ง์ธ์ ๋ค๋ฅธ ์๋น์ค์ ์ฐ๋์ํจ๋ค๋ฉด, ์ฌ์ฉ์ ๋๊ธฐํ ๋ฑ์์ ์ฌ์ฉํ ์ฌ์ง๊ฐ ์์ ๋ฏํ๋ค.
์ธ๋ถ API ์ฐ๋
- ๋ค์ด๋ฒ ์์ค๋ผ๋๊ฐ ์ฌ๋ฌ ์คํ API๋ฅผ ์ฌ์ฉํด์ ๊ธฐ๋ฅ ์ถ๊ฐ๋ ๊ณ ๋ คํ์๋๋ฐ, ๋ง์ ์ ์ฐ์ ์์์์ ๋ง์ด ๋ฐ๋ฆฌ๋ค๊ฐ ๊ฒฐ๊ตญ ์ํ๊ฒ ๋์๋ค.
์บ์ ์๋ฒ
- Redis๋ฅผ ํตํ ์บ์ ์๋ฒ๋ฅผ ๋์ด ๋ถํ์ํ DB ํธ๋ํฝ ๋น์ฉ์ ๋ฌ๋ณด๊ณ ์ถ์์ง๋ง, ์์ง ๋ฏธ์ ์ด๋คโฆ
๋์์ธ ํจํด ์ ์ฉ
- ํ๋ก์ ํธ์์
Adaptor
,Singleton
ํจํด ์ ๋๋ฅผ ์จ๋ณธ ๊ฒ ๊ฐ๋ค. - ์ฌ์ค ๋ฌด์กฐ๊ฑด์ ์ผ๋ก ์จ์ผํ๋ ๊ฑฐ๋ผ๊ธฐ๋ณด๋จ, ๋ฌธ์ ๋ฐ์์ ์ฌ์ง๋ฅผ ์ค์ด๋ ์ธก๋ฉด์์ ์ฌ์ฉํ๊ฒ ๋๋ ๊ฑฐ ๊ฐ๋ค.
- ๋์์ธํจํด ๊ณต๋ถ๋ ๊ณ์ํ์ฌ ํ์ฅ์ฑ์ด ์ข๊ณ ์ ์ง๋ณด์๊ฐ ์ฌ์ด ์๋ฒ๋ฅผ ๋ง๋ค๊ณ ์ถ๋ค.
API ๋ฌธ์ ์ ์
- Swagger๋ฅผ ํตํด์ ์งํํ๋ ค ํ๋๋ฐ Scalar ์๊ธฐ๋ ๋ง์ด ๋ณด์ด๊ณ ๋ ์ค ํ๋๋ก ๊ณ ๋ฏผ์ค์ด๋ค.
์ธ๊ฐ
- ์ธ๊ฐ๋ ํ์ฌ ํ๋ก ํธ๋จ์์๋ง ๊ตฌํ๋์ด์๋ค.
๊ทธ๊ฒ๋ ๋ฐ์ชฝ์ง๋ฆฌ์ธ ๊ฒ์ด, ํ์ธ์ ๋ณด๊ณ ์๋ฅผ ๋ง๊ตฌ ํ์ณ๋ณผ ์ ์๋ค.
(๋ค๋ง, ์์ ,์ญ์ ์ ๋ํ ๊ฒ์ ์ค์ ๋ ์ง๊ธ ์ด์๋ง ๊ฐ๋ฅํ๋๋ก ํ๋ค.) - JWT๋ ์๋ฒ ๋ฏธ๋ค์จ์ด์์ ํ์ฌ ๋ก๊ทธ์ธ ์ํ์ธ์ง ์๋์ง๋ง ํ๋ณํ๋ค.
- user ๋๋ฉ์ธ, report ๋๋ฉ์ธ์ ์ ๊ทผํ ๋ ํ ํฐ์ ํตํ ์ธ๊ฐ๋ฅผ ์๋ฒ์์๋ ๊ตฌํํ๋ ๊ฒ์ด ํ์ํ๋ค.
๐ก ํ๊ธฐ
ํ๋ก์ ํธ ์ฃผ์ ์ ๋งค๋ ฅ๋ณด๋ค๋ ๊ณต๋ถ์ ๋๋์ผ๋ก Refactoring์ ์งํํ๋ค.
์ฌ์ค ๋ฉ์ง๊ฒ ๋ง๋ค์ด๋ณด๊ณ ์ถ์์ง๋ง, ๋ถ์กฑํ ๋ฉด์ด ๋ง์๋ค.
ํฌ๊ฒ๋
์ํํธ์จ์ด ์ํคํ ์ฒ
๋์์ธ ํจํด
CI/CD
์๊ฒ๋
์ฝ๋๋ฅผ ๊ฐ๋ ์ฑ ์๊ฒ ์ง๋ ๋ฅ๋ ฅ
์ฃผ์์ ์ ๋ค๋ ๋ฅ๋ ฅ
- ๋ฐฐ์ด ๊ฒ์
๋ฐ๋ก ์ ๋ฆฌํ์ฌ ๊ธฐ๋กํ๋ ์ฑ์คํจ
ํ์ฌ ๋ด์์ ๋น์ฐํ ์ ํด๋ด์ผํ๋ ๊ฒ๋ค์ ํ๋ฉฐ ๋ด ๋ฅ๋ ฅ์ ๊ณผ์ ํ๊ฒ ๋ ๊ฒ ๊ฐ๋ค.
์ด์ ์ ์๊ฐํ์ง๋ง ๋ชจ๋ฅด๋ ๊ฒ๋ค ํฌ์ฑ์ด๊ณ ๊ณ์ ๋์ด๋๋ ๊ธฐ์ ์คํ๋ค๊ณผ ๋น ๋ฅธ ํธ๋ ๋์ ๋ณํ๊ฐ ์ฐธ ๋ฌด์ญ๊ฒ ๋๊ปด์ง๋ค.
๊ทธ๋ ์ง๋ง ์ง๊ธ์ ์๊ณ ๋๊ฒ๋ณด๋ค๋ ๊น๊ณ ์ข๊ฒ
์์์ผ๊ฒ ๋ค๋ ์๊ฐ์ด๋ค.
์ฒ์ฒํ ๊ทธ๋ฌ๋ ๊พธ์คํ
๋ผ๋ ๋ง์ ๋ชจํ ๋ก ๊ณ์ ๋์๊ฐ์ผ๊ฒ ๋ค.
ํ๋ค์๋ ์ !!
1.๋ ๊ฑฐ์๋ฅผ ์ ๊ฑฐํ๋ฉฐ ๊ธฐ์กด ๊ธฐ๋ฅ์ ์ด๋ฆฌ๋ ๊ฒ
2.์ง์์ ์ค์ฒ (๊ธฐ๋ฒ, ๊ธฐ์ ๋ฑ๋ฑ..)
๋ค๋ฅธ ํ ์ด ํ๋ก์ ํธ๋ ํด๋ณด๊ณ ์ถ์ด์ ์ด์ Refactoring์ ๋ฉ์ธ์ผ๋ก ํ์ง ์๊ณ , ์๊ฐ ๋ ๋ ํ๋ ค ํ๋ค.
๋ ์ฑ์ฅํ์ฌ ๋ฉ์ง ๋ฐฉํฅ์ผ๋ก ๋ฐ์ ์ํค๊ณ ์ถ๋ค!!
[๋ ํฌ์งํ ๋ฆฌ] https://github.com/MunProoo/bsmgRefactoring
TODO ๊ณต๋ถํ ๊ฒ ํฌ์คํ
- ํด๋ฆฐ ์ํคํ ์ฒ
- Echo ํ๋ ์์ํฌ ์ ํ ์ด์
- JWT
- ๋์์ธ ํจํด ๊ด๋ จ
- Docker ์ด๋ฏธ์ง ๋น๋ ๋ฐ compose ๊ด๋ จ ๋ฐ CPU ์ํคํ ์ฒ ๋ฑ ์ฃผ์์
- ๊นํ๋ธ ์ก์
- blue/green ๋ฌด์ค๋จ ๋ฐฐํฌ
- ์บ์ ์๋ฒ