완벽한 설계를 하려고 하지 말자

백엔드&인프라 추종자·2025년 11월 7일

정우님 👏
그 생각 정말 잘하셨어요. 아주 현명한 접근이에요.

처음부터 완벽한 설계를 하려다 보면,
대부분은 “설계 지옥”에 빠집니다 —
코드를 쓰기 전에 너무 많은 걸 고려하다가 아무것도 안 돌아가는 상태가 되죠 😅


✅ 진짜 실무 고수들도 이렇게 합니다

“먼저 돌아가게 만들고, 나중에 좋게 만든다.”

이건 마틴 파울러(Martin Fowler)가 말한 유명한 원칙이에요:

"Make it work, make it right, make it fast."
(일단 돌아가게 만들고, 올바르게 고치고, 마지막에 빠르게 한다.)


💡 정우님에게 추천드리는 개발 순서

단계목표특징
Prototype기능 중심으로 빠르게 돌아가게 하기디렉토리 구조 단순, 코드도 직관적
Refactor구조 개선, 중복 제거, 책임 분리handler → service → repository 계층 분리
Optimize성능, 보안, 안정성 개선connection pool, presigned, limit, retry 등

✅ 예시: 초기에는 이렇게 단순하게 시작

func UploadHandler(c *gin.Context) {
    file, _ := c.FormFile("file")
    src, _ := file.Open()
    defer src.Close()

    // 그냥 바로 MinIO 업로드
    minioClient.PutObject(context.TODO(), "bucket", file.Filename, src, file.Size, minio.PutObjectOptions{})

    c.JSON(200, gin.H{"message": "uploaded"})
}
  • 그냥 “동작”만 보게 만드는 단계
  • 에러 처리, 구조 분리, DTO 전혀 신경 안 써도 됩니다.

✅ 기능이 안정되면 이렇게 리팩토링

type UploadRequest struct {
    File *multipart.FileHeader `form:"file" binding:"required"`
}

func UploadHandler(c *gin.Context) {
    var req UploadRequest
    if err := c.ShouldBind(&req); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }

    if err := service.UploadToMinio(req.File); err != nil {
        c.JSON(500, gin.H{"error": err.Error()})
        return
    }

    c.JSON(200, gin.H{"message": "ok"})
}

이제 서비스 코드(service/upload_service.go)로 분리하고,
테스트하기도 쉬워집니다.


✅ 이렇게 생각해보세요

  • 처음엔 “정답 코드”보다 “내가 이해한 코드”가 중요합니다.
  • 구조 개선은 언제든지 가능합니다.
  • 오히려 직접 불편을 느껴봐야 리팩토링 포인트를 정확히 이해하게 됩니다.

🧭 현실적인 팁

  • internal/, pkg/, service/ 같은 구조는 “나중에 옮기기 쉽게”만 생각해두세요.
  • 처음에는 main.go 안에 다 때려넣고,
    나중에 “아, 이 부분은 분리해야겠다” 싶을 때 디렉토리화해도 전혀 늦지 않습니다.

원하신다면 지금 정우님 프로젝트 상황 기준으로
👉 “현재 구조로 시작했다가, 자연스럽게 리팩토링할 수 있는 단계별 가이드
(예: 1단계: 단일 main.go → 2단계: service 분리 → 3단계: interface 도입)
이렇게 만들어드릴까요?

profile
AI 답변 글을 주로 올립니다.

0개의 댓글