Skip to content

Commit 7878f16

Browse files
committed
post: add
1 parent 2421124 commit 7878f16

5 files changed

Lines changed: 344 additions & 10 deletions

File tree

assets/gopher.png

-40.3 KB
Binary file not shown.

assets/gopher.webp

9.39 KB
Loading

assets/thisishaneum-history.webp

51.3 KB
Loading

content/개발 회고/Go로 정적 블로그 개발해 본 후기.md

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 344 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,344 @@
1+
---
2+
date: 2025-09-26
3+
category: [개발 회고]
4+
published: true
5+
fixed: false
6+
---
7+
8+
![](/assets/gopher.webp)
9+
10+
## 서론
11+
나는 블로그 유목민으로, 정말 많은 블로그를 개발하고 옮겨다녔다.
12+
GitHub Pages 블로그를 만들게된 기념으로,
13+
나의 블로그 활동 역사를 한 번 소개해보도록 하겠다.
14+
15+
## Blog Haneum
16+
2021년에 처음 HTML, CSS를 배우고 나서, [Blog Haneum](https://github.com/chebread/blog-haneum)이라는 정적 블로그를 만들었다.
17+
처음 웹 개발을 배우고 만든 블로그인지라, 모든 부분을 내가 개발했다.
18+
블로그 본문 부분의 CSS도 다 스타일링했다.
19+
20+
> 하나하나 개발하면서 즉각적으로 시각적인 결과물이 보여서 정말 재미가 있었다.
21+
> 이 블로그 개발로 하여금 웹 개발에 본격적으로 흥미가 생겼던 것 같다.
22+
23+
이 블로그를 스타일링 하면서 기억나는 것은,
24+
그 당시 클럽 하우스가 유행하던 때라
25+
클럽 하우스의 기술 블로그를 참고해서
26+
메뉴 팝업을 꾸몄었다.
27+
28+
그러나, 이 블로그의 가장 큰 단점이 있었는데, 포스팅을 하려면 html 파일을 직접 만들어야 한다는 것이었다.
29+
그래서 나는 html 템플릿 파일을 하나 만들고, `cp` 명령어를 사용하여 복붙해서 포스팅을 했었다.
30+
정말 귀찮았었다.
31+
32+
## 벨로그
33+
Blog Haneum 블로그를 통해 포스팅을 했지만 Read only만 되는지라, 독자들과 상호작용을 할 수 없었다.
34+
그때 벨로그라는 서비스에 대해서 알게 되었다.
35+
벨로그에는 댓글 기능이 자체적으로 탑제되어 있어서 독자들과 상호작용을 할 수 있었다.
36+
그래서 2022년에 벨로그를 개설하고 포스팅을 하기 시작했다.
37+
38+
처음으로 내가 쓴 [힙하게 코딩하는 방법](https://velog.io/@haneum/%ED%9E%99%ED%95%98%EA%B2%8C-%EC%BD%94%EB%94%A9%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95)이 게시한 지
39+
일주일도 안되서 피드 상위에 랭크되고, 좋아요가 50개를 넘어가서 너무 재밌었던 기억이 있다.
40+
41+
> 참고로, 지금은 좋아요가 무려 80개에 육박한다.
42+
43+
그때는 중학생이었어서, 비판적인 댓글에 대해서 매우 불쾌함을 느껴 반박하는 댓글도 남기기도 했다.
44+
그 당시, 나는 개발자 문화인 '비판'에 대해서 아예 몰랐던 것이다.
45+
그 이후, 나는 지속적으로 개발을 하면서 비판에 대해 생각이 많이 바뀌었다.
46+
개발자에게 '비판'이란 인격 모독이 아니라, 나를 성장케 하는 양분이라는 것을 점차 알게 되었다.
47+
48+
## Haneum Blog
49+
벨로그에서 활동을 하게 되면서
50+
다른 개발자분들의 벨로그를 많이 보게 되었다.
51+
벨로그를 많이 보면서 나는 많은 개발자분들이
52+
개인 사이트를 가지고 계신다는 사실을 알게 되었다.
53+
그래서 나를 소개하는 웹 사이트의 필요성에 대해서 자각하게 되었다.
54+
55+
그 당시 나는 React를 사용하여 SPA를 배우고 있었다.
56+
React 자체는 매우 쉬웠지만, SPA의 핵심 동작 방식은 잘 알지 못했다.
57+
그래서 나는 SPA의 핵심 동작도 익힐겸, ES6의 문법도 익힐겸해서
58+
SPA를 직접 만들어보기로 했다.
59+
그래서 [haneum blog](https://github.com/chebread/haneum-blog)라는 개인 블로그를 만들게 되었다.
60+
61+
> 이번에도 직접 정적 사이트 빌더를 만들었듯, 나는 핵심적인 것을 공부해서 직접 만드는 것을 참 좋아한다.
62+
> 어렸을 때 레고를 참 좋아했는데, 레고 설명서를 보고 일단 만든 후에 부셔버린 후,
63+
> 설명서를 통해 만들면서 익힌 핵심적인 아이디어를 통해 내가 창작하여 다시 만드는 것을 좋아했다.
64+
> 이런 나의 유년시절에 발현된 경향성이, 지금 이렇게 프로그래밍에서도 여실히 보여주는 듯하다.
65+
66+
> 나는 그리고 이론과 실전은 항상 같이 가야한다고 생각한다.
67+
> 이론만 공부한다면, 실전에서 어떻게 이론을 활용해야 하는지 감도 오지 않는다.
68+
> 그래서 다시 또 이론을 공부하게 되고, ...
69+
> 이렇게 쳇바퀴 처럼 이론만 공부하는 바보가 되어버린다.
70+
> 그리고 실전만 한다면, 또 이론은 알지 못한다.
71+
> 이론을 알기위해서 이론을 공부하게 되면
72+
> 너무 어려운 탓에 이론 공부를 도외시하게 되기 십상이다.
73+
> 그래서 내가 추천하는 방법은 이론과 실전을 함께 가라는 것이다.
74+
> 여담이지만, 내가 이번에 만든 정적 사이트 빌더도 Go 언어의 슬라이스를 공부하고
75+
> 슬라이스 개념을 익히고자 진행한 프로젝트이다.
76+
77+
이 프로젝트를 개발할 때는 SPA를 직접 구축하는 것이다 보니, CRA의 도움을 받지 못했음으로
78+
79+
```js
80+
import webpack from 'webpack';
81+
import fs from 'fs-extra';
82+
import paths from '../config/paths.js';
83+
import webpackConfig from '../config/webpack.config.js';
84+
import SpeedMeasurePlugin from 'speed-measure-webpack-plugin';
85+
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
86+
const config = webpackConfig('production'); // start는 원래 development 환경에서 진행하기 때문에 그냥 인자를 이것으로만 줘도 괜찮다.
87+
const configWithSmp = new SpeedMeasurePlugin().wrap(config);
88+
configWithSmp.plugins.push(
89+
new MiniCssExtractPlugin({
90+
filename: '[name].[hash:8].css',
91+
chunkFilename: '[name].[hash:8].chunk.css',
92+
})
93+
);
94+
const compiler = webpack(configWithSmp);
95+
fs.emptyDirSync(paths.appBuild); // build directory remove
96+
fs.copySync(paths.appPublic, paths.appBuild, {
97+
dereference: true,
98+
filter: file => file !== paths.appHtml,
99+
});
100+
const build = () => {
101+
compiler.run();
102+
};
103+
build();
104+
105+
```
106+
107+
직접 이렇게 Webpack과 Babel을 구성했다.
108+
109+
그리고 `build.js`, `start.js` 이렇게 파일을 만들어서
110+
111+
```json
112+
"build": "node scripts/build.js"
113+
"start": "node scripts/start.js"
114+
```
115+
116+
이렇게 실행하곤 했다.
117+
118+
```js
119+
import routes from './routes.js';
120+
import render from './render.js';
121+
122+
const router = path => {
123+
if (!(path === window.location.pathname)) {
124+
window.history.pushState(null, null, window.location.origin + path);
125+
}
126+
if (!routes[path]) {
127+
if (!(path === '/')) {
128+
render('/404');
129+
}
130+
return;
131+
}
132+
render(path);
133+
window.onpopstate = () => {
134+
if (!routes[window.location.pathname]) {
135+
if (!(window.location.pathname === '/')) {
136+
render('/404');
137+
}
138+
return;
139+
}
140+
render(window.location.pathname);
141+
};
142+
};
143+
144+
export default router;
145+
```
146+
147+
그리고 이렇게 `window` 객체를 활용해서 라우터를 구현 해보기도 했다.
148+
149+
SPA를 구현하는데 있어서, 라우터가 가장 구현하기 힘들었다.
150+
라우터가 SPA의 핵심이었음으로, 일단 라우터가 만들어져야 SPA 사이트를 만들 수 있었다.
151+
그래서 거의 몇 주 동안은 라우터만 개발하고 개선했던 거 같다.
152+
그 당시에는 JavaScript도 잘 익히지 못했던 터라,
153+
정말 구현하는데 힘들었다.
154+
SPA를 직접 개발하면서,
155+
SPA 라이브러리/프레임워크를 그래서 쓰는 것이구나를 몸소 알게 되었다.
156+
157+
소스코드가 더 궁금하다면, https://github.com/chebread/haneum-blog를 참고해보기를 바란다.
158+
159+
새로운 블로그를 만들기는 했지만, 기존에 운영중이던 Blog Haneum은 종료하지는 않았다.
160+
이 블로그는 thisishaneum 프로젝트를 시작하면서 종료하게 되었다.
161+
162+
> Blog Haneum을 종료하고 빠르게 thisishaneum을 만들 수 있을 줄 알았지만,
163+
> 1년이 넘게 소요될 줄은 꿈에도 몰랐다.
164+
165+
내가 SPA의 핵심적인 것을 이해하고자
166+
Haneum Blog을 개발했지만,
167+
솔직히 SPA가 어떻게 돌아가는지 정확하게 알지는 못했다.
168+
왜냐하면 프레임워크/라이브러리가 로직이 보이지 않게 처리하고 있고,
169+
그것을 추상적인 개념으로서 기능화하여 개발자에게 제공하기 때문이다.
170+
거의 핵심적인 기능은 실제 코드 베이스를 봐야만 알 수 있다.
171+
그러나 라이브러리/프레임워크들이 고도화됨에 따라
172+
코드 베이스가 너무 복잡해지고 커지기 때문에
173+
기능을 알기 위해 코드 베이스를 모두 보고 공부한다는 것은
174+
물리적으로 불가능하다.
175+
176+
> 나는 솔직히 아직도 SPA가 어떻게 돌아가는지 알지 못한다.
177+
> 왜냐하면 프레임워크/라이브러리가 로직이 보이지 않게 처리하고 있고,
178+
> 그것을 추상적인 개념으로서 기능화하여 개발자에게 제공하기 때문이다.
179+
> 그래서 나는 SPA를 사용해서 개발하는데 너무 애를 먹었다.
180+
> 나는 이런 추상적인 기술을 배우는 것은 의미가 없다고 판단되서,
181+
> 그래서 프론트엔드 개발자를 포기하고,
182+
> 시스템 프로그래밍을 공부하게 되었다.
183+
> 추상적인, 분절된 지식을 배우는 것보다 핵심적인 기술을 배우는 것이 몇 배는 쉬운 것 같다.
184+
185+
## thisishaneum
186+
Haneum Blog를 만들었지만,
187+
내가 완벽주의 성향이 있는지라,
188+
약간 부족하다고 생각되어 새로운 개인 사이트를 만들게 되었다.
189+
해당 사이트는 블로그의 성격보다는, 나를 표현하는 것에 더욱더 초점을 맞춰 개발하고자 했다.
190+
191+
그 당시 나는 SPA 라이브러리인 React를 공부하고 있었음으로
192+
React로 정적 사이트를 만들게 되었다.
193+
그러나, React로 정적 사이트를 만드는 것은 매우 어려움이 많았다.
194+
Horizontal scroll을 구현하기 위해
195+
GSAP 라이브러리를 사용하는데,
196+
MPA 방식의 사이트에서는 간단하게 JavaScript CDN만 불러오면 되는데,
197+
React 에서는 너무 설정할 것이 많았고, 매우 복잡하게 설정해야 했다.
198+
그리고 React 라이브러리의 동작 방식이 너무 추상적인지라,
199+
도대체 어떻게 다른 라이브러리를 불러와서 활용하는지에 대한 로직도 내 머릿속으로 시각화되지 않았다.
200+
솔직히 아직도 시각화가 되지 않는다.
201+
도대체 SPA 라이브러리/프레임워크는 어떤 위계, 절차로서 동작하고 있는 것인가?
202+
프론트엔드 라이브러리/프레임워크 보다 시스템 프로그래밍이 더 이해하기 단순한 거 같다.
203+
204+
> 다만, 단순함이 쉬움을 의미하지는 않는다.
205+
206+
그 당시 이러한 깊은 동작 방식들을 알려고 하니,
207+
추상적인 내용들 밖에 나오지 않았다.
208+
그래서 이해를 포기했었다.
209+
그리고 그 당시에는 개발은 생산과 흡사하다고 생각했기 때문에,
210+
그냥 "동작하면은 됬지"라는 생각을 했던지라,
211+
딱히 깊이 있는 이해를 하지 않아도 상관은 없겠다라는 생각을 했다.
212+
213+
> 지금 생각해보면 참 안일한 생각이다.
214+
> 개발은 본질적으로 생산이 아니기 때문이다.
215+
216+
내가 지금은 GitHub에는 공개하지 않고 있지만,
217+
이 당시 거의 1년 넘게 thisishaneum을 수 십개 버전으로 만들었었다.
218+
완벽주의가 심했던 터라, 다 만들어 놓았는데도 조금 바꾸고 싶어서
219+
또 새롭게 만들고 그랬었다.
220+
221+
> <img src="/assets/thisishaneum-history.webp" width="300">
222+
> 이게 그 기록들이다.
223+
224+
그렇게 삽집을 계속 하면서, 이대로는 웹 개발 공부에 진척이 없을 것 같아
225+
thisishaneum을 React로 만드는 것을 아예 포기하게 되었다.
226+
227+
> 그러나 참 웃긴 것은, 이때 삽질하던 것이 지금 나에게 매우 큰 도움이 되었다는 것이다.
228+
> 이는, 프론트엔드 프로그래밍이 일개 마크업이 아니라는 것에 대한 증명이다.
229+
> 프론트엔드 개발 또한 프로그래밍이다.
230+
> 프론트엔드는 프로그래밍이 아니라는 주장은,
231+
> 프론트엔드 개발을 제대로 안해본 개발자들이 하는 주장이다.
232+
233+
## thisishaneum.com
234+
그 후, 2023년 내가 Next.js를 배운 후에,
235+
Next.js가 정적 사이트를 만드는데 아주 쉽다고 해서
236+
다시 정적 사이트를 만드는 것에 도전하게 되었다.
237+
나는 삽질을 최소화하기 위해 다른 개발자가 만든 프로젝트를 참고해서 개발을 진행하였다.
238+
블로그 프로그램 로직은 [maxleiter](https://github.com/MaxLeiter/maxleiter.com/)를 참고해서 개발했다.
239+
블로그 디자인은 [Ryan Dahl](https://tinyclouds.org/)를 참고해서 개발했다.
240+
241+
다른 것을 참고해서 개발하니 매우 순조롭게 개발이 끝났고,
242+
cloudflare로 Domain을 연결하고, vercel에 배포하니
243+
매우 그럴듯한 [thisishaneum.com](https://github.com/chebread/thisishaneum) 블로그가 완성되었다.
244+
내가 창조한 것은 아니지만, 그래도 Haneum Blog 이후 제대로 배포해본 거는 오랜만이라 뜻깊게 여겨졌다.
245+
246+
이렇게 thisishaneum.com 블로그를 개발하고
247+
열심히 블로그 활동을 이어가던 중,
248+
하나 눈에 띄는 것을 발견하게 되었다.
249+
바로 나의 thisishaneum.com 리포지토리에 folk가 1로 되어 있는 것이다.
250+
251+
누가 folk를 했을 까 궁금하여 history를 보니 어떤 인도 개발자가 folk를 한 것을 알게되었다.
252+
그러나, 얼마 지나지 않아 인도 개발자의 GitHub를 들어가보니 충격을 받았다.
253+
바로 나의 블로그를 그냥 folk해서 그대로 자기 사이트처럼 배포를 해놓고 운영중이었던 것이다.
254+
나의 포스팅을 영어로 번역해서 그대로 포스팅하고 있었다.
255+
참으로 충격이었다.
256+
그 때는 사람들이 아무도 안 볼줄 알고 나의 개인적인 글도 가득했는데,
257+
그대로 그 인도 개발자가 무단으로 복붙해서 활용중이었던 것이다.
258+
그 때 나는 오픈소스를 잘 활용해야 겠다는 생각이 번쩍 들었다.
259+
내가 MIT License를 사용했던 지라, 그 개발자를 신고할 수도 없었으므로,
260+
개인적으로 이메일을 통해 지워잘라고 재차 부탁해서, GitHub에서 만큼은 없애게 되었다.
261+
그 이후로 나는 블로그를 GitHub를 통해 포스팅할 때는 매사 신중히 포스팅하려고 하고 있다.
262+
263+
이 인도 개발자 사태 이후,
264+
사건도 사건이고
265+
블로그 또한 내가 직접 만든 것은 아닌지라
266+
thisishaneum.com 블로그에 대한 애정이 많이 떨어지게 되었다.
267+
그래서 GitHub에 블로그 소스코드는 올려놓는 대신, 배포는 중단하게 되었다.
268+
269+
## chebread.github.io
270+
다시 블로그를 직접 내 손으로 개발해봐야 겠다고 생각되어,
271+
2024년 초에 블로그 디자인을 완성했다.
272+
273+
> 참고로, 이때 만든 디자인이 지금 현재 이 블로그이다.
274+
275+
디자인을 완성한 후에, Next.js로 개발을 하려고 했었다.
276+
그렇게 계획만 하고 있다가 거의 1년이 지나버렸다.
277+
블로그 개발이 늦어진 여러 이유들이 있겠으나,
278+
고등학교 진학 이후 어려움으로 인해 번아웃이 있었다.
279+
280+
그렇게 2025년이 되고,
281+
프론트엔드를 포기하고 시스템 프로그래밍을 공부하였고,
282+
Go 언어를 공부하면서 문득 이런 생각이 들게 되었다.
283+
284+
"Go로 정적 블로그 빌더를 만들면 어떨까?"
285+
286+
Go 언어를 배우고 있는지라, 이론을 체화하는데에도 매우 큰 도움이 될 것 같아
287+
블로그 정적 빌더를 만들게 되었다.
288+
디자인은 이미 만들어 놓은 것이 있어 순조롭게 개발되었다.
289+
그리고 로직 부분은 시대가 시대인지라, 생산적인 측면이라고 판단되는 것은
290+
LLM을 사용했고, 핵심적인 로직은 내가 직접 구현했다.
291+
292+
내가 구현한 로직은 여러 로직이 있지만,
293+
중요한 것들만 소개해보자면,
294+
PostsData로 데이터 중앙화를 했고
295+
GetFilePaths를 클로저 방식으로 구현한 것이다.
296+
PostsData 로직은 너무 길어서 첨부하기는 그러므로, GetFilePaths 함수만 첨부하겠다.
297+
298+
```go
299+
func GetFilePaths(dirPath string) []string {
300+
var files []string
301+
var f func(string) []string // 클로저 함수 타입 선언
302+
f = func(dirPath string) []string {
303+
entries, err := os.ReadDir(dirPath)
304+
if err != nil {
305+
fmt.Println(err)
306+
}
307+
for _, v := range entries {
308+
if v.IsDir() {
309+
subDirPath := dirPath + "/" + v.Name()
310+
f(subDirPath)
311+
} else {
312+
if filepath.Ext(v.Name()) == ".md" || filepath.Ext(v.Name()) == ".mdx" {
313+
files = append(files, dirPath+"/"+v.Name())
314+
}
315+
}
316+
}
317+
return files
318+
}
319+
f(dirPath)
320+
return files
321+
}
322+
```
323+
324+
더 많은 로직이 궁금하다면, https://github.com/chebread/chebread.github.io를 참고하기 바란다.
325+
326+
그렇게 재밌게 Go로 정적 블로그를 완성하게 되었고,
327+
그 결과물이 지금 당신이 보고 있는 이 [chebread.github.io](https://chebread.github.io/) 블로그이다.
328+
329+
이 블로그의 핵심 기능을 소개해보자면,
330+
파일명 기반 블로그 제목 및 링크 생성이다.
331+
즉, 파일명이 곧 블로그 제목이다.
332+
파일명에는 한글이 들어가도 상관 없고, 특수문자가 들어가도 상관이 없다.
333+
자동으로 정적 빌더가 처리해서 링크를 생성해준다.
334+
굳이 불편하게 마크다운 프론트 메터에서 `title`로 설정하지 않아도 되며,
335+
`slug` 속성을 지정하지 않아도 된다.
336+
파일명으로 `title``slug`를 함께 지정할 수 있다.
337+
이는 기존의 정적 빌더에서는 않던 매우 편리한 기능이라고 볼 수 있다.
338+
339+
이 기능 말고도 다른 재밌는 기능이 많으니 https://github.com/chebread/chebread.github.io를 참고해보기를 바란다.
340+
341+
## 결론
342+
나의 짧은 블로그 유목민 역사가
343+
개인 블로그를 운영하고 싶은 개발자분들께
344+
조금이나마 도움이 되기를 바란다.

0 commit comments

Comments
 (0)