안녕하세요! 그로스로그 입니다!😊 🌱
서버에서 미리 데이터를 받아두는 렌더링 이야기, 자바 프로그램이 메모리를 쓰는 방식, 그리고 갓 시험을 치르고 온 사람의 공부법. 3기 첫 회차입니다.
성장일지는 멤버들이 2주에 한 번씩 자신의 성장을 기록하는 활동이에요. 매 회차 운영진이 모든 글을 읽고, 그중 특히 마음에 남은 글을 함께 골라 큐레이션합니다.
3기는 2025년 3월에 시작됐습니다. 인원이 다시 한 번 늘면서 글의 결도 넓어졌어요. 첫 회차부터 실전 적용 · 기초 심화 · 자격증 후기가 나란히 올라왔습니다.
01
⚡ [Next.js] Tanstack Query로 SSR ???
신지훈 님
Next.js에서 Tanstack Query(구 React Query)로 서버 사이드 렌더링(SSR)을 구현하는 방법을 정리한 글입니다.
"Next.js를 쓰면서도 결국 리액트처럼 개발하고 있지 않나"라는 문제의식에서 출발해요.
'use client'를 습관적으로 붙이는 대신, 필요한 곳에만 쓰고 나머지는 SSR에 맡기자는 제안입니다.서버 단계와 클라이언트 단계를 나눠 설명하고, 바로 쓸 수 있는 예시 코드까지 붙였습니다.
글 마지막의 한 문장이 이 글의 성격을 잘 보여줍니다. "이제 'use client' 선언은 제발 필요한 부분에서만 하고 SEO 위해 SSR에게 양보하자!"
조금 더 들어가 보면
먼저 이 문제가 왜 생기는지부터 보겠습니다.
리액트는 CSR(Client-Side Rendering)을 택했습니다. 서버는 빈 껍데기 HTML만 주고, 브라우저가 자바스크립트를 받아 화면을 그리는 방식이에요. 덕분에 페이지를 옮겨 다녀도 깜빡임이 없고, 웹이 앱처럼 부드러워졌습니다.
그런데 대가가 있었습니다. 검색 엔진이 빈 페이지를 보게 된 겁니다. 검색 로봇이 방문했을 때 HTML에 아무 내용이 없으니까요. 그리고 보여줄 데이터가 많을수록 첫 화면이 뜨는 데 오래 걸렸습니다.
Next.js는 이걸 되돌리는 도구입니다. 서버에서 미리 HTML을 만들어 보내는 거죠. 그런데 글이 짚은 함정이 여기 있습니다. Next.js를 쓰면서도 실제로는 CSR처럼 개발하는 경우가 아주 많다는 것.
원인은 대개 'use client'입니다. 이 선언을 붙이면 그 컴포넌트는 브라우저에서 실행돼요. 그런데 useState나 useQuery 같은 걸 쓰려면 붙여야 하니, 습관적으로 최상단에 붙이게 됩니다. 그러면 그 아래 전부가 클라이언트 컴포넌트가 되고, 서버 렌더링의 이점이 사라집니다. Next.js를 쓰는데 SEO가 안 되는 상황이 이렇게 만들어져요.
📝 원문에서는 이렇게 나눕니다
해법은 데이터를 가져오는 일과 화면에 쓰는 일을 갈라놓는 것입니다. 서버 쪽 코드입니다.
// app/ssr-page/page.tsx (SSR 적용)
import { HydrationBoundary, QueryClient, dehydrate } from "@tanstack/react-query";
import PostList from "./post-list";
import { fetchPosts } from "./fetchPosts";
export default async function SSRPage() {
const queryClient = new QueryClient();
// ✅ 서버에서 미리 데이터 가져오기 (SSR)
await queryClient.prefetchQuery({
queryKey: ["posts"],
queryFn: fetchPosts,
});
return (
<HydrationBoundary state={dehydrate(queryClient)}>
<PostList />
</HydrationBoundary>
);
}
'use client'가 없습니다. 이 파일은 서버에서만 돕니다.
세 단어가 핵심이에요.
· prefetchQuery — 서버가 미리 데이터를 가져와 캐시에 담습니다
· dehydrate — 그 캐시를 클라이언트로 보낼 수 있는 형태로 말립니다(직렬화)
· HydrationBoundary — 브라우저에서 그걸 다시 물에 불려 캐시로 복구합니다
말린 미역을 보내서 물에 불리는 그림이 정확합니다. 서버가 가져온 데이터를 그대로 옮겨 심는 거예요.
받는 쪽은 이렇습니다.
// app/ssr-page/post-list.tsx (클라이언트에서 데이터 사용)
"use client";
import { useQuery } from "@tanstack/react-query";
import { fetchPosts } from "./fetchPosts";
const usePosts = () => {
return useQuery({
queryKey: ["posts"],
queryFn: fetchPosts,
});
};
export default function PostList() {
const { data, isLoading } = usePosts();
if (isLoading) return <p>Loading...</p>;
return (
<ul>
{data.map((post: any) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
여기엔 'use client'가 붙었습니다. 그런데 'use client'가 이 파일 하나에만 있다는 게 요점이에요. 데이터를 가져오는 무거운 일은 위쪽 서버 컴포넌트가 이미 끝냈고, 이 파일은 받아서 그리기만 합니다.
🧭 queryKey가 같아야 하는 이유
두 파일을 다시 보면 queryKey: ["posts"]가 양쪽에 똑같이 있습니다. 이게 우연이 아니에요.
useQuery는 실행될 때 먼저 캐시를 뒤집니다. ["posts"]라는 열쇠로 찾아보고, 이미 있으면 네트워크 요청을 아예 하지 않습니다. 서버가 넣어둔 값을 그대로 씁니다.
그래서 열쇠가 어긋나면 어떻게 될까요. 서버는 열심히 데이터를 가져왔는데 클라이언트가 못 찾고 API를 한 번 더 부릅니다. 화면은 정상으로 보이지만 요청이 두 번 나가죠. 에러가 안 나서 알아채기 어려운 종류의 낭비입니다.
그리고 글이 짚은 버전 주의도 실용적입니다. Tanstack Query v4와 v5는 문법이 다릅니다. v4의 Hydrate가 v5에서 HydrationBoundary로 바뀌었어요. 검색해서 나온 코드가 안 돌아가면 대개 버전 문제입니다.
큐레이터 노트
"쓰고는 있는데 제대로 쓰고 있나"를 물었다는 점에서 뽑았습니다.
Next.js를 도입하는 팀은 많습니다. 그런데 도입했다고 SSR이 저절로 되는 게 아니에요. 이 글은 자기가 쓰던 방식을 한 번 의심해봤습니다. "리액트식 개발을 벗어날 수 있지 않을까"라는 문장이 그 지점이에요.
바로 적용 가능한 형태로 정리한 것도 좋았습니다. 파일 두 개를 나란히 놓아서, 무엇이 서버이고 무엇이 클라이언트인지가 눈에 바로 들어옵니다. 개념 설명만 있는 글보다 훨씬 실전적이에요.
3기 첫 회차에 이런 글이 올라온 게 반가웠습니다. 최신 프레임워크를 쓰면서 생기는 고민은 자료가 빨리 낡아서, 이런 기록이 특히 값집니다.
02
☕ [JAVA] JVM 메모리 구조(Runtime Data Area)
박지수B 님
자바 프로그램이 실행될 때 메모리를 어떻게 나눠 쓰는지를 정리한 글입니다. Method Area, Heap, Stack, PC Register, Native Method Stack 다섯 영역을 하나씩 짚습니다.
단순 나열이 아니에요. Java 7의 PermGen이 Java 8에서 Metaspace로 바뀐 이유, Heap이 Young/Old로 나뉘는 까닭, Stack이 GC 대상이 아닌 이유까지 들어갑니다.
그리고 마지막에 다섯 영역을 표로 비교해 정리했습니다. 이전 글(JVM 개요)에 이어지는 시리즈의 두 번째 편이에요.
기초를 다루는 글인데 깊이가 상당합니다. 면접 단골 주제이기도 하고요.
조금 더 들어가 보면
JVM 메모리를 배울 때 가장 먼저 잡아야 할 축이 "누가 공유하고 누가 혼자 쓰는가"입니다. 글이 이걸 표로 정리해뒀어요.
모든 스레드가 공유하는 것 — Method Area, Heap
스레드마다 따로 갖는 것 — Stack, PC Register, Native Method Stack
이 구분이 왜 중요할까요. 공유하는 곳에서만 동시성 문제가 생기기 때문입니다.
여러 스레드가 같은 객체를 건드리면 값이 꼬입니다. 그런데 메서드 안에서 만든 지역 변수는 아무리 스레드가 많아도 안전해요. 각자 자기 Stack에 갖고 있으니까요. "지역 변수는 thread-safe하다"는 말의 근거가 여기 있습니다.
🧬 Heap이 나뉘는 이유 — 대부분의 객체는 금방 죽는다
Heap을 Young과 Old로 나누는 설계가 흥미롭습니다. 그냥 한 덩어리로 두면 안 될까요?
여기엔 관찰에서 나온 근거가 있습니다. 대부분의 객체는 만들어지자마자 곧 쓸모없어진다는 거예요. 메서드 안에서 잠깐 쓴 문자열, 반복문에서 만든 임시 객체 같은 것들이죠. 반대로 오래 살아남은 객체는 앞으로도 계속 살아남는 경향이 있습니다.
그러면 자주 죽는 것들만 모아놓고 거기만 자주 청소하면 효율이 좋아집니다. 그게 Young Generation이고, 거기서 일어나는 청소가 Minor GC예요. 영역이 작으니 빠르게 끝납니다.
Young 안이 또 Eden / Survivor 0 / Survivor 1로 나뉘는 것도 같은 맥락입니다. new로 만든 객체는 Eden에 놓이고, 청소에서 살아남으면 Survivor로 옮겨집니다. 여러 번 살아남으면 Old Generation으로 승격되고요.
글이 짚은 규칙 하나가 재미있습니다. "Survivor 0과 1 중 하나는 반드시 비어 있어야 한다." 살아남은 객체를 한쪽으로 몰아 옮기면서 메모리 조각이 생기지 않게 만드는 방식이에요. 빈 공간이 흩어지지 않고 한 덩어리로 유지됩니다.
🗄️ PermGen이 Metaspace가 된 이유
Java 8의 변화를 다룬 부분이 이 글에서 가장 실용적입니다.
Java 7까지 클래스 정보는 PermGen에 저장됐습니다. 문제는 크기가 고정이었다는 점이에요. -XX:MaxPermSize로 정해두면 그 이상 못 씁니다.
그러면 어떤 일이 생기냐면, 클래스가 많은 애플리케이션에서 OutOfMemoryError: PermGen space가 납니다. 스프링처럼 프록시 클래스를 동적으로 잔뜩 만드는 프레임워크에서 특히 그랬어요. 서버를 재시작하지 않고 애플리케이션을 다시 배포하면 클래스가 쌓여서 터지는 일이 흔했습니다.
Java 8은 이걸 Metaspace로 바꾸고 OS의 네이티브 메모리를 쓰게 했습니다. 필요하면 알아서 늘어나니 그 에러가 사라졌죠.
글이 표로 정리한 변화 중 하나가 특히 눈에 띕니다. String Pool이 PermGen에서 Heap으로 이동했다는 것. 문자열 상수도 GC 대상이 되면서, 안 쓰는 문자열이 정리될 수 있게 됐습니다.
큐레이터 노트
"어떻게 생겼나"를 넘어 "왜 그렇게 됐나"까지 간 글이라 뽑았습니다.
JVM 메모리 구조는 정리 글이 아주 많은 주제입니다. 그런데 대부분 다섯 영역을 나열하고 끝나요. 이 글은 PermGen에서 Metaspace로 바뀐 배경, Survivor 영역 하나가 비어 있어야 하는 이유 같은 걸 짚습니다. 외운 것과 이해한 것의 차이가 이런 데서 드러나요.
시리즈로 쌓아가는 방식도 좋았습니다. 앞 글에서 JVM 전체 구조를 다루고, 이 글에서 메모리를 파고들고, 다음 글에서 GC로 이어집니다. 실제로 이 저자는 다음 회차에 GC 글을 올리셨어요. 한 주제를 여러 편으로 나눠 파고드는 게 기록이 자산이 되는 방식입니다.
참고 자료를 네 개 밝혀둔 것도 눈에 띄었습니다. 여러 글을 읽고 자기 순서로 재구성했다는 뜻이니까요.
03
📝 2025 SQLD 1회차 필기 후기
한지수 님
시험을 치른 당일에 쓴 SQLD 응시 후기입니다. 아직 결과도 나오기 전에 기록했어요.
2024년 개정으로 뭐가 달라졌는지, 어떤 책과 강의를 썼는지, 어떤 순서로 공부했는지를 구체적으로 적었습니다.
그리고 "떨어지면 이렇게 보완하겠다"까지 미리 적어뒀어요. 결과와 무관하게 남는 기록입니다.
기술 글은 아닙니다. 그런데 자격증을 준비하는 사람에게는 어떤 개념 정리보다 실질적인 도움이 되는 종류의 글이에요.
조금 더 들어가 보면
이 글이 실질적으로 해결해주는 문제가 하나 있습니다. "개정됐다는데 예전 정보를 봐도 되나"입니다.
자격증을 준비할 때 이 불안이 시간을 많이 잡아먹습니다. 검색해서 나오는 후기는 대부분 개정 전 것이고, 그게 아직 유효한지 알 수가 없거든요. 그래서 정보를 찾는 데 시간을 쓰다가 정작 공부를 못 시작합니다.
글은 여기에 명확히 답합니다. 2024년 개정으로 추가된 건 정규표현식과 PIVOT/UNPIVOT 정도이고, 나머지는 사실상 같은 범위라고요. 그러니 "다른 정보 찾느라 시간 까먹을 것 없이 바로 공부 시작하라"는 겁니다.
"신유형이 많아 난이도가 올라갔다더라"는 소문에 대해서도 "겁먹을 수준까진 아닌 듯"이라고 직접 치른 사람의 감각으로 답합니다. 소문을 실측으로 바꿔주는 것 — 후기 글이 할 수 있는 가장 좋은 일입니다.
🧭 공부 방법이 구체적이라는 것
추천이 뭉뚱그려져 있지 않은 점도 좋습니다.
노랭이(SQL 자격검정 실전문제) 하나로 공부했다고 밝히면서, 단서를 정확히 답니다. "인터넷에 공유된 정리본을 찾아다닐 자신이 있다면" 괜찮고, "SQL 기본 개념이 부족하다면 개념서부터 시작하라"고요.
추천에 조건을 붙인다는 게 중요합니다. "이거 하나면 됩니다"는 읽는 사람의 상황을 모르는 조언이에요. 이 글은 자기 상황을 밝히고, 다른 상황에는 다른 답을 줍니다.
강의 추천도 구체적입니다. 이기적 영진닷컴의 핵심 이론 1~5회와 기출문제 풀이 영상을 들었고, 개정으로 추가된 정규식 부분이 거기엔 없어서 다른 강의로 보완했다고요. 한 자료의 빈 곳을 다른 자료로 메운 경로가 그대로 남아 있습니다.
그리고 이 문장이 좋았습니다. "group by 문제는 진짜 요 강의 듣고 난 이후로 10초 만에 풀게 됨". 막연한 "도움이 됐다"가 아니라 무엇이 어떻게 달라졌는지를 말하고 있어요.
🧭 결과를 모르는 채로 쓴 것
이 글에서 가장 눈여겨볼 부분은 시점입니다.
보통 후기는 합격한 다음에 씁니다. 그런데 합격 후에 쓰면 기억이 결과에 맞춰 정리됩니다. "이렇게 해서 붙었다"는 이야기가 되죠.
결과를 모른 채 쓰면 다릅니다. 확신할 수 없으니 본 대로만 적게 됩니다. 그래서 이 글에는 "합격 못한다면 공부법에 문제가 있는 것일 테니 보완해야지" 같은 문장이 들어가 있어요. 자기 방법을 검증 대상으로 두고 있는 상태입니다.
그리고 실제로 보완 계획까지 미리 적어뒀습니다. 개념서를 추가로 사겠다고요. 결과가 어느 쪽이든 다음 행동이 준비된 기록입니다.
큐레이터 노트
성장일지의 폭을 보여주는 글이라 뽑았습니다.
성장일지는 기술 글만 쓰는 활동이 아닙니다. 개발자로 성장하며 겪은 것이면 무엇이든 기록의 대상이에요. 자격증 준비도 분명히 그중 하나고요.
무엇보다 이 글은 읽는 사람에게 시간을 아껴줍니다. "개정됐는데 어떡하지"로 며칠 헤맬 사람이 이 글 하나로 바로 시작할 수 있어요. 커뮤니티 안에 이런 글이 쌓이면, 뒤에 오는 사람이 같은 자리에서 멈추지 않게 됩니다.
프로필의 한 줄도 눈에 남았습니다. "비전공자 개발자가 앞으로 얼마나 성장할지 개봉박두." 직전 글이 정보처리기사 합격 후기더라고요. 자격증을 하나씩 쌓아가는 과정이 블로그에 그대로 남아 있습니다.
💡 세 편을 겹쳐 읽으며
세 글이 서 있는 자리가 다릅니다. 최신 프레임워크, 언어의 밑바닥, 자격증 시험.
그런데 나란히 놓으면 공통점이 보입니다. 셋 다 "남들이 안 알려주는 전제"를 짚습니다.
신지훈 님의 글은 "Next.js를 쓰면 SSR이 되는 줄 알았는데"를 건드립니다. 도구를 도입했다고 그 이점이 저절로 오지 않는다는 것.
박지수B 님의 글은 "메모리는 그냥 알아서 관리되는 줄 알았는데"를 파고듭니다. GC가 있으니 신경 안 써도 될 것 같지만, 어디에 무엇이 놓이는지에 따라 성능도 안정성도 달라진다는 것.
한지수 님의 글은 "개정됐다니까 다 새로 공부해야 하는 줄 알았는데"를 확인해줍니다. 소문과 실제가 다르다는 것.
당연하다고 믿고 있던 걸 한 번 확인해보는 일 — 셋 다 그 일을 했습니다. 그리고 확인한 결과를 남겼기 때문에, 뒤에 오는 사람은 같은 착각을 하지 않아도 됩니다.
3기의 첫 회차로 좋은 출발이었어요.
이번 회차에서 가져갈 것
1. 'use client'는 잎사귀에만. 최상단에 붙이면 그 아래 전부가 클라이언트가 됩니다. 상태가 실제로 필요한 컴포넌트까지 내려서 붙이세요. 데이터 가져오기는 서버 컴포넌트에 남겨두고요.
2. 캐시 열쇠는 양쪽이 똑같아야 한다. queryKey가 어긋나면 서버가 미리 받아둔 데이터를 못 찾고 API를 한 번 더 부릅니다. 에러가 안 나서 모르고 지나가기 쉬워요.
3. 지역 변수가 안전한 이유를 알아두기. Stack은 스레드마다 따로 있습니다. 동시성 문제는 공유되는 곳(Heap, Method Area)에서만 생겨요. 이 구분을 알면 "어디를 조심해야 하는가"가 정해집니다.
4. 정보를 찾는 데 시간을 다 쓰지 말 것. 개정 여부, 최신 자료 유무를 확인하느라 시작을 미루는 경우가 많습니다. 먼저 겪은 사람의 후기 한 편이 그 며칠을 줄여줘요. 그리고 내가 겪었으면 남겨주는 것도요.
5. 결과가 나오기 전에 써두기. 합격 후에 쓰면 기억이 결과에 맞춰 정리됩니다. 과정을 정확히 남기려면 결과를 모를 때 쓰는 게 오히려 낫습니다.
좋은 글 남겨주신 신지훈 님, 박지수B 님, 한지수 님께 감사드립니다! 😊
다음 큐레이션으로 다시 찾아오겠습니다! 🌱
- 에디터 · 성장일지 큐레이터 -
※ 본 큐레이션은 각 저자가 공개한 글을 소개하는 것이며, 모든 원문의 저작권은 저자에게 있습니다. 저자 본인의 요청이 있을 경우 즉시 수정 또는 삭제합니다.