Section · 02

개발 Development/Engineering

07 Posts
Latest · 개발 2026.11.05 13 min read

SEO 생각하기, Lighthouse 100점이 채울 수 없는 것

점수는 100점인데 보이지 않는 페이지 프런트엔드 개발에서 SEO는 흔히 배포 전에 한 번 훑고 지나가는 체크리스트의 모습으로 다뤄집니다. 페이지마다 고유한 title을 넣고, meta description을 다듬고…

Posts최신순
2026.10.20
개발
내가 만든 프로그램을 다른 사람에게 배포하려면 왜 돈을 내야 할까

내 컴퓨터에서 멀쩡하게 실행되는 프로그램도 다른 사람의 컴퓨터에서는 위험한 프로그램으로 취급될 수 있습니다. 코드를 잘못 작성해서도, 악성 기능을 넣어서도 아닙니다. 단지 누가 만들었는지 확인할 수 없다는 이유만으로 실행이 차단되기도 합니다. 그렇다면 운영체제는 프로그램의 출처를 어떻게 확인하며, 사용자는 그 프로그램을 신뢰할 수 있는지 어떻게 판단할까요. 작년에 처음으로 제 이름으로 iOS 앱을 출시하면서 애플 개발자 프로그램에 무려 10만 원이 넘는 연회비를 지불했고, 이후 맥용 데스크톱 앱도 만들어 앱스토어에 올리려 했지만 심사를 받기도 전에 Xcode의 업로드 단계에서 막혔습니다. 두 번의 경험을 거치며 소프트웨어를 만드는 일과 그것을 사람들이 실제로 사용할 수 있는 상태로 만드는 일은 전혀 다른 문제라는 것을 실감했습니다. 돈을 내고서야 시작된 배포 회사에서 모바일 앱을 개발해왔기 때문에 앱을 배포하려면 인증서가 필요하다는 사실 자체는 알고 있었습니다. 다만 그때는 늘 회사의 개발자 계정으로 작업했던 터라, 제 이름으로 앱을 출시하려면 직접 개발자 프로그램에 가입하고 매년 10만 원이 넘는 비용을 내야 한다는 사실은 프리랜서가 된 뒤에야 알 수 있었습니다. 애플은 Xcode를 비롯한 개발 도구를 무료로 제공하고, 자신의 기기에서 앱을 개발하고 테스트하는 일도 무료 계정으로 어느 정도 가능합니다. 하지만 애플 앱스토어를 통해 앱을 배포하려면 유료 개발자 계정을 만들어야 합니다. 계정을 만들었다고 모든 문제가 해결되는 것도 아니었습니다. 인증서, 프로비저닝 프로파일(provisioning profile), 코드 서명(code signing) 같은 설정이 얽혀 있었고, 인증서 관련 오류를 해결하느라 적지 않은 시간을 보냈습니다. 웹 서비스는 서버에 코드를 배포하고 도메인을 연결하면 누구나 접속할 수 있습니다. 물론 웹에도 HTTPS 인증서가 필요하고 서버 비용도 들지만, 적어도 운영체제 제조사에 개발자로 등록하고 돈을 내야만 제가 만든 웹사이트를 공개할 수 있는 것은 아닙니다. 그런데 모바일 애플리케이션은 달랐습니다. 프로그램을 완성했다고 해서 곧바로 다른 사람의 기기에 배포할 수 있는 것은 아니었습니다. 내 맥북에서만 쓰이는 Tiskofy(?) 그 뒤에는 Tiskofy라는 맥용 데스크톱 애플리케이션을 만들었습니다. 이름은 별다른 의미 없이 알파벳을 조합해 지었고, 혼자서 '티스코피'라고 부르고 있습니다. 유튜브 URL을 입력하면 영상이나 음원을 추출해 로컬에 저장하는 프로그램입니다. Tauri 프레임워크를 사용해서 리액트로 사용자 인터페이스를 만들고, 러스트로 운영체제의 네이티브 기능을 활용할 수 있도록 개발했습니다. 러스트를 어느 정도 다룰 줄 알았기 때문에 선택해 본 프레임워크였고 당시 처음 써 보는 것이었는데, 화면은 익숙한 웹 기반 코드를 사용해 만들면서도 브라우저만으로는 다루기 어려운 파일 시스템과 운영체제 기능에 접근할 수 있다는 점이 흥미로웠습니다. 개발 자체는 비교적 순조로웠습니다. 제 맥북에서는 의도한 대로 실행되었고, 지금도 필요할 때마다 저는 이 프로그램을 사용하곤 합니다. 그런데 문제는 이게 영원히 오직 저 혼자만 쓸 수 있는 프로그램이라는 사실(?)입니다. Xcode 업로드조차 통과하지 못했던 앱 야심차게 AI의 도움을 받아 앱 아이콘까지 만들어서 티스코피를 Mac App Store에 정식 등록하고 싶었지만, 저는 그 당시 앱스토어 심사에서 거절당한 것도 아니고 심사를 받기 위해 Xcode에서 빌드를 업로드하는 단계부터 통과하지 못했습니다. 정확한 오류 내용은 지금 기억나지 않습니다. 영상과 음원을 처리하려고 포함했던 FFmpeg 계열의 바이너리가 관련되어 있었던 것으로 기억합니다만, 당시 오류 로그가 남아 있지 않아 원인을 단정하기는 어렵습니다. 앱 내부에 포함된 실행 파일의 서명이 문제였는지, 다른 빌드 설정과 충돌했던 것인지도 확실하지 않습니다. 지금 다시 관련 문서를 읽어보니 앱스토어에 배포하는 앱에는 코드 서명과 앱 샌드박스(App Sandbox) 등 여러 요구사항이 적용된다고 합니다. 별도의 실행 파일이 포함된 앱이라면 그 파일의 서명과 번들 구조도 함께 확인해야 합니다. 당시에는 이런 내용을 충분히 이해하지 못한 채 오류를 해결하려고 했습니다. 무엇을 수정해도 인증 관련 오류가 반복되었던 것으로 기억합니다. 다만 벌써 1년 전의 일이라 정확히 어떤 문제였는지는 가물가물합니다. 아무튼 Tiskofy는 끝내 앱스토어에 올라가지 못했습니다. 제 컴퓨터에서는 아무런 문제 없이 실행되는 프로그램인데, 다른 사람에게 배포하려면 왜 이렇게 많은 검증을 거쳐야 하는 것일까요. 코드 서명은 무엇을 증명할까 이 질문에 답하려면 먼저 코드 서명이 무엇인지 이해해야 합니다. 코드 서명은 소프트웨어에 디지털 서명을 붙여 서명자의 신원과 프로그램의 무결성을 검증할 수 있게 하는 기술입니다. 여기에는 공개키 암호화 기술이 쓰입니다. 개발자는 서로 대응하는 개인키(private key)와 공개키(public key)를 사용하는데, 개인키는 서명을 만드는 데, 공개키는 그 서명이 올바른지 검증하는 데 사용합니다. 프로그램에 서명할 때는 먼저 프로그램의 데이터를 해시(hash)라는 함수로 처리합니다. 해시는 입력 데이터를 일정한 길이의 값으로 바꾸는 함수로, 입력이 조금만 달라져도 일반적으로 전혀 다른 결과가 나옵니다. 개발자는 이 해시값을 바탕으로 개인키로 디지털 서명을 만들고, 사용자의 컴퓨터는 공개키로 서명을 검증해 실제 프로그램의 내용이 서명된 데이터와 일치하는지 확인합니다. 그 덕분에 서명한 뒤에 누군가 실행 파일을 수정했는지를 알아낼 수 있습니다. 그런데 여기에는 한 가지 문제가 남습니다. 개인키와 공개키는 누구나 만들 수 있으니, 악성 프로그램을 만드는 사람도 자기 프로그램에 디지털 서명을 붙일 수 있습니다. 서명이 올바르다는 사실만으로는 그 서명자가 믿을 만한 사람인지 알 수 없다는 뜻입니다. 이 간극을 메우는 것이 인증 기관(Certificate Authority, CA)입니다. 인증 기관은 정해진 절차에 따라 신청자의 신원을 확인하고, 그 신청자의 공개키와 신원 정보를 연결한 디지털 인증서를 발급합니다. 운영체제는 자신이 신뢰하는 인증 기관으로 이어지는 인증서인지 검증해 서명자의 신원을 확인합니다. 결국 코드 서명은 프로그램에 이름표를 붙이는 일이 아니라, 누가 서명했는지 확인하고 서명 이후 내용이 바뀌지 않았는지 검증할 수 있도록 신뢰 관계를 구성하는 과정입니다. 다만 코드 서명이 프로그램의 안전성을 보증하는 것은 아닙니다. 악성 프로그램도 유효한 인증서로 서명될 수 있기 때문입니다. 서명은 프로그램이 무해하다는 증명서가 아니라, 검증 가능한 서명자의 신원과 프로그램의 무결성을 확인하기 위한 수단입니다. macOS의 공증과 Gatekeeper macOS에는 코드 서명 외에도 공증(notarization)이라는 절차가 있습니다. 이 노터라이제이션, 애플의 공증이란 쉽게 말하면 개발자가 제출한 소프트웨어에 알려진 악성 콘텐츠나 코드 서명 관련 문제가 있는지 자동으로 검사하는 절차입니다. 검사를 통과하면 공증 티켓이 발급됩니다. macOS의 보안 기능인 Gatekeeper는 인터넷에서 내려받은 프로그램을 처음 실행할 때 코드 서명과 공증 여부 등을 확인합니다. 필요한 검증을 통과하지 못한 프로그램은 경고가 나타나거나 실행이 차단될 수 있습니다. 코드 서명이 누가 서명했고 그 뒤로 내용이 바뀌지 않았는지 확인하는 절차라면, 공증은 애플이 해당 프로그램에 자동화된 보안 검사를 수행했다는 사실을 확인하는 절차입니다. 여기서 구분해야 할 것이 있습니다. 애플 앱스토어를 통한 배포와 개발자 웹사이트에서 설치 파일을 직접 제공하는 방식은 요구사항이 다릅니다. 애플 앱스토어에 등록하는 앱은 스토어의 제출과 심사 절차를 거치고, 별도의 Developer ID 공증은 필요하지 않습니다. 반면 앱스토어 밖에서 직접 배포하는 앱은 일반적으로 Developer ID 인증서로 코드 서명을 하고 애플의 공증을 거쳐 Gatekeeper가 신뢰할 수 있도록 준비해야 합니다. 맥에서 직접 배포할 때 흔히 쓰는 파일 형식이 dmg인데, 사용자는 dmg 파일을 열고 그 안의 애플리케이션을 Applications 폴더로 옮겨 설치합니다. 다만 dmg 파일을 만드는 일과 그 안의 애플리케이션이 보안 검사를 통과하는 일은 별개입니다. 더 복잡한 문제는 애플리케이션 안에 별도의 실행 파일이 들어 있을 때 생깁니다. 이 티스코피처럼 FFmpeg 같은 외부 도구를 사용하는 프로그램이라면 앱 자체뿐 아니라 내부에 포함된 실행 파일에도 올바르게 코드 서명을 해야 할 수 있습니다. 또한 앱스토어를 거치지 않고 직접 배포하기 위해 공증을 받을 때는 하드닝 런타임(Hardened Runtime)이라는 보안 기능도 적용해야 합니다. 하드닝 런타임은 프로그램이 실행되는 동안 외부에서 코드를 주입하거나 메모리를 부당하게 변경하는 등의 공격을 어렵게 만드는 macOS의 보안 기능입니다. 즉, 프로그램을 누가 만들었는지 확인하는 것뿐 아니라 실행 중에도 안전하게 보호받을 수 있도록 여러 보안 조건을 충족해야 하는 것입니다. 앱스토어 빌드에도 외부 실행 코드의 서명, 앱 샌드박스, 번들 구성에 관한 별도의 요구사항이 있습니다. 다만 티스코피가 실제로 어느 단계에서 어떤 규칙을 충족하지 못했는지는 당시의 오류 기록이 없으므로 알 수 없습니다. 개발할 때는 하나의 프로그램으로 보였던 것이, 배포 단계에서는 각각 검증해야 하는 여러 실행 파일과 설정의 집합이 됩니다. 윈도우의 exe 파일도 크게 다르지 않습니다 윈도우용 애플리케이션도 비슷한 보안 체계를 사용합니다. 다만 이 부분은 제가 직접 배포를 경험한 것이 아니어서 마이크로소프트의 공식 문서를 참고했습니다. 윈도우에서 인터넷으로 내려받은 exe 파일을 실행하다 보면 “Windows의 PC 보호”라는 경고 화면이 나타나는 경우가 있는데, Microsoft Defender SmartScreen이라는 보안 기능이 보여주는 경고입니다. 이 경고가 나타난다고 해서 반드시 악성 프로그램이라는 뜻은 아니고, 서명되지 않았거나 아직 충분한 평판(?)이 쌓이지 않은 프로그램에도 나타날 수 있다고 합니다. 윈도우에서 실행 파일에 코드 서명을 하려면 전통적으로 인증 기관에서 코드 서명 인증서를 발급받아 써왔습니다. 대표적으로 조직의 신원을 검증하는 OV(Organization Validation) 인증서와 더 엄격한 신원 확인 절차를 거치는 EV(Extended Validation) 인증서가 있습니다. 이 인증서는 웹사이트의 HTTPS 인증서처럼 공개키 기반의 신뢰 체계를 이용하지만 용도는 다릅니다. HTTPS 인증서는 서버의 신원을 확인하고 브라우저와 서버 사이의 통신을 보호하는 데 쓰이고, 코드 서명 인증서는 실행 파일의 서명자와 무결성을 검증하는 데 쓰입니다. 물론 윈도우용 프로그램을 배포할 때 반드시 별도의 상용 인증서를 구입해야 하는 것은 아닙니다. 예를 들어 Microsoft Store에 MSIX 형식으로 애플리케이션을 제출하면 스토어에서 검증을 거친 패키지에 마이크로소프트가 서명을 적용하므로 개발자가 상용 코드 서명 인증서를 구입할 필요가 없습니다. Microsoft Store에 MSI나 exe 설치 파일을 제출할 때는 개발자가 신뢰할 수 있는 인증서로 직접 서명해야 합니다. 자신의 웹사이트에서 exe 파일을 배포할 때는 서명이 법적·기술적으로 항상 필수인 것은 아니지만, 서명되지 않은 프로그램은 스마트스크린 경고가 나타날 가능성이 높아 일반 사용자를 대상으로 배포하기에는 불리합니다. 유효한 인증서로 서명했다고 해서 스마트스크린 경고가 반드시 사라지는 것도 아닙니다. 스마트스크린은 해당 프로그램이 얼마나 널리 사용되었는지, 이전에 보안 문제가 발견된 적은 없는지 등 여러 정보를 종합해 위험성을 판단합니다. 따라서 처음 배포하는 프로그램은 안전하게 만들어졌더라도 신뢰성을 판단할 만한 정보가 충분히 쌓이지 않아 경고가 나타날 수 있습니다. 과거에는 더 비싼 EV 인증서를 구입하면 경고를 즉시 피할 수 있다는 점이 장점으로 소개되기도 했지만, 지금은 EV 인증서도 그런 효과를 보장하지 않는다고 합니다. 결국 윈도우와 macOS 모두 프로그램을 만드는 일과 신뢰할 수 있는 형태로 배포하는 일 사이에 별도의 절차를 두고 있습니다. 그런데 왜 돈을 내야 할까 애플 개발자 프로그램에 처음 가입했을 때 가장 의아했던 것도 이 부분이었습니다. 프로그램을 만드는 개발 도구는 무료로 제공하면서, 왜 다른 사람에게 배포하려면 별도의 비용을 내야 할까요. 인증서를 발급하고 신뢰 체계를 유지하는 데에는 실제로 비용이 들 것입니다. 인증 기관은 신청자의 신원을 확인해야 하고, 인증서가 유효한지 검증할 수 있는 시스템을 운영해야 하며, 개인키가 유출되거나 인증서가 악용되면 이를 폐기하고 더 이상 신뢰하지 않도록 하는 체계도 갖춰야 합니다. 다만 소프트웨어를 배포하기 위해 지불하는 비용이 모두 같은 성격을 갖는 것은 아닙니다. 애플 개발자 프로그램의 연회비는 인증서 한 장의 가격이라기보다는 앱스토어 배포와 여러 개발자 서비스를 이용하기 위한 비용에 가깝습니다. 반면 윈도우에서 사용하는 상용 코드 서명 인증서는 인증 기관이 개발자의 신원을 확인하고 인증서를 발급·관리하는 데 드는 비용이라는 성격이 더 강합니다. 마이크로소프트는 인증서를 직접 구매하는 방식 외에도 클라우드 기반 코드 서명 서비스인 Azure Artifact Signing을 제공합니다. 과거 Trusted Signing이라고 불렸던 서비스로, 공식 문서에 안내된 기본 요금은 월 9.99달러부터입니다. 하지만 가격이 저렴하다고 누구나 이용할 수 있는 것은 아닙니다. 2026년 10월 기준으로 개인 개발자가 이용할 수 있는 지역은 미국과 캐나다로 제한되어 있습니다. 한국의 개인 개발자라면 이 서비스를 바로 쓰기 어렵고, 직접 배포하기 위한 서명에는 다른 인증 기관의 인증서를 고려해야 할 수 있습니다. 이처럼 모든 운영체제와 배포 방식에서 비싼 인증서가 필수인 것은 아니지만, 개인 개발자가 자신의 웹사이트에서 설치 파일을 직접 제공하려 하면 신원 확인과 코드 서명, 운영체제별 보안 정책이라는 장벽을 만나게 됩니다. 사용자를 악성 프로그램으로부터 보호해야 한다는 필요성은 충분히 이해합니다. 출처를 알 수 없는 프로그램이 사용자 컴퓨터의 파일을 읽거나 수정하고 다른 프로그램을 실행할 수 있다면 위험하기 때문입니다. 그렇지만 이제 막 프로그램 하나를 만들어본 개인 개발자와 오랫동안 소프트웨어를 배포해온 기업이 이런 절차를 감당하는 데에는 분명한 차이가 있습니다. 더구나 인증서를 사서 프로그램에 서명한다고 소프트웨어가 자동으로 신뢰를 얻는 것도 아닙니다. 개발자가 신원을 증명하는 일과 실제로 믿을 수 있는 프로그램을 만드는 일은 또 다른 문제이기 때문입니다. AI가 낮춘 문턱, 낮추지 못한 문턱 AI의 발전으로 요즘은 바이브코딩을 통해 프로그램을 만드는 사람이 많아졌습니다. 개발 경험이 그리 많지 않은 사람이라도 원하는 기능을 자연어로 설명하고 AI가 작성한 코드를 고쳐가며 실제로 동작하는 프로그램을 만들 수 있게 된 것입니다. 저는 특히 데스크톱 애플리케이션이 일상에서 마주하는 크고 작은 문제를 해결하기에 좋은 도구라고 생각합니다. 별도의 서버 없이도 실행할 수 있고, 데이터를 외부로 전송하지 않고 사용자의 컴퓨터에서 직접 처리할 수도 있습니다. 파일 시스템이나 운영체제의 기능을 활용할 수 있다는 점도 장점입니다. 파일을 일괄 변환하거나 반복적인 업무를 자동화하고, 특정 형식의 데이터를 정리하는 프로그램이 대표적인 예입니다. 과거에는 이런 프로그램을 직접 만들려면 상당한 개발 지식이 필요했지만, 이제는 AI의 도움으로 훨씬 적은 시간과 노력만으로도 구현할 수 있게 되었습니다. 그런데 이렇게 만든 프로그램을 다른 사람에게 배포하거나 판매하려고 하면 전혀 다른 문제가 시작됩니다. 프로그램을 exe나 dmg 파일로 패키징하는 작업은 AI가 상당 부분 도와줄 수 있습니다. 코드 서명에 필요한 명령어를 작성하거나 빌드 설정을 수정하는 일도 마찬가지입니다. 하지만 개발자 계정을 등록하고 신원을 확인받거나, 필요한 인증서와 서명 서비스를 이용할 자격을 갖추는 일은 코드를 잘 작성한다고 해결되지 않습니다. AI가 대신 작성해줄 수 있는 코드와 실제 사람이나 조직이 자신의 신원을 증명해야 하는 절차는 별개의 문제이기 때문입니다. 여기에 운영체제별 빌드 환경, CPU 아키텍처, 외부 바이너리, 자동 업데이트, 라이선스 관리, 결제 시스템까지 고려하기 시작하면 개인적인 도구 하나를 만드는 일과 소프트웨어 제품을 배포하고 판매하는 일 사이에 얼마나 많은 단계가 있는지 알게 됩니다. 저 역시 티스코피를 만들면서 그 차이를 경험했습니다. 프로그램을 구현하는 데에는 AI의 도움을 많이 받았지만, 배포 과정에서 생긴 문제는 끝내 풀지 못했습니다. 지금 생각하면 제가 완성한 것은 “동작하는 프로그램”이었지, 아직 “배포할 준비가 된 제품”은 아니었던 것 같습니다. AI 덕분에 프로그램을 만드는 사람이 늘어난 만큼, 이런 문제를 처음 마주하는 사람도 많아지지 않을까 생각합니다. 프로그램을 만드는 자유와 배포하는 책임 물론 티스코피가 Xcode 업로드 문제를 해결했다고 해서 반드시 앱스토어에 등록되었을 것이라고 장담할 수는 없습니다. 유튜브에서 영상이나 음원을 추출하는 기능은 사용 방식에 따라 저작권이나 플랫폼 이용약관과 관련된 문제가 생길 수 있고, 앱스토어 심사 지침도 검토해야 하기 때문입니다. 당시 제가 부딪힌 벽은 단지 배포 과정에 있는 여러 관문 중 하나였습니다. 코드 서명과 공증은 꼭 필요한 기술입니다. 사용자의 컴퓨터에서 실행되는 프로그램은 웹사이트보다 운영체제의 기능에 폭넓게 접근할 수 있어서, 출처를 확인할 수 없는 실행 파일을 아무런 검증 없이 실행하도록 두는 것은 상당한 위험을 동반합니다. 다만 그 신뢰 체계를 누가 관리하고, 어떤 기준으로 프로그램을 신뢰하며, 그 비용을 누가 부담해야 하는지는 따로 생각해볼 문제입니다. 웹 역시 브라우저의 보안 정책과 인증 기관의 신뢰 체계에 의존하므로 완전히 자유로운 공간은 아니지만, 웹사이트를 공개하는 일과 사용자의 컴퓨터에서 실행될 바이너리를 배포하는 일에는 요구되는 검증 방식과 책임에 차이가 있습니다. AI가 소프트웨어 개발의 진입 장벽을 낮추고 있는 지금, 전문 개발자가 아니더라도 자신의 문제를 풀려고 만든 프로그램을 다른 사람에게 판매하려는 시도는 더 많아질 것이라고 생각합니다. 그 과정에서 코드를 쓰는 능력만큼이나 배포와 보안, 신뢰 체계를 이해하는 일이 중요해질 것입니다. 프로그램을 만드는 일이 쉬워졌다고 해서 그것을 다른 사람에게 건네는 일까지 쉬워진 것은 아닙니다. 제 맥북에는 여전히 티스코피가 설치되어 있습니다. 앱스토어에 등록하지도, 다른 사람에게 판매하지도 못했지만 제게 필요한 기능은 잘 수행하는 프로그램입니다. 처음에는 프로그램만 완성하면 누구에게나 배포할 수 있을 것이라고 생각했습니다. 하지만 소프트웨어를 배포한다는 것은 단순히 완성된 파일을 전달하는 일이 아니었습니다. 그 파일이 어디에서 왔고, 누가 책임지며, 사용자는 무엇을 근거로 그것을 신뢰할 수 있는지까지 생각해야 하는 일이었습니다. AI는 프로그램을 만드는 데 필요한 시간과 기술의 장벽을 낮췄습니다. 하지만 자신이 만든 프로그램에 대한 책임까지 대신 져주지는 않습니다. 프로그램을 완성하는 일과 그것을 다른 사람이 신뢰하고 사용할 수 있는 제품으로 만드는 일은 여전히 서로 다른 문제입니다. 참고 링크 Apple Developer, 「Become a member」 Apple Developer Documentation, 「Notarizing macOS software before distribution」 Apple Developer, 「Distributing software on macOS」 Microsoft Learn, 「Code signing options for Windows app developers」 Microsoft Learn, 「SmartScreen reputation for Windows app developers」 Tauri, 「macOS Code Signing」

2026.10.13
개발
구름 아래에는 건물이, 서버 안에는 전기가

예전에 다니던 어떤 한 회사에서 러스트(Rust)를 사용해 온프레미스 소프트웨어를 개발했던 적이 있습니다. 그 회사를 들어가면서 "온프레미스"라는 용어를 처음 접하게 되었는데, "온프레미스"란 간단하게 설명하자면 서비스 제공자의 클라우드 환경이 아니라 고객이 직접 통제하는 자체 서버 환경에 소프트웨어를 설치하고 운영하는 방식을 말합니다. 그 회사에서 일하면서 사무실 안에 별도의 서버실이 있는 것도 처음 보았습니다. 그전까지 제게 서버란 IP 주소나 접속 계정처럼 모니터 안에서만 접하는 추상적인 존재에 가까웠습니다. 소프트웨어가 아무리 추상적인 형태로 존재하더라도 그 아래에는 결국 물리적인 컴퓨터가 있다는 사실을 이미 머리로는 알고는 있었습니다만, 그 사실을 눈으로 실감한 것은 그 서버실에서였던 것 같습니다. 지금은 상주 프리랜서로 회사에서 클라우드 기반으로 제공되던 서비스를 로컬 서버 기반의 온프레미스 서비스로 바꾸는 작업을 진행하고 있습니다. 클라우드 콘솔에서 몇 번의 클릭으로 생기던 것들을 온프레미스에서는 하나씩 직접 마련해야 하다 보니, 그동안 “있겠거니” 하고 넘어갔던 물리적인 층이 다시 눈앞으로 올라오는 느낌이 듭니다. 구름 아래에는 건물이 있다 2006년 아마존이 저장 공간을 제공하는 S3와 가상 서버를 제공하는 EC2를 선보이면서, 오늘날 우리가 익숙하게 사용하는 "클라우드" 서비스가 본격적으로 확산되기 시작했습니다. 그전에도 서버를 빌려 쓰는 호스팅 서비스는 있었지만, 서버와 저장 공간을 필요할 때 프로그램으로 확보하고 쓴 만큼 비용을 내는 방식이 본격적으로 퍼진 것은 이때부터였습니다. 직접 장비를 사서 둘 곳을 마련하고 회선을 끌어오지 않아도, 계정 하나와 결제 수단 하나만 있으면 서버를 확보하는 일이 훨씬 간편해졌습니다. "구름"이라는 이름의 유래도 흥미롭습니다. 찾아보니 이는 네트워크 구성도에서 인터넷처럼 내부를 일일이 그리지 않아도 되는 영역을 구름 모양으로 뭉뚱그려 표시하던 오래된 관습에서 비롯되었다고 합니다. 구름은 그 자리에 아무것도 없다는 표시가 아니라, 여기서는 '속을 들여다보지 않아도 된다'는 의미를 가진 표시였습니다. 그러나 그림에서 지워졌다고 해서 이를 가능케 하는 물리적인 것들이 모두 사라진 것은 아닙니다. 클라우드는 결국 누군가의 데이터센터에 있는 서버를 빌려 쓰는 일이고, 서버가 물리적으로 어딘가에 놓여 있다는 점은 온프레미스나 클라우드나 둘 다 같습니다. 다만 그 건물이 누구의 것인지, 전기요금과 고장 난 디스크를 누가 맡는지, 필요한 자원을 어떤 방식으로 확보하고 늘려가는지가 달라지는 것입니다. 클라우드에서 온프레미스로 옮기며 다시 보이기 시작한 것 이번 작업을 하며 제게 가장 크게 다가온 차이는 ‘무엇을 직접 책임져야 하는가’였습니다. 클라우드 사업자들은 책임 공유 모델이라는 말로 이 관계를 설명하는데, 건물과 전원과 하드웨어는 사업자가 관리하고, 그 위의 운영체제와 애플리케이션, 데이터와 설정은 어떤 서비스를 쓰느냐에 따라 사업자와 사용자가 나눠 맡는다는 구분입니다. 온프레미스로 옮기자 이 책임의 상당 부분이 조직 안으로 내려왔습니다. 디스크 교체와 백업, 네트워크 장비의 관리와 보안 패치까지 누군가는 직접 맡아야 합니다. 옮기는 작업에서 가장 크게 다가오는 부분은 관리형 서비스입니다. 클라우드에서는 데이터베이스, 오브젝트 스토리지, 메시지 큐, 로드밸런서, 인증을 서비스 형태로 가져다 쓰는 일이 흔한데, 온프레미스로 옮길 때는 이런 서비스가 맡던 기능을 어떻게 유지할지 다시 정해야 합니다. 직접 설치할 수 있는 오픈소스나 상용 제품으로 대체하기도 하고, 구조를 바꿔 일부 기능을 합치거나 없애기도 합니다. 체크박스 하나 뒤에 그렇게 많은 것이 있었다는 사실은 체크박스가 없어지고 나서야 보입니다. 한 사업자의 전용 서비스에 깊이 기대어 만든 시스템일수록 옮기기 어렵다는 뜻이기도 해서, 벤더 종속이라는 말이 이 지점에서 현실이 됩니다. 어느 쪽을 택하든 서버가 놓일 공간과 전기, 냉각과 네트워크는 필요합니다. 클라우드는 그 부담을 없애는 기술이라기보다, 그것을 다른 사람의 책임으로 옮겨 보이지 않게 만드는 서비스에 가깝습니다. 그렇다면 클라우드에서 그 책임을 대신 맡고 있는 곳은 어디일까요. 데이터센터는 무엇을 하는 곳일까 뉴스에서 데이터센터라는 말을 가장 크게 들은 것은 2022년 10월 판교의 데이터센터에서 불이 나 카카오 서비스가 오래 멈췄을 때였던 것으로 기억합니다. 많은 사람들이 일상적으로 사용하는 카카오톡 메신저 기능뿐 아니라 택시 호출과 결제까지 한꺼번에 멈추면서, 서로 다른 수많은 서비스들이 사실은 같은 건물 하나에 의존하고 있었다는 것을 실감하게 된 사건이었습니다. 지금 다시 찾아보니 그 당시 불은 배터리 쪽에서 시작되었다고 하는데, 이후에는 불이 난 것 자체뿐 아니라 이중화와 복구 체계를 충분히 갖추고 있었는지도 쟁점이 되었다고 합니다. 데이터센터는 서버라는 컴퓨터를 랙이라는 선반형 틀에 층층이 꽂아 모아두고, 그 기계들이 24시간 멈추지 않도록 필요한 것을 전부 갖춘 건물입니다. 여기엔 우선 전기가 있습니다. 외부 전력이 끊겨도 서버가 멈추지 않도록 무정전전원장치(UPS)와 배터리, 그다음을 받아주는 비상 발전기가 겹겹이 붙습니다. 서버가 소비한 전력의 상당 부분은 결국 열이 되기 때문에, 그 열을 식히기 위한 냉각 설비에도 상당한 전력이 필요합니다. 통신사 회선은 여러 경로로 들어오고, 화재를 대비한 소화 설비와 출입 통제, 보안 요원도 있습니다. 안정적인 운영을 위해 전원과 냉각, 통신 회선 등을 이중화하기도 하는데, 일부 장비에 문제가 생겨도 다른 장비가 곧바로 그 역할을 이어받도록 설계합니다. 클라우드 사업자들은 장애의 영향을 분산하기 위해 물리적으로 분리된 가용 영역(availability zone)을 운영합니다. 하나의 가용 영역은 하나 이상의 데이터센터로 구성되고, 서비스를 여러 가용 영역에 나눠 두도록 설계하면 특정 시설에 장애가 생겨도 서비스를 계속 운영할 가능성이 높아집니다. 제가 처음 본 회사 서버실은 이 데이터센터의 아주 작은 축소판이었습니다. 스타트업에서는 보기 드문 경험이지만, 데이터센터 수준까지는 아니어도 은행과 병원, 제조 현장, 공공기관처럼 데이터를 건물 안에 두어야 하는 곳에서는 자체 서버실을 짓고 운영하는 경우가 적지 않습니다. 반대로 클라우드 사업자가 운영하는 대형 데이터센터는 서버를 수천, 수만 대씩 수용하고, 큰 캠퍼스는 도시 하나에 맞먹는 전력을 쓰도록 계획되기도 한다고 합니다. 규모는 달라도 필요한 것은 같습니다. 기계가 있고, 전기가 들어오고, 열이 나고, 그것을 식히고, 외부와 연결할 선이 필요합니다. 클라우드 요금표에는 결국 이 모든 것을 밤낮으로 유지하는 비용이 들어 있습니다. 가장 작은 서버실은 내 책상 위에 데이터센터가 서버의 가장 큰 집이라면, 가장 작은 집은 제 책상 위에 있습니다. 개발을 하다 보면 “로컬에서 서버를 띄운다”는 말을 자주 하게 되는데, 이때 서버를 띄운다는 것은 요청을 받아 처리하고 응답하는(serving) 프로그램을 실행한다는 뜻이고, 로컬은 그 프로그램이 지금 앞에 놓인 내 컴퓨터에서 돌아간다는 뜻입니다. 서버 프로그램을 실행하는 순간 내 컴퓨터의 CPU와 메모리, 디스크, 그리고 전기가 그대로 쓰입니다. 브라우저에서 localhost라는 주소로 접속하는 것은 인터넷 어딘가에 다녀오는 일이 아니라 내 컴퓨터가 자기 자신에게 말을 거는 일이어서, 이 주소를 루프백(loopback)이라고 부릅니다. 노트북을 끄면 서버도 함께 멈춥니다. 24시간 운영을 전제로 만들어진 데이터센터와 달리, 제 노트북은 원래 그런 역할을 하도록 마련된 기계가 아닙니다. 이렇게 보면 로컬에서 실행하는 개발 서버도, 조직이 자체적으로 운영하는 온프레미스 서버도, 클라우드에서 실행하는 서버도 결국 같은 원리로 동작합니다. 요청을 받아 처리하는 프로그램이 어딘가의 컴퓨터에서 실행되고 있다는 점입니다. 다만 그 컴퓨터가 어디에 있고, 누가 관리하며, 어떤 방식으로 외부와 연결되는지가 달라집니다. 클라우드에서 실행되던 서비스를 온프레미스로 옮기는 일은 결국 클라우드 사업자의 인프라에서 실행되던 프로그램을 조직이 통제하는 서버 환경으로 가져오는 일입니다. 규모와 운영 방식은 달라도, 컴퓨터에서 서버 프로그램을 실행한다는 점에서는 노트북에 로컬 서버를 띄우는 일과 같은 원리 위에 있습니다. 그런데 여기까지 내려와도 아직 ‘서버’라는 말은 하나의 검은 상자처럼 남아 있습니다. 0과 1 아래에는 전기와 빛 서버 안으로 한 단계 더 내려가면 CPU에는 트랜지스터(transistor)가 수십억 개씩 들어 있고, 트랜지스터는 전기로 여닫는 작은 스위치입니다. 흔히 0과 1을 전기의 연결과 끊김으로 설명하지만, 컴퓨터가 다루는 0과 1은 실제로는 회로가 구분할 수 있는 두 가지 전기적 상태, 이를테면 높은 전압과 낮은 전압으로 구현됩니다. 기억도 마찬가지입니다. 메인 메모리인 DRAM은 미세한 축전기에 저장된 전하로 정보를 기억합니다. 전하가 조금씩 새어 나가기 때문에 전원이 공급되는 동안에도 주기적으로 다시 채워야 하고, 전원이 끊기면 정보도 사라집니다. SSD는 플래시 메모리 셀에 저장된 전하에 따른 전기적 특성을, 하드디스크는 자성 물질의 자기 상태를 이용해 데이터를 기록한다고 합니다. 메신저 한 줄이나 사진 한 장처럼 화면에서는 형태가 없어 보이는 정보도 서버 안에서는 반드시 어떤 물질의 상태로 존재합니다. 게다가 "무선 인터넷”이라는 말이 워낙 대중화되어 있어서 정말로 인터넷은 무선으로 이루어진다고 착각할 수 있겠지만, 와이파이는 기기와 공유기 사이를 전파로 연결하고, 유선 회선을 쓰는 일반적인 가정이라면 공유기 뒤로는 랜선이 건물의 통신실로, 거기서부터는 광케이블이 땅속을 지나갑니다. 광케이블에서는 전기 신호 대신 빛의 변화를 이용해 데이터를 보내고, 그 빛은 목적지 장비 앞에서 다시 전기 신호로 바뀝니다. 결국 바깥세상과 이어지는 길도 전기와 빛의 신호를 선을 따라 보내는 일입니다. 대륙 사이의 통신은 바다 밑에 깔린 해저 케이블이 대부분을 담당합니다. 통신 위성이 대륙을 이어줄 것 같지만, 찾아보니 국제 데이터 통신의 압도적인 부분이 해저 광케이블을 지난다고 하고, 한반도에도 그 케이블이 올라오는 랜딩 스테이션이 있다고 합니다. 한 줄의 메시지가 바다를 건너려면 해저의 선을 지나야 한다는 사실을 떠올릴 때마다, 인터넷이라는 말이 얼마나 많은 물리적 사실을 가리고 있는지 생각하게 됩니다. 마치며 서비스를 클라우드에서 온프레미스로 옮기는 지금의 작업은 눈에 보이지 않던 이런 층들을 하나씩 직접 마주하게 해줍니다. 콘솔에서 클릭 몇 번으로 끝나던 일을 하나하나 직접 마련하다 보면, 앱 하나가 열리는 데에도 얼마나 많은 장비와 사람이 필요한지가 보입니다. 화면에 뜬 메시지 한 줄의 뒤에는 서버가 놓인 건물이 있고, 밤새 돌아가는 냉각기가 있고, 칩 속의 전하와 바다 밑을 지나는 광섬유가 있고, 그 전기를 만들고 공급하는 시설과 사람들이 있습니다. 클라우드는 이 모든 것을 매번 생각하지 않아도 되게끔 만들어 주었지만, 다만 눈에 보이지 않게 되었다고 해서 없어진 것은 아닙니다.

2026.10.12
개발
Ghost, 인블로그, 헤드리스 CMS 사이에서 워드프레스를 다시 보다

비교의 기준부터 블로그를 만들어주는 도구는 많지만, 같은 블로그를 만들어준다고 해서 같은 종류의 선택은 아닙니다. 이 도구들을 완전히 배타적인 네 종류로 나누기는 어렵습니다. 운영 방식으로는 서비스가 서버를 관리하는 호스팅형(hosted service)과 사용자가 직접 운영하는 셀프 호스팅형(self-hosted)이 있고, 콘텐츠와 화면의 관계로는 전통적인 CMS와 헤드리스 CMS(headless CMS)를 구분할 수 있습니다. 여기에 Markdown 파일과 정적 사이트 생성기를 조합하는 방식까지 비교 대상으로 놓아보겠습니다. 인블로그, Wix, Substack은 서비스 안에서 글을 쓰고 서버는 서비스가 대신 운영하는 호스팅형입니다. 워드프레스와 Ghost는 소프트웨어를 직접 설치하거나 운영을 맡겨 쓰는 셀프 호스팅 CMS입니다. Sanity나 Strapi 같은 헤드리스 CMS는 글을 담고 관리하는 뒷단만 제공하고, 화면은 개발자가 따로 만듭니다. 한 도구가 여러 갈래에 걸치기도 합니다. Ghost는 직접 운영할 수 있으면서 헤드리스로도 쓸 수 있고, 워드프레스도 뒤에서 다루겠지만 헤드리스 CMS가 될 수 있습니다. 그래서 도구 이름을 줄 세우기 전에 비교 기준부터 정해두려고 합니다. 데이터와 주소를 누가 쥐고 있는지, 기능을 얼마나 넓힐 수 있는지, 주변 생태계가 얼마나 두꺼운지, 운영에 드는 수고와 비용이 어떻게 늘어나는지, 글 쓰는 사람의 편집 경험은 어떤지, 구독이나 광고 같은 수익화는 얼마나 쉬운지, 이렇게 여섯 가지입니다. W3Techs의 집계에서 워드프레스의 점유율은 2025년 1월 43.6%로 정점을 찍은 뒤 2026년 가을에는 40% 안팎까지 내려왔고, 같은 기간 Wix와 Shopify 같은 호스팅형 서비스는 조금씩 올랐습니다. 점유율이 곧 품질을 의미하지는 않습니다. 기존 사용자가 다른 CMS로 옮겼는지, 새로 만들어지는 웹사이트에서 다른 도구를 선택하는 비중이 늘었는지까지 이 수치만으로 판단할 수는 없습니다. 다만 웹사이트를 구축하는 데 워드프레스 외의 선택지가 점차 존재감을 키우고 있다는 사실은 분명해 보입니다. 이 흐름의 이유를 인정하지 않고 워드프레스의 장점만 늘어놓으면 공정한 비교가 되지 않을 것입니다. 서버를 직접 돌보지 않아도 되는 호스팅형 서비스의 편안함에는 분명히 큰 값어치가 있으니까요. 월요일 아침에 서버 알림이 하나도 없는 평화는 무엇과도 바꾸기 어렵습니다. 그러니 워드프레스가 어떤 조건에서 가장 설득력을 갖는지를 하나씩 찾아보겠습니다. Ghost: 글과 독자, 구독을 하나로 묶다 저는 예전에 Ghost로 블로그를 구축해본 적이 있습니다. Ghost는 2013년 존 오놀런(John O'Nolan)이 킥스타터(Kickstarter) 프로젝트로 시작한 오픈소스 CMS로, 지금은 비영리 재단인 Ghost Foundation이 운영하며 MIT 라이선스로 공개되어 있습니다. 워드프레스가 PHP 위에서 돌아간다면 Ghost는 Node.js와 MySQL 8 위에서 돌아가고, 직접 설치하려면 가상 서버(VPS)와 명령줄 작업에 익숙해야 합니다. Ghost가 눈에 띄는 지점은 블로그와 뉴스레터와 유료 구독을 하나의 목적으로 묶어 놓았다는 것입니다. 이메일 뉴스레터 발송과 무료·유료 멤버십 관리가 처음부터 들어 있고, 유료 구독 결제는 Stripe와 연결됩니다. Ghost 자체는 구독 매출에서 별도의 플랫폼 수수료를 받지 않지만, Stripe의 결제 처리 수수료는 발생합니다. (그리고 참고로 Stripe는 2026년 10월 현재, 대한민국 결제를 지원하지 않습니다. 이것은 매우 중요합니다!) 관리형 호스팅인 Ghost(Pro)는 연간 결제 기준 월 $18부터 시작하며, 유료 구독 기능을 사용하려면 월 $29부터 제공되는 Publisher 플랜 이상이 필요합니다. 직접 서버를 운영한다면 Ghost 소프트웨어 자체는 무료로 사용할 수 있습니다.2025년 8월에 나온 Ghost 6.0은 여기에 자체 분석 도구와 ActivityPub 기반의 소셜 웹 연동까지 얹었습니다. 글을 쓰고 독자를 모으고 수익을 만드는 길이 하나의 도구 안에 함께 담겨 있습니다. 워드프레스와 나란히 놓으면 차이는 철학에서 갈립니다. 워드프레스도 콘텐츠 발행과 사용자 관리에 필요한 다양한 기능을 기본으로 제공하지만, 이메일 뉴스레터와 유료 멤버십을 Ghost처럼 하나의 통합된 발행 시스템으로 제공하지는 않습니다. 선택지는 넓지만 조립은 제 몫입니다. Ghost는 반대로 필요한 기능이 이미 한 덩어리로 맞물려 있어서, 정해진 길 위에서는 훨씬 편안하고 빠르게 움직일 수 있습니다. 대신 플러그인과 확장 모듈의 생태계는 워드프레스보다 작습니다. 이것을 단점이라고 할 수도 있겠지만, 단점이라기보다는 설계의 대가라는 말이 더 정확할 것 같습니다. 그래서 Ghost가 기본으로 해주지 않는 일이 필요해지면 외부 서비스를 끌어와 이어 붙이는 경우가 많습니다. Zapier나 Make가 대표적인 서비스로, 서로 다른 서비스를 코드 없이 연결해주는 자동화 도구입니다. 예를 들어 “새 구독자가 가입하면 스프레드시트에 한 줄을 추가하고 슬랙으로 알림을 보낸다”는 규칙을 화면에서 클릭으로 만들어 두면, 한 서비스에서 일어난 일이 다른 서비스의 동작으로 이어집니다. 같은 요구사항을 워드프레스에서는 전용 플러그인이나 자동화 플러그인으로 처리할 선택지가 상대적으로 많습니다. 물론 워드프레스 역시 외부 API나 자동화 서비스를 연결해야 하는 경우가 있습니다. 차이는 무엇을 할 수 있느냐보다, 그 기능을 구현하는 데 선택할 수 있는 경로가 얼마나 다양한가에 있습니다. 사이트의 구조도 비슷합니다. Ghost도 설정 파일(routes.yaml)로 사이트를 블로그와 팟캐스트 같은 구역으로 나누고 구역마다 다른 템플릿을 줄 수 있지만, 찾아보니 글에 새 입력 칸을 만드는 일, 예를 들어 책 리뷰에 별점과 저자 칸을 추가하는 일은 기본 기능이 아니라는 이야기가 Ghost 포럼에 꾸준히 올라옵니다. 워드프레스에서는 글 유형(custom post type)과 사용자 정의 필드(custom fields)로 자유롭게 입력 칸을 직접 만들 수 있습니다. 연재물과 책 리뷰, 다국어 아카이브, 회원 전용 자료실처럼 성격이 다른 글을 한 사이트에 담으려면 이런 유연함이 필요해집니다. 인블로그: 검색 유입에 필요한 수고를 덜다 인블로그(inblog)는 한국어 문서와 국내 고객 사례를 앞세운 호스팅형 블로그 서비스입니다. 인블로그 문서에 따르면 개인 창작자보다 기업의 인바운드 콘텐츠 마케팅(inbound content marketing)에 최적화되어 있습니다. 검색엔진이 해석하기 좋은 HTML 구조와 제목 태그 마크업, 사이트맵과 robots.txt, 구조화 데이터(JSON-LD) 같은 검색엔진 최적화(SEO)의 기술적 설정을 별도 작업 없이 기본으로 제공합니다. 방문자를 잠재 고객으로 바꾸는 리드 수집 폼과 트래픽·키워드 분석도 기본으로 갖추고 있습니다. 무료 플랜에서는 글을 계속 공개하고 새 글도 발행할 수 있지만 커스텀 도메인 연결과 분석, 폼 같은 기능은 쓸 수 없습니다. 유료인 팀 플랜은 월 39달러(VAT 별도)부터 시작하며, 최근 30일간의 페이지뷰에 따라 월 79달러, 149달러, 299달러로 요금이 자동 조정됩니다. 가장 높은 월 299달러 구간에서는 트래픽 제한이 없습니다. 모든 요금 구간에서 동일한 팀 기능을 제공하며, 도메인 구매나 외부 서비스 연동에 필요한 비용은 별도입니다. 워드프레스나 Ghost, 네이버 블로그에서 글을 옮겨오는 마이그레이션도 지원하므로 이사의 문턱도 낮춰 두었습니다. 워드프레스와 견주면 인블로그가 가져간 것은 수고입니다. 워드프레스에서는 테마를 고르고 SEO 플러그인을 설정하고 사이트맵과 구조화 데이터를 확인하는 일이 제 몫이지만, 인블로그에서는 그 설정이 이미 맞춰진 채로 시작합니다. 인블로그가 올려둔 워드프레스 비교 글은 워드프레스를 SEO용으로 쓸 만하게 만들려면 인력과 시간과 학습 비용이 필요하다고 말하는데, 이 지적에는 동의합니다. 물론 SEO 기반을 갖추는 것과 실제 검색 순위에서 경쟁력을 얻는 것은 별개입니다. 다만 대가도 있습니다. 서비스가 정한 기능 안에서 움직여야 하고, 가격은 서비스가 정한 방식으로 늘어나며, 앞선 글에서 이야기한 거처의 문제가 다시 따라옵니다. 커스텀 도메인을 연결하면 주소의 주인은 제가 되지만, 그 주소에서 어떤 소프트웨어가 돌아가고 데이터가 어떻게 관리되는지는 서비스의 몫으로 남습니다. 기업 블로그가 검색 유입과 리드 수집이라는 한 가지 목표를 향해 달리는 곳이라면 그 대가가 합리적일 수 있고, 여러 해에 걸쳐 모습이 달라질 블로그라면 무겁게 다가올 수 있습니다. 어느 쪽이 맞는지는 도구가 아니라 블로그의 목적이 정합니다. 호스팅형 서비스가 파는 것은 편리함이다 호스팅형 서비스에는 몇 가지 결이 있습니다. Substack은 뉴스레터를 중심에 두고 유료 구독 매출의 10%를 플랫폼 수수료로 받습니다. (Stripe 결제 수수료는 별도) Ghost가 고정 호스팅 비용을 부담하는 대신 구독 매출에 플랫폼 수수료를 부과하지 않는다면, Substack은 유료 구독 매출이 발생할 때 그 일부를 가져가는 구조입니다. Medium은 이미 모인 독자 속에 글을 놓는 서비스이고, Notion 문서를 그대로 블로그로 발행해주는 서비스들도 있습니다. Wix와 Squarespace와 Webflow는 시각적인 편집기로 웹사이트 전체를 만들어줍니다. W3Techs의 집계에서 Shopify와 Wix와 Squarespace가 워드프레스 다음 자리를 채우고 있다는 것은, 쉽다는 이유 하나만으로도 충분히 많은 사람을 설득하고 있다는 뜻일 것입니다. 이들이 파는 것은 편리함이고, 공통된 대가는 주소와 데이터와 기능의 통제권을 서비스와 나눠 갖는다는 것입니다. 앞선 글에서 티스토리와 네이버 블로그를 두고 했던 이야기가 여기에도 그대로 이어집니다. 이쪽에서 워드프레스로 이사하는 길은 열려 있지만, 글을 옮기는 일과 독자와 검색 순위까지 함께 옮기는 일은 다른 문제입니다. 헤드리스 CMS: 화면의 결정권을 가져오다 헤드리스 CMS는 글을 쓰고 관리하는 뒷단(보통 개발 세계에선 백엔드라고 하죠)과 독자가 보는 화면(프런트엔드)을 떼어 놓은 구조입니다. 뒷단은 API로 글을 내어주고, 화면은 Next.js나 Astro 같은 프레임워크로 개발자가 직접 만듭니다. 이쪽에서 자주 거론되는 이름은 SaaS인 Sanity와 Contentful, MIT 라이선스 오픈소스인 Strapi, TypeScript로 설정을 쓰는 코드 우선(code-first) 방식의 Payload, 기존 SQL 데이터베이스 위에 관리 화면과 API를 얹는 Directus 정도입니다. Ghost도 Content API를 통해 헤드리스로 쓸 수 있습니다. Markdown 파일을 Git 저장소에 두고 Astro나 Hugo로 빌드하는 방식은 엄밀히는 CMS가 아니지만, 그 위에 편집 화면을 얹는 도구들까지 포함해 같은 가족으로 묶어 볼 수 있습니다. 헤드리스 CMS의 장점은 확실합니다. 화면을 한 줄도 남김없이 직접 설계할 수 있고, 한 곳에 쌓은 콘텐츠를 웹과 앱과 다른 채널에 함께 내보낼 수 있습니다. 헤드리스 구성에서는 렌더링 방식도 자유롭게 선택할 수 있습니다. 정적 사이트로 빌드하면 요청 시 서버에서 실행되는 코드를 줄일 수 있어 성능과 보안 측면에서 이점을 얻을 수 있지만, CMS 자체의 운영과 보안 문제까지 없어지는 것은 아닙니다. Payload처럼 콘텐츠 모델을 코드로 정의하는 CMS에서는 타입 시스템을 활용하고 스키마 변경 이력을 Git으로 관리할 수도 있습니다. 아마 개발자에게는 가장 즐거운 길일 것입니다. 저도 매번 블로그를 직접 구축할 때마다 늘 헤드리스 CMS 방법을 써왔었으니까요. (야심차게 개발은 다 해놓고 정작 글을 쓰지 않아서 폐쇄한 블로그가 여태 몇 개였던가...) 화면을 직접 설계할 수 있다는 자유가 곧 글을 쓰게 하는 힘이 되지는 않았습니다. 블로그라는 목적에 놓고 보면 직접 만들어야 하는 것이 많습니다. 미리보기, 검색, RSS와 사이트맵, 이미지 최적화, 댓글, 구독 폼, 예약 발행까지 워드프레스에서는 코어나 플러그인으로 이미 해결되어 있던 일이 이 길에서는 직접 개발자가 구축해야 할 "작업"의 목록이 됩니다. 비용 구조도 다릅니다. SaaS 계열은 API 호출량과 사용자 수에 따라 요금이 붙고, 오픈소스 계열은 라이선스는 무료이지만 서버와 운영을 직접 담당해야 합니다. 블로그 하나를 위해 CMS와 화면과 배포 파이프라인을 따로 두는 것이 합리적인지는 그 블로그가 어떤 형태의 웹사이트인지에 따라 달라집니다. 처음에 세운 여섯 가지 기준으로 지금까지 본 도구들을 정리하면 다음과 같습니다. 비교 기준워드프레스Ghost인블로그전용 헤드리스 CMS데이터 통제높음 (셀프 호스팅)높음 (셀프 호스팅)서비스 의존제품·배포 방식에 따라 다름확장성매우 넓음발행·구독 중심제공 기능·API 범위 중심개발을 통한 확장에 강함생태계매우 큼상대적으로 작음전용 SaaS제품별 차이 큼운영 부담직접/관리형 선택직접/관리형 선택낮음제품·구성에 따라 다름편집 경험테마·플러그인에 따라 다양글쓰기·뉴스레터 중심기업 블로그 중심편집 UI 구성에 따라 다름수익화플러그인·서비스 조합멤버십·구독 내장리드 수집 중심별도 구현·연동 중심 (일반적인 제품 구성에 대한 정성적 비교이며, 요금제와 별도 개발에 따라 달라질 수 있습니다.) 워드프레스는 어디까지 바뀔 수 있을까 워드프레스는 헤드리스 CMS로도 쓸 수 있습니다. 앞선 글에서 이야기한 REST API는 4.7부터 글과 댓글, 사용자 같은 콘텐츠를 내어주기 때문에, REST API만으로도 Next.js나 Astro, Nuxt로 만든 화면에 데이터를 전달하는 헤드리스 구성이 가능합니다. 여기에 WPGraphQL 플러그인을 설치하면 GraphQL 방식으로도 콘텐츠를 제공할 수 있고, 사용자 정의 필드 플러그인인 Advanced Custom Fields(ACF)로 만든 필드까지 GraphQL로 전달하려면 WPGraphQL for ACF를 추가합니다. Next.js용 프레임워크인 Faust.js는 이 과정에서 까다로운 미리보기와 인증을 대신 처리해준다고 합니다. 2026년 현재 Next.js와 WPGraphQL의 조합이 가장 흔하고, 콘텐츠 중심 사이트에서는 Astro를 고르는 경우도 늘고 있다고 합니다. 이 구성에서 편집자는 익숙한 워드프레스 관리자 화면(wp-admin)에서 글을 쓰고, 방문자는 워드프레스에 직접 닿지 않은 채 빠른 정적 화면을 만납니다. 일반 테마로 시작해서 필요해지면 일부 페이지만 API로 빼내고, 더 필요해지면 화면 전체를 갈아 끼우는 길이 하나의 소프트웨어 안에서 이어져 있습니다. 콘텐츠 데이터와 편집 환경을 유지한 채 방문자가 보는 화면을 교체할 수 있다는 점은 큰 장점입니다. 물론 화면을 새로 개발하는 비용은 별도로 들지만, 적어도 콘텐츠를 다른 CMS로 옮기고 편집자가 새로운 관리 도구에 적응하는 과정은 줄일 수 있습니다. 헤드리스 CMS로 처음부터 시작하면 첫날부터 화면을 직접 만들어야 하고, 호스팅형 서비스에서 시작하면 서비스가 열어둔 범위 안에서만 움직일 수 있습니다. 다만 화면을 따로 만드는 순간 프런트엔드에서 동작하던 플러그인의 상당수가 그대로 쓰이지 않으므로, SEO 메타데이터와 사이트맵 연동, 폼, 댓글, 캐시 무효화를 화면 쪽에서 다시 구현해야 합니다. 생태계 가운데 일부를 내려놓고 편집 경험과 데이터 모델만 가져가는 선택이고, 워드프레스 서버를 운영하고 지켜야 하는 숙제도 그대로 남습니다. 그래서 헤드리스는 화면에 대한 요구가 테마로 감당할 수 없을 만큼 커졌을 때의 선택이고, 그때까지는 일반 테마가 훨씬 단순한 답입니다. 여기까지 놓고 보면 워드프레스가 모든 항목에서 일등인 것은 아닙니다. 구독과 뉴스레터는 Ghost가, 기술적 SEO 설정의 편의성은 인블로그가, 코드로 정의하는 콘텐츠 모델은 헤드리스 CMS가 더 매끄럽게 풀어냅니다. 그럼에도 워드프레스가 앞서는 지점은 어느 한 항목이 아니라 항목을 가로지르는 폭입니다. 하나의 소프트웨어 위에서 일반 블로그로 시작해 여러 사람이 쓰는 매체로, 회원제 사이트로, 쇼핑몰(WooCommerce)로, 헤드리스 구성으로 모습을 바꿀 수 있습니다. 필요한 기능은 대부분 누군가가 이미 만들어 두었고, 없으면 플러그인이나 코드로 만들 수 있습니다. 소유의 측면에서는 GPL 오픈소스라는 점이 Ghost의 MIT 라이선스와 같은 편에 서 있고, 호스팅 업체와 도메인과 데이터를 제가 정한다는 점에서 호스팅형 서비스와 갈립니다. 또 하나는 사람과 선택지입니다. W3Techs 조사 대상 웹사이트의 약 40%가 사용하는 소프트웨어인 만큼, 높은 보급률을 바탕으로 개발자, 디자이너, 호스팅 업체 등 폭넓은 생태계가 형성되어 있습니다. 막혔을 때 물어볼 곳이 많고, 일을 맡길 사람을 찾기 쉬우며, 호스팅을 옮겨야 할 때 고를 곳도 많습니다. 도구가 사라지거나 정책을 바꿀 위험은 호스팅형 서비스보다 낮다고 생각합니다. 제가 말하고 싶은 것은, 그저, 워드프레스가 가장 뛰어난 도구가 아니라 가장 넓은 선택지를 가진 도구라는 것. 그 넓음이 오래 쓸 블로그에서는 가장 믿을 만한 보험이 됩니다. 그 선택지에는 관리 비용이 따른다 물론 워드프레스가 모든 상황에서 통하는 것은 아닙니다. 가장 먼저 걸리는 것은 운영입니다. 코어와 테마와 플러그인의 업데이트, 백업, 보안, 성능 설정이 모두 제 몫이고, 이 수고는 호스팅형 서비스나 관리형인 Ghost(Pro)에서는 서비스가 맡아주는 일입니다. 플러그인을 조립하는 방식도 양날입니다. 구독과 뉴스레터를 갖추려면 플러그인과 외부 서비스를 고르고 이어 붙여야 하고, 그 조합이 서로 충돌하지 않는지 지켜보는 일까지 따라옵니다. 이 지점에서 Ghost처럼 한 덩어리로 맞물린 도구가 주는 편안함에는 분명히 설득력이 있습니다. 개발 경험의 차이도 있습니다. 워드프레스는 PHP와 훅(hook) 기반의 오래된 구조 위에 쌓여 있어서, 타입이 맞춰진 콘텐츠 모델과 TypeScript 중심의 개발 흐름에 익숙한 팀에게는 헤드리스 CMS 쪽이 더 자연스럽게 느껴질 수 있습니다. 검색 노출도 마찬가지입니다. 인블로그는 기술적 SEO 설정이 처음부터 맞춰져 있는 반면 워드프레스는 어떤 테마와 플러그인을 고르느냐에 따라 결과가 갈립니다. 워드프레스의 장점이 가장 빛나는 곳은 이런 약점을 감당할 수 있거나, 감당할 이유가 있는 블로그입니다. 3년 뒤에도 같은 블로그일까 저라면 개발 인력이 없는 팀이 검색 유입과 리드 수집을 목적으로 기업 블로그를 운영한다면 인블로그 같은 서비스를 고려할 것입니다. 뉴스레터와 유료 구독을 중심으로 독자와 관계를 만들어가려는 1인 매체라면 Ghost가 더 적합할 수 있습니다. 콘텐츠를 여러 채널에 제공하거나 화면과 데이터 구조를 직접 설계해야 하는 개발팀이라면 헤드리스 CMS가 자연스러운 선택일 것입니다. 글을 가끔 올리는 개인 기술 블로그라면 마크다운 파일과 정적 사이트 생성기만으로도 충분할 수 있습니다. 워드프레스는 이들보다 시작하기 번거로울 때가 있고, 운영에 더 많은 신경을 써야 할 수도 있습니다. 하지만 처음에는 평범한 블로그였다가 나중에는 여러 사람이 글을 쓰는 매체가 되거나, 회원제 서비스나 쇼핑몰로 확장될 가능성이 있다면 이야기가 달라집니다. 그때 워드프레스의 넓은 생태계와 유연한 구조가 장점이 될 수 있습니다. 한편으로는 블로그를 직접 개발하는 일이 글을 쓰는 일보다 더 재미있었던 때도 있었습니다. 새로운 기술을 골라 화면을 만들고 배포하는 과정에 공을 들였지만, 정작 그 안에 글을 채우지 못한 블로그도 있었습니다. 돌아보면 블로그를 만들기 좋은 기술과 블로그를 오래 운영하기 좋은 기술이 반드시 같지는 않았던 셈입니다. 결국 어느 CMS가 가장 뛰어난지보다 중요한 것은 그 도구로 무엇을 하려는지, 그리고 얼마나 오래 운영할 수 있는지일 것입니다. 워드프레스는 모든 상황에서 정답이 되지는 않지만, 앞으로 무엇이 필요해질지 아직 모르는 사람에게는 여전히 설득력 있는 선택지입니다. 본문에 연결했거나 참고한 출처입니다. Ghost, Ghost 6.0 변경 내역 TechCrunch, Ghost 6 출시 보도(2025-08-05) Bluehost, Ghost 개요(Node.js, MySQL 8 요구 사항) Ghost 포럼, 글 유형 외 입력 칸에 관한 논의 인블로그, 자주 묻는 질문 인블로그, 요금 안내 인블로그, 무료·팀 플랜 안내(에이전시용 FAQ) 인블로그, 인블로그 vs 워드프레스(2026) Sender, Substack 요금과 수수료 정리(2차 자료) W3Techs, CMS 점유율 연간 추이 Directus, Best headless CMS in 2026(업체 자료) WP Engine, Faust.js 소개 WPGraphQL, WPGraphQL for ACF Gautam Khorana, Headless WordPress 2026(에이전시 블로그) WordPress Developer Resources, REST API 핸드북

2026.10.12
개발
워드프레스, 스무 해가 넘은 블로그 엔진을 지금도 써야 할까

블로그를 새로 만들 도구를 고를 때 워드프레스는 가장 먼저 거론되는 이름이면서, 동시에 가장 먼저 "낡았다"는 말을 듣는 이름이기도 합니다. 여전히 가장 흔한 도구 W3Techs의 2026년 10월 집계에서 워드프레스는 조사 대상 웹사이트의 약 40%에서 쓰이고 있습니다. 콘텐츠 관리 시스템(CMS)을 식별할 수 있는 사이트만 놓고 보면 점유율은 약 59%에 이릅니다. 2003년에 시작된 소프트웨어가 20년이 넘도록 이 정도 비중을 유지하고 있다는 사실은 그 자체로 흥미롭습니다. 많이 쓰이는 도구에는 많이 쓰이는 대로의 이점이 따라붙습니다. 개발자로 일하다 보면 거대한 생태계 자체가 하나의 기능이라는 생각이 들 때가 있습니다. 막히는 문제가 생겨 검색해 보면 먼저 같은 문제를 겪은 사람의 해결 방법이 이미 있고, 대부분의 호스팅 업체가 설치를 지원합니다. 테마와 플러그인을 만드는 개발자도 많아서 필요한 기능을 처음부터 만들지 않고 가져다 쓸 수 있습니다. 이런 것들이 쌓여 도구의 사용성을 결정하기도 합니다. 물론 점유율이 곧 품질의 증거는 아니어서, 많이 쓰인다는 사실이 곧 좋은 도구라는 뜻으로 연결되지는 않기에, 이번 글에서는 오직 "블로그"라는 용도로만 좁혀서 워드프레스가 다른 블로그 플랫폼이나 웹 사이트 구축 프레임워크에 비해 가지는 장점을 살펴보겠습니다. 블로그에서 태어난 소프트웨어 워드프레스는 2003년 매트 멀런웨그(Matt Mullenweg)와 마이크 리틀(Mike Little)이 b2/cafelog라는 블로그 소프트웨어를 이어받아 갈라져 나오면서 시작되었다고 합니다. 워드프레스가 처음부터 블로그를 만들기 위해 태어났다는 사실은 지금의 구조를 이해하는 데 중요한 단서가 됩니다. 글(post)과 페이지(page)가 구분되어 있고, 글에는 카테고리와 태그가 붙고, 최신 글이 위로 쌓이는 시간순 구조가 기본값이며, 글마다 고유한 주소인 퍼머링크(permalink)가 생기고, RSS 피드와 댓글 기능도 기본으로 들어 있습니다. 댓글 기능은 간단하게 설정을 통해 켜고 끌 수 있습니다. "범용 웹 사이트 빌더에 블로그 메뉴를 하나 얹은 도구"와 "처음부터 글이 중심이 되는 블로그를 위해 만들어진 도구"는 기능 목록이 같아도 유저 입장에서는 쓰는 느낌이 확연히 달라서, 글이 수십 편, 수백 편으로 늘어날수록 이런 기본 구조의 편리함은 더욱 분명해집니다. 지금은 블로그가 아닌 용도로도 쓰이지만, 워드프레스의 뼈대에는 여전히 "글"이라는 단위가 놓여 있습니다. 2018년 12월, 워드프레스 5.0과 함께 구텐베르크(Gutenberg)라는 블록 에디터가 기본 편집기가 되었습니다. 단락, 제목, 이미지, 인용, 코드, 표, 임베드가 각각 하나의 블록이고, 블록을 끌어서 순서를 바꾸거나 자주 쓰는 구성을 패턴으로 저장해둘 수 있습니다. 처음 도입됐을 때는 불만도 많았지만, 여러 차례 개선을 거친 지금은 글을 작성하고 구성하는 과정이 한결 자연스러워졌습니다. 물론 이것이 모든 사람에게 가장 단순한 편집기일 수는 없을 것입니다. 마크다운으로 쓰는 것에 익숙한 사람에게는 블록 편집기가 오히려 번거롭게 느껴질 수 있습니다. 워드프레스의 강점은 편집기 하나가 아니라, 글을 쓰고 이미지와 표를 배치하고 초안을 다듬어 예약 발행하기까지의 과정이 하나의 작업 환경 안에 모여 있다는 데에 있습니다. 글을 쓰는 손과 사이트를 만지는 손이 따로 필요하지 않다는 점이 블로그에는 생각보다 큰 장점이 아닐까 싶습니다. 자동 저장과 수정 이력, 이미지 크기 자동 생성 같은 편의 기능도 기본으로 제공됩니다. 물론 서버나 네트워크 상태에 따라 모든 작업이 안전하게 보존되는 것은 아니지만, 일상적인 글쓰기에서 직접 신경 써야 할 부분을 상당히 줄여줍니다. 블록 편집이나 예약 발행은 워드프레스만의 기능이 아니고 다른 도구에서도 충분히 구현할 수 있습니다. 중요한 것은 이런 기능을 직접 만들 필요 없이 설치한 순간부터 쓸 수 있다는 점입니다. 단순하게 말해보자면, 블로그를 만들기 위해 개발을 시작하는 것이 아니라, 글을 쓰기 위해 도구를 설치하는 것에 더 가깝다고 볼 수 있겠습니다. 내 글의 거처를 내가 정한다는 것 워드프레스 소프트웨어는 GPL 라이선스로 공개된 오픈소스입니다. WordPress.org는 이 소프트웨어를 내려받는 프로젝트 사이트이고, 이를 직접 설치해 운영하는 방식을 셀프 호스팅(self-hosted)이라고 부릅니다. 같은 소프트웨어를 Automattic이 대신 운영해주는 서비스는 WordPress.com이라는 별개의 이름으로 제공됩니다. 셀프 호스팅에서는 호스팅 업체와 도메인과 데이터 관리 방법을 운영자가 고르고, 글과 이미지와 데이터베이스에 직접 접근해 백업하고 내보낼 수 있습니다. 이는 "내 글의 거처는 내가 정한다"는 의미와 닿아 있습니다. 티스토리나 네이버 블로그처럼 플랫폼이 운영하는 서비스는 특별한 개발 지식 없이도 사용하기 편리하다는 큰 장점이 있지만, 정책이 바뀌거나 서비스가 흔들리면 글의 거처도 함께 흔들릴 수 있습니다. 블로그를 몇 년 이상 꾸준히 운영할 생각이라면 이 차이가 가장 무겁게 다가올 것입니다. 서비스가 흔들리는 일은 국내에서도 있었습니다. 2003년에 시작한 블로그 서비스 이글루스는 2023년 6월 16일 운영을 종료했고, 이용자는 정해진 기간 안에 직접 글과 데이터를 백업해 새로운 거처를 찾아야 했습니다. 찾아보니 종료 이후에도 약 반년 동안 백업 기간이 주어졌다고 합니다. 처음부터 자신의 도메인으로 운영하는 워드프레스는 호스팅 업체를 바꾸더라도 기존 글의 주소를 유지할 수 있습니다. 이전 과정에서 주소 구조와 검색엔진 설정을 올바르게 관리하면 외부에서 걸어준 링크도 계속 작동하게 만들 수 있습니다. (그러나 검색 순위까지 보장되는 것은 아닙니다. 서버를 옮기는 동안 응답 속도나 크롤링 허용 설정, 대표 주소(canonical URL), 내부 링크가 달라지면 검색 결과도 흔들릴 수 있기 때문입니다.) 그러나 가장 흔하게는 티스토리처럼 개인 도메인을 연결할 수 있는 서비스도 많이 있는 만큼, 워드프레스를 사용할지를 결정할 때 중요하게 작용하는 점은 "단순히 자신의 도메인을 사용할 수 있느냐"가 아니라 "그 주소에서 어떤 소프트웨어를 실행하고 데이터를 어떻게 관리할지까지 스스로 결정할 수 있느냐"가 될 것 같습니다. 십 년 뒤에도 내 글이 지금과 동일한 주소에서 열리기를 바란다면, 주소의 주인이 누구인지는 생각보다 중요한 문제가 될 것이기 때문입니다. 물론 데이터를 직접 관리할 수 있다고 해서 언제든 손쉽게 다른 시스템으로 옮길 수 있다는 뜻은 아닙니다. 데이터 통제권, 곧 데이터에 접근하고 백업하고 수정할 수 있는 권한과, 데이터 이동성, 곧 도구를 바꾸고 싶을 때 실제로 옮길 수 있는 정도는 다른 문제입니다. 플러그인이 자체 데이터베이스 테이블에 정보를 저장하거나 페이지 빌더가 전용 형식으로 콘텐츠를 저장하면, 워드프레스 안에서도 새로운 종속이 생깁니다. 워드프레스는 확실히 전자의 통제권에서 강하고, 후자의 이동성은 어떤 테마와 플러그인을 고르느냐에 따라 달라집니다. 그래도 백업하고 이전을 시도할 권한이 운영자에게 있다는 점은 여전히 중요한 차이입니다. 물론 네이버 블로그에는 워드프레스가 가질 수 없는 것도 있습니다. 네이버 안에서 이웃 관계와 검색을 따라 독자가 흘러들어오는 구조, 서버와 보안을 신경 쓰지 않아도 되는 편안함, 가입하고 바로 쓸 수 있는 속도가 그렇습니다. 다만 그 편리함을 선택하는 대신 주소와 데이터에 대한 운영의 자율성을 어느 정도 내려놓아야 합니다. 블로그를 오래 운영할 생각이라면, 특히 오랜 시간 쌓은 글을 바탕으로 자신만의 브랜드나 전문성을 만들어가고 싶다면, 저는 이 차이를 중요하게 바라보아야 한다고 생각합니다. 필요한 만큼만 확장하는 구조 워드프레스 공식 플러그인 디렉터리에만 수만 개의 플러그인이 등록되어 있다고 합니다. 검색엔진 최적화(SEO)는 Yoast SEO나 Rank Math, 속도는 캐시 플러그인, 거기에 백업과 보안, 이미지 압축, 다국어, 뉴스레터 연동까지, 필요한 기능은 대부분 이미 누군가의 손으로 만들어져 있습니다. 테마를 교체해도 글과 페이지의 기본 콘텐츠는 유지되므로 디자인을 비교적 독립적으로 바꿀 수 있습니다. 물론 메뉴 위치와 위젯, 템플릿, 테마 전용 숏코드, 페이지 빌더에 의존한 부분까지 자동으로 이어지는 것은 아니어서, 사이트를 오래 꾸밀수록 테마를 바꾸는 비용은 커집니다. 2022년에 나온 워드프레스 5.9부터는 블록 테마를 사용하는 경우 사이트 편집기(Site Editor)로 헤더와 푸터, 페이지 템플릿까지 코드 없이 고칠 수 있습니다. 개발자에게는 자식 테마(child theme)와 훅(hook)을 이용해 기존 구조를 활용하면서 기능을 확장할 방법도 열려 있습니다. 처음부터 끝까지 직접 짜야 하는 도구와 처음부터 끝까지 정해진 틀 안에서만 쓰는 도구 사이에 이런 중간 지대가 있다는 것이 저에게는 가장 실용적으로 느껴집니다. RSS 피드는 기본으로 제공되어 독자가 리더 앱으로 구독할 수 있고, 고유주소(퍼머링크) 구조를 바꿔 글 주소에 영문 슬러그(slug)를 넣을 수도 있습니다. 워드프레스 5.5부터는 XML 사이트맵도 코어에서 기본으로 제공하므로, 사이트맵을 만들기 위해 SEO 플러그인이 반드시 필요하지는 않습니다. Yoast SEO나 Rank Math 같은 플러그인은 글마다 메타 설명을 설정하고 검색엔진에 전달할 정보를 더 세밀하게 관리할 때 쓰입니다. 물론 이런 기능이 검색 노출을 보장해주지는 않습니다. SEO 기능이 풍부하다는 것과 기본적으로 SEO가 잘된 사이트라는 것도 다른 이야기여서, 잘못 만든 테마와 불필요하게 늘어난 카테고리·태그 페이지, 중복 콘텐츠, 느린 플러그인은 오히려 검색 노출에 불리하게 작용할 수 있습니다. 그래도 검색엔진이 읽기 좋은 구조의 HTML을 내보내는 테마와 도구가 풍부하다는 점은 분명한 이점입니다. 소셜 플랫폼의 알고리즘이 바뀔 때마다 도달률이 출렁이는 것을 보면, RSS처럼 플랫폼의 추천 알고리즘에 의존하지 않는 구독 통로를 기본으로 제공하고, 필요하다면 이메일 뉴스레터까지 확장할 수 있는 구조의 중요성은 점점 더 커질 것입니다. 기능을 넓히는 방식도 다릅니다. 티스토리는 스킨의 HTML과 CSS를 고칠 수 있어 꽤 자유롭지만 서버에서 돌아가는 코드나 데이터베이스까지는 손댈 수 없는 것으로 알고 있고, 네이버 블로그는 외부 스크립트 삽입이 제한되며 광고 수익도 네이버의 광고 서비스 안에서 이루어지는 것으로 알고 있습니다. 서버 환경을 제가 정할 수 있는 워드프레스에서는 뉴스레터 구독 폼, 회원 전용 글, 연재물이나 책 리뷰처럼 성격이 다른 글을 따로 묶는 커스텀 포스트 타입, 검색엔진 최적화를 위한 구조화 데이터, 주소를 바꿨을 때 옛 주소를 새 주소로 이어주는 301 리다이렉트까지 플러그인이나 코드로 직접 넣을 수 있습니다. 광고를 붙일지, 유료 구독을 받을지, 아무것도 붙이지 않고 깨끗하게 둘지도 운영하는 사람이 직접 정합니다. 블로그가 블로그 이상의 것이 될 때 블로그를 시작하는 데에는 사실 꼭 필요한 기능은 많지 않고, 위에서 다룬 기능 가운데 상당수는 블로그 규모가 어느 정도 커진 뒤에야 필요해집니다. 개인 블로그가 몇 사람이 함께 쓰는 매체나 콘텐츠 서비스가 되는 순간이 그렇습니다. 워드프레스에는 관리자(Administrator), 편집자(Editor), 저자(Author), 기여자(Contributor), 구독자(Subscriber)라는 사용자 역할이 기본으로 있어서, 기여자가 쓴 글을 편집자가 검토한 뒤 발행하는 흐름을 기본 권한만으로 꾸릴 수 있습니다. 다만 검토 요청, 단계별 알림, 승인 이력 같은 체계적인 편집 워크플로까지 기본으로 제공되는 것은 아니어서 플러그인이나 별도 도구가 필요합니다. REST API는 4.4에서 기반이 들어왔고 4.7에서 글과 댓글, 사용자 같은 콘텐츠 엔드포인트가 코어에 포함되었습니다. 덕분에 워드프레스를 글 관리용 백엔드로만 쓰고 화면은 Next.js 같은 프런트엔드 프레임워크로 만드는 헤드리스 구성도 가능합니다. 오래되었다는 것은 무엇을 의미할까 낡았다는 평가에는 이유가 있습니다. PHP와 관계형 데이터베이스를 중심으로 만들어진 오래된 구조, 수많은 플러그인이 각자의 방식으로 기능을 확장하는 생태계, 서로 다른 시대의 흔적이 남아 있는 관리자 화면, 플러그인마다 제각각인 설정 경험이 그렇습니다. 처음부터 현대적인 개발 환경을 전제로 설계된 도구와 견주면 투박하게 느껴지는 부분이 분명히 있습니다. 오래되었다는 것은 시간에 대한 설명이지만, 낡았다는 것은 현재의 쓸모에 대한 평가입니다. 둘은 반드시 같은 뜻일 필요가 없습니다. PHP나 관계형 데이터베이스를 쓴다는 사실 자체는 낡은 기술의 증거가 아닙니다. 중요한 질문은 오래된 구조가 언제 기술 부채가 되고 언제 안정적인 자산이 되느냐입니다. 오랫동안 호환성을 지켜온 덕분에 오래전에 쓴 글이 지금도 열리고, 오랫동안 쌓인 문제 해결 방법을 지금도 검색해서 찾을 수 있습니다. 오래된 소프트웨어의 나이는 기술 부채인 동시에 자산입니다. 오래 쓸 수 있다는 장점의 반대편에는 오래된 선택을 계속 관리해야 한다는 부담이 있습니다. 몇 년 전에 설치한 플러그인이 더 이상 업데이트되지 않거나, 과거의 커스터마이징 때문에 PHP 버전을 올리지 못하거나, 플러그인을 바꾸려는데 기존 글이 그 플러그인의 형식에 묶여 있어 쉽게 걷어내지 못하는 일이 생깁니다. 오래된 소프트웨어를 쓴다는 것은 과거의 호환성을 자산으로 얻는 동시에 그 호환성을 유지할 책임도 받아들이는 일입니다. 그 자산이 현재의 불편을 감수할 만큼 가치가 있는지는, 블로그를 어떻게 운영하느냐에 따라 달라진다고 생각합니다. 관리라는 숙제 물론 직접 호스팅하는 워드프레스에는 관리라는 숙제가 따라옵니다. 코어와 테마와 플러그인의 업데이트를 미루면 취약점이 열리고, 플러그인 취약점이 침해 사고의 주요 경로로 자주 지적된다고 합니다. 백업, 캐시 설정, HTTPS, 호스팅 비용도 챙겨야 하고, 플러그인을 하나씩 늘리다 보면 사이트가 무거워지거나 서로 충돌하기도 합니다. 워드프레스 소프트웨어를 무료로 쓸 수 있다는 사실이 블로그 운영까지 무료라는 뜻은 아닙니다. 도메인과 호스팅 비용, 유료 테마나 플러그인의 구독료, 업데이트와 백업에 들이는 시간, 문제가 생겼을 때 직접 해결해야 하는 책임까지 비용으로 본다면 실제 운영비는 월 호스팅 요금보다 훨씬 커집니다. 관리를 맡겨도 되는 매니지드 호스팅을 고르거나 플러그인을 꼭 필요한 것만 두는 것으로 부담은 꽤 줄지만, 그 선택에 들이는 시간 역시 워드프레스를 사용하는 비용이며, 그에 따른 책임도 운영자의 몫입니다. 글을 가끔 발행하고 별도의 관리 화면이 필요하지 않다면 Hugo나 Jekyll, Astro 같은 도구로 정적 사이트를 만드는 편이 운영 부담을 줄일 수도 있습니다. 정적 파일만 제공하면 공개 서버에서 관리할 동적 실행 환경이 줄어들기 때문입니다. 물론 빌드 도구의 의존성, 배포 계정, 외부 서비스, 자동 배포 환경의 보안까지 사라지는 것은 아닙니다. 그렇다면 누구에게 워드프레스가 맞을까 결국 중요한 것은 워드프레스가 얼마나 좋은 도구인지보다 자신의 상황에 얼마나 잘 맞는지일 것입니다. 복잡한 설정 없이 국내 독자와 소통하고 싶다면 네이버 블로그가 가장 빠른 길이고, 별도 서버 운영 없이 간편하게 글을 발행하고 싶다면 티스토리 같은 호스팅형 서비스가 편합니다. 자신만의 도메인과 콘텐츠 구조로 장기간 운영하고 싶다면 셀프 호스팅 워드프레스가 어울리고, 개발에 익숙하며 글 중심의 빠르고 단순한 사이트를 원한다면 Hugo나 Astro 같은 정적 사이트 생성기가 맞습니다. 글을 바탕으로 회원제나 다양한 콘텐츠 서비스로 키울 생각이 있다면 워드프레스나 다른 확장형 CMS가 후보가 됩니다. 어느 쪽을 고르든 기준이 되는 것은 도구의 유행이 아니라 이 블로그를 얼마나 오래, 어디까지 키울지라고 생각합니다. 워드프레스가 여전히 합리적인 선택이 되는 조건은 오래 운영하고, 자기 주소를 갖고, 필요에 따라 키워갈 블로그라는 데 있습니다. 도구는 글 뒤에 있을 때 가장 좋다 워드프레스가 여전히 권할 만한 도구인 이유는 오래되었는데도 쓸 만해서가 아니라, 오랫동안 사용되면서 축적된 것들이 여전히 쓸모 있기 때문입니다. 오래된 구조는 새로운 요구사항에 대응하거나 과거의 의존성을 정리해야 할 때 짐이 되지만, 이미 쌓인 글과 익숙한 작업 방식, 풍부한 확장 기능을 계속 활용할 때는 자산이 됩니다. 정적 사이트도, 플랫폼 블로그도, 헤드리스 구성도 저마다 맞는 자리가 있습니다. 그 가운데 워드프레스는 처음에는 블로그로 시작하고, 필요해질 때 기능을 확장하면서 오래 운영할 수 있는 선택지로 남아 있습니다. 결국 중요한 것은 지금 가장 새롭고 편리한 도구가 무엇이냐보다, 앞으로 글이 쌓여가는 시간을 어떤 구조에 맡길 것이냐는 질문일 것입니다. 저는 "글"이 쌓이는 공간을 만들기 위한 도구라면 무엇보다도 그 "글이 쌓여가는 시간"을 견딜 수 있는 구조가 되어야 한다고 생각합니다. 참고한 자료들 본문에 연결했거나 참고한 출처입니다. W3Techs, WordPress 사용 통계 WordPress Learn, WordPress.org와 WordPress.com의 차이 Make WordPress Core, 5.5의 XML 사이트맵 WordPress.org 문서, 사이트 편집기(블록 테마 필요) WordPress Developer Resources, REST API 핸드북 뉴스1, 이글루스 서비스 종료 보도 WebSight Design, WordPress와 WP Engine 분쟁 경과(2026-06-30)

2026.10.01
개발
브라우저 밖에서 리액트를 다시 만나다

브라우저 탭 바깥에서 만난 리액트 저는 스타트업에서 정규직 개발자로 일하며 주로 리액트로 웹 서비스를 만들었고, 지금은 이런 저런 제조 대기업을 옮겨 다니며 상주 프리랜서로 일하고 있습니다. 직함과 계약 형태가 바뀌었을 뿐 쓰는 언어는 비슷할 것이라고 생각했는데, 생판 처음 겪어보는 제조업의 다양한 현장을 경험하다 보니 자바스크립트(타입스크립트)가 닿아 있는 영역이 제가 알던 것보다 훨씬 넓다는 것을 깨닫고 있는 중입니다. 설비 상태를 보여주는 모니터링 화면, 현장 작업자가 장갑을 낀 채 누르는 터치 패널, 장치가 보내는 신호를 모아 화면 쪽으로 넘겨주는 게이트웨이 서비스까지, 우리가 일반적으로 생각하는 웹 사이트라고 부르기는 어려운 것들이지만 많은 화면들이 웹 기반에서 웹 화면을 구성하는 언어와 도구 위에서 돌아가고 있었습니다. 이전 글에서 저는 “모든 웹 사이트에 정말 리액트가 필요한가”라고 물었는데, 어떻게 생각해보면, 웹 사이트를 웹이라는 환경 위의 html 문서들만으로 한정할 수는 없겠다는 생각이 듭니다. 프런트엔드라는 말이 가리키던 범위 프런트엔드, (많은 사람들이 '프론트엔드'라고 쓰지만 국립국어원이 공표하는 외래어 표기법에 의하면 정확히는 '프런트엔드'라고 쓰는 게 맞습니다...아무튼) 이 단어는 원래 사용자와 맞닿은 쪽, 클라이언트 영역, 말 그대로 "front-end", 앞단의 끝, 을 의미할 뿐인데, 웹이 압도적인 플랫폼이 되면서 그 "앞단의 끝"은 곧 "브라우저 뷰포트"로 굳어버린 것 같습니다. 많은 사람들이 프런트엔드(FE) 개발자라고 하면 웹 화면을 만드는 개발자를 떠올리고, 실제로 많은 FE 개발자들이 웹 화면을 개발하고 있으니 그런 인식은 언뜻 자연스럽게 여겨지기도 합니다. 지금 제가 일하는 곳도 마찬가지여서, 이곳의 FE팀은 오로지 웹 화면을 담당하는 개발자들로 이루어져 있고, 저는 이곳에서 모바일과 그 외의 각종 장비 쪽 화면을 담당하지만 저는 FE팀이 아니라 FE팀과는 분리된 Native팀에 소속되어 있습니다. 같은 화면을 만드는 일인데도 이름과 소속은 갈려 있습니다. 사람이 소프트웨어와 만나는 면은 식당 테이블 위의 주문용 태블릿이기도 하고, 아파트 현관과 거실을 잇는 월패드이기도 하며, 주차장 출구의 무인정산기, 병원 접수 키오스크, 마트의 셀프 계산대, 공장 라인 옆 설비 제어 패널이기도 한데, 이 화면들의 공통점은 사용자가 "주소창에 무언가를 입력하지 않는다"는 것입니다. 전원을 켜면 정해진 화면이 뜨고, 사용자는 그 화면 안에서 몇 가지 조작을 하고, 기계는 그 조작에 반응하며 자기 상태를 다시 화면에 돌려줍니다. 사용자는 이것을 “웹사이트에 접속했다”고 느끼지 않고 “기계를 조작했다”고 느낍니다. 이런 화면을 만드는 개발자도 결코 적지 않을 텐데, 단순히 제가 느끼기엔 프런트엔드라는 이름은 이상하게도 유독 웹 브라우저 뷰포트 안의 화면 개발에 초점이 맞춰져 온 것 같다는 생각이 듭니다. 문서가 아니라 기계를 조작하는 화면 웹 문서와 기기 화면은 해결하려는 문제가 근본적으로 다릅니다. 웹 문서의 핵심 단위는 URL이 가리키는 문서이고, 그래서 검색엔진 노출, 링크 공유, 첫 바이트까지의 시간, 초기 HTML에 콘텐츠가 들어 있는가 같은 질문이 중요해집니다. 이전 글에서 길게 다룬 서버 렌더링, 스트리밍, 서버 컴포넌트, 캐시 계층은 모두 이 문서 모델 위에서 생긴 문제와 그 해법입니다. 반면, 예컨대, 주문용 태블릿을 예시로 들어보겠습니다, 여기에서 중요한 것은 /menu/coffee/americano라는 주소가 아니라 지금 사용자가 메뉴를 고르는 중인지, 옵션을 정하는 중인지, 결제 단말과 통신하는 중인지, 결제가 끝나 주문 번호를 보여주는 중인지입니다. 검색엔진 크롤러는 이 화면을 영영 방문하지 않고, 링크를 공유할 사람도 없으며, 검색 유입을 위해 초기 HTML을 어떻게 채울지 고민할 이유도 없습니다. 물론 전원을 켠 뒤 화면이 빨리 준비되어야 한다는 별도의 시작 속도 문제는 남습니다. 대신 터치하는 순간 화면이 바뀌어야 하고, 서버나 장치에서 오는 상태 변화가 지연 없이 화면에 반영되어야 하며, 몇 주씩 재시작 없이 켜져 있어도 화면이 망가지지 않아야 합니다. 즉 같은 리액트라도 웹 문서에서는 “서버가 이미 아는 내용을 어떻게 빨리 보여줄 것인가”가 숙제였다면, 기기에서는 “계속 변하는 상태를 어떻게 일관되게 화면으로 투영할 것인가”가 숙제가 됩니다. 그런데 이 두 번째 질문은, 재미있게도, 리액트가 처음 만들어질 때 세상에 던졌던 질문이기도 합니다. 이 부분에 대해 부연을 해보자면, 리액트가 어떤 문제에서 출발했는지를 이야기해야겠습니다. 리액트는 2013년 5월 JSConf US에서 처음 공개되었는데, 그 전에 페이스북 안에서 먼저 쓰이고 있었고 인스타그램이 그 뒤를 이었습니다. 찾아보니 리액트 초기 멤버였던 피트 헌트(Pete Hunt)는 ACM Queue와의 인터뷰에서 페이스북의 웹 앱 가운데 가장 복잡한 것으로 광고를 만들고 광고 계정을 관리하는 도구를 꼽았고, 그 화면을 Bolt라는 DOM 변화 감시 시스템으로 만들던 시절에는 아무도 원인을 풀지 못하는 버그가 쌓였다고 회고합니다. 읽는 문서라기보다 값을 입력하고 상태를 확인하며 계속 조작하는 도구에 가까운 화면이었을 것으로 짐작합니다. 이 문제에 대한 리액트의 답은, 헌트가 2013년 인터뷰에서 설명한 표현을 빌리면, 데이터가 바뀔 때마다 서버 렌더링 앱에서 새로고침 버튼을 누르는 것처럼 화면 전체를 다시 그린다고 생각하게 만드는 것이었습니다. 어디를 어떻게 고칠지 개발자가 일일이 지시하는 대신 지금 상태에서 화면이 어떤 모습이어야 하는지만 선언하고, 실제로 무엇이 달라졌는지는 가상 DOM이라는 내부 표현을 비교해서 리액트가 찾아냅니다. 정리하면 리액트의 첫 질문은 “이 문서를 얼마나 빨리 보여줄 것인가”가 아니라 “계속 바뀌는 상태와 화면이 어긋나지 않게 하려면 어떻게 해야 하는가”였고, 이 질문은 제가 생각하기에, 서버 렌더링과 검색 노출이 중요한 웹 문서보다 인터폰이나 주문용 태블릿 같은 기기 화면의 질문에 훨씬 가깝습니다. 그래서 기기 화면에서 리액트가 자연스럽게 맞아떨어지는 것은 우연이 아니라 설계의 출발점에 가까운 일이라고 저는 생각합니다. 이 차이는 화면 바깥의 네트워크 지식에서 더 선명해집니다. 일반적인 웹 프런트엔드에서 개발자가 직접 마주하는 네트워크 모델은 대체로 HTTP 기반의 요청과 응답을 중심으로 합니다. DNS 조회, TCP나 QUIC 연결, TLS 같은 하위 계층의 상당 부분은 브라우저와 인프라가 추상화해주고, 애플리케이션 개발자는 주로 상태 코드, 헤더, 캐시, 인증, CORS 같은 상위 계층을 다룹니다. 물론 웹소켓이나 SSE(서버가 브라우저로 이벤트를 계속 흘려보내는 HTTP 기반 방식)처럼 연결을 길게 유지하는 웹 서비스도 있고, 장애와 재연결이 설계 대상이라는 점은 웹도 마찬가지입니다. 다만 일반적인 웹 애플리케이션에서는 장비 통신에 비해 전송 계층 자체를 직접 의식할 일이 상대적으로 적습니다. 기기와 장비가 서로 통신하는 네트워크에서는 이 전제가 거의 모두 뒤집힙니다. 통신의 상대가 서버 한 대가 아니라 센서, 게이트웨이, 그 외의 기타 다른 기기이고, 프로토콜도 HTTP 하나가 아니라 시리얼 회선 위의 Modbus RTU나 이더넷 위의 Modbus TCP, 산업 표준인 OPC UA, 발행/구독 방식의 MQTT처럼 목적에 따라 갈립니다. 특히 Modbus 같은 프로토콜에서는 레지스터 주소와 바이트 순서를 직접 다뤄야 하고, 32비트 값을 두 레지스터에 나누어 담을 때 제조사마다 순서가 다르기도 해서 데이터시트를 읽고 값의 의미를 직접 해석해야 합니다. MQTT처럼 전달되는 내용의 형식을 애플리케이션이 정하는 프로토콜도 있고, OPC UA처럼 데이터에 의미 정보까지 붙여 모델링하는 훨씬 높은 수준의 표준도 있습니다. 통신 모델도 프로토콜마다 크게 달라서, Modbus처럼 요청과 응답이 명확한 프로토콜이 있는가 하면 MQTT처럼 브로커와 연결을 유지한 채 발행/구독으로 비동기 메시지를 주고받는 프로토콜도 있습니다. TCP 기반 프로토콜에서는 연결을 장시간 유지하는 경우가 있고, 시리얼 통신에는 애초에 TCP식 연결 개념이 적용되지 않습니다. 어느 경우든 케이블이 빠지거나 장비가 재부팅되어 통신이 끊기는 것은 예외가 아니라 일상입니다. 그래서 하트비트와 타임아웃, 재연결 정책, MQTT의 QoS 단계, Last Will 메시지처럼 “상대가 사라졌다는 사실을 어떻게 알아챌 것인가”를 다루는 지식이 중요해지고, 망 구성도 공인 인터넷이 아니라 폐쇄망 안에서 사설 인증서와 고정 IP, 시간 동기화까지 신경 써야 하는 경우가 흔합니다. 브라우저가 임의의 TCP 소켓이나 시리얼 포트를 자유롭게 열 수 없다는 보안 모델상의 제약 때문에, 웹 화면이 장비와 직접 대화하기보다 게이트웨이가 장비의 언어를 HTTP나 웹소켓으로 번역해주는 구조가 일반적이고, 이 번역의 품질이 화면에 보이는 상태의 신뢰도를 좌우합니다. 여기 나온 이름들이 낯선 분들을 위해 짧게 풀어두겠습니다. Modbus는 1979년에 만들어진 오래된 프로토콜인데, 한쪽이 “몇 번 장비의 몇 번 레지스터 값을 알려달라”고 물으면 상대가 숫자로 답하는 아주 단순한 질의응답 구조입니다. 레지스터는 번호가 붙은 작은 숫자 저장칸이라고 생각하시면 되고, 그 숫자가 온도인지 압력인지는 통신 규약이 아니라 장비 제조사가 제공하는 데이터시트의 표에 적혀 있습니다. 같은 질의응답을 RS-485 같은 시리얼 회선으로 주고받으면 Modbus RTU, 이더넷의 TCP 위에서 주고받으면 Modbus TCP입니다. OPC UA는 제조사가 서로 다른 장비와 소프트웨어가 데이터를 주고받을 수 있도록 만든 국제 산업 표준(IEC 62541)으로, 번호 붙은 칸이 아니라 이름과 자료형 같은 의미 정보가 붙은 객체 구조로 데이터를 표현하고 인증과 암호화도 규격에 포함하고 있습니다. MQTT는 발행/구독 방식의 메시징 프로토콜로, 센서가 브로커라는 중개 서버의 어떤 주제(topic)에 값을 올리면 그 주제를 구독하던 화면이나 서비스가 전달받으며, 양쪽이 서로의 주소를 알 필요가 없고 헤더가 가벼워서 불안정한 망에서도 널리 쓰입니다. 나머지 용어도 마찬가지입니다. 하트비트(heartbeat)는 “나 아직 살아 있다”는 신호를 일정 간격으로 주고받다가 신호가 끊기면 상대가 사라졌다고 판단하는 방식이고, MQTT의 QoS는 메시지가 최대 한 번(0), 최소 한 번(1), 정확히 한 번(2) 전달되도록 보장하는 정도를 고르는 단계입니다. Last Will 메시지는 장비가 연결을 맺을 때 브로커에 미리 맡겨두는 메시지로, 장비가 비정상적으로 끊기면 브로커가 대신 발행해서 “이 장비가 사라졌다”는 사실을 화면에 알려줍니다. VLAN은 하나의 물리적 네트워크를 여러 개의 논리적 2계층(데이터 링크 계층) 네트워크로 나누는 기술로, 서로 다른 VLAN 사이의 통신에는 라우팅과 별도의 정책이 필요하고, NTP는 장비들의 시계를 서로 맞추는 프로토콜입니다. 시계가 어긋나면 어느 장비의 기록이 먼저인지조차 알 수 없어서, 현장에서는 생각보다 중요한 설정입니다. 웹에서는 응답이 늦으면 로딩 표시와 재시도 버튼으로 대부분 해결되지만, 기기에서는 응답이 오지 않는다는 사실 자체가 하나의 상태이고, 그 상태를 정의하지 않으면 사용자는 멈춘 화면 앞에서 기계가 고장 난 것인지 통신이 끊긴 것인지 알 수 없습니다. 상태로부터 화면을 계산한다는 리액트의 모델이 기기 화면에서 더 절실한 이유가 여기에 있습니다. 상태 기계로서의 화면 리액트가 2013년 JSConf US에서 처음 공개되었을 때의 핵심 주장은, 화면을 직접 조작하지 말고 상태로부터 화면을 계산하라는 것이었습니다. 이 발상은 UI의 상태를 명시적으로 모델링하려는 더 오래된 여러 흐름과도 닿아 있습니다. 예를 들어 데이비드 하렐이 1987년 「Statecharts: A Visual Formalism for Complex Systems」에서 정리한 스테이트차트 모델이 그렇습니다. 웹 쪽에서는 2014년 페이스북이 공개한 Flux가 단방향 데이터 흐름을 대중화했고, 그 영향을 받아 등장한 Redux는 여기에 엘름(Elm) 아키텍처의 아이디어까지 받아들였습니다. 이 모델이 현장 화면에서 얼마나 자연스러운지는 인터폰 같은 장치를 떠올릴 때 가장 선명하게 느껴졌습니다. 대기, 호출 수신, 통화 중, 문 열림 처리 중, 네트워크 끊김처럼 화면이 가질 수 있는 상태가 유한하고, 상태마다 허용되는 조작과 보여줄 것이 다르기 때문입니다. 타입스크립트의 판별 유니언(discriminated union)을 쓰면 이 구조가 거의 그대로 코드가 됩니다. type IntercomState = | { kind: "idle" } | { kind: "ringing"; visitorId: string } | { kind: "talking"; visitorId: string; startedAt: number } | { kind: "doorOpening"; visitorId: string } | { kind: "offline"; retryAt: number }; function Screen({ state }: { state: IntercomState }) { switch (state.kind) { case "idle": return <StandbyView />; case "ringing": return <IncomingCall visitorId={state.visitorId} />; case "talking": return <VideoCall visitorId={state.visitorId} since={state.startedAt} />; case "doorOpening": return <DoorProgress visitorId={state.visitorId} />; case "offline": return <OfflineNotice retryAt={state.retryAt} />; default: { const _exhaustive: never = state; return _exhaustive; } } } 여기서 never 검사가 중요합니다. 요구사항이 바뀌어 상태가 하나 추가되면 그 상태를 처리하지 않은 모든 지점이 컴파일 단계에서 드러납니다. 현장에 설치된 기기를 쉽게 고칠 수 없다는 점을 생각하면 “빠뜨린 상태”를 배포 전에 잡아주는 이 성질은 편의가 아니라 안전장치에 가깝습니다. 여기에 useReducer로 상태 전이를 한곳에 모으거나 XState 같은 상태 기계 라이브러리로 허용 가능한 전이(transition)를 명시하면 존재해서는 안 되는 상태 전이를 훨씬 체계적으로 차단할 수 있고, 충분한 상태 전이와 이벤트 로그를 남겨두면 현장에서 어떤 순서로 이상 동작이 발생했는지를 추적하고 재현하는 데 큰 도움이 됩니다. 컴포넌트 구조도 마찬가지입니다. 카메라 영상 영역, 통화 상태 표시, 숫자 키패드, 문 열림 버튼, 볼륨 조절은 실제 기기에서도 독립적인 조작 단위여서 컴포넌트 트리가 제품의 구조를 거의 그대로 반영하게 됩니다. 블로그의 한 문단까지 컴포넌트로 만드는 것이 과하다고 느꼈던 저에게, 이 일치는 “추상화가 비용이 아니라 설계 도구가 되는 자리”를 보여주었습니다. 렌더러라는 이음매 리액트가 브라우저 바깥으로 나갈 수 있는 이유는 변경 사항을 계산하는 부분과 그 결과를 실제 환경에 반영하는 부분을 분리해 둔 구조에 있습니다. 리액트는 무엇이 바뀌었는지를 계산하는 reconciler와, 그 결과를 실제 환경에 반영하는 렌더러를 구분하며, 이 구분은 파이버 이전인 2015년 React Native가 처음 소개될 때도 이미 존재했습니다. 2017년 리액트 16에서는 기존 reconciler를 파이버(Fiber) 아키텍처로 전면 재작성했고, 이 구조를 이용해 별도의 렌더링 환경을 구현할 수 있게 해주는 react-reconciler 패키지도 존재합니다(다만 이 패키지는 공식 저장소에서 실험적인 커스텀 렌더러용 패키지로 안내되고 있습니다). 렌더러를 만드는 사람은 호스트 환경에서 노드를 생성하고 자식을 붙이고 갱신하는 방법 등을 정의하는 호스트 설정(host config)을 구현해야 하고, 상태 관리와 훅, 컴포넌트 합성 같은 나머지는 리액트가 그대로 제공합니다. 이 이음매 덕분에 react-dom은 브라우저 DOM을, React Native는 iOS와 안드로이드의 네이티브 뷰를, react-three-fiber는 three.js 장면을, Ink는 터미널의 텍스트 UI를 대상으로 삼습니다. 여기에 리액트 컴포넌트로 영상의 프레임을 구성하는 Remotion처럼, 컴포넌트 모델을 전혀 다른 출력물에 활용하는 도구도 있습니다. 레이아웃에는 React Native와 Ink가 모두 플렉스박스 레이아웃 엔진 요가(Yoga)를 활용하는 것으로 알고 있는데, 덕분에 웹에서 익힌 플렉스박스식 배치 감각을 모바일 앱이나 터미널 화면에서도 상당 부분 그대로 쓸 수 있습니다. React Native가 2015년 처음 소개될 때 내건 표어가 “write once, run anywhere”가 아니라 “learn once, write anywhere”였다는 점도 의미심장합니다. 같은 코드를 모든 곳에서 돌리겠다는 약속이 아니라, 같은 사고방식을 모든 곳에서 쓰겠다는 약속이었습니다. 이후 React Native는 JSI를 기반으로 Fabric과 TurboModules 등을 도입한 New Architecture를 0.76부터 기본으로 활성화했고(모바일 환경에 최적화된 자바스크립트 엔진 Hermes는 그보다 앞선 0.70부터 기본 엔진이었습니다), 마이크로소프트가 윈도우와 맥OS용 React Native를 따로 유지한다는 사실에서도 이 접근이 모바일에만 머물지 않음을 짐작할 수 있습니다. 결국 리액트에서 본체는 DOM이 아니라 “상태 변화를 최소한의 변경 목록으로 환산하는 계산”이었고, DOM은 그 계산 결과를 받아주는 여러 호스트 가운데 가장 유명한 하나였을 뿐입니다. 크롬이 들어 있는 기계들 현장에서 가장 자주 마주치는 구성은 사실 React Native가 아니라 “크로미움이 들어 있는 기계”입니다. 키오스크, 사이니지, 설비 옆 패널 PC는 상당수가 전체 화면 크롬이나 일렉트론, 혹은 임베디드 웹뷰 위에서 동작하는 웹 애플리케이션입니다. (지금 제가 상주 프리랜서로 근무하고 있는 곳에서도 저는 일렉트론을 다루고 있습니다.) 일렉트론(Electron)은 2013년 GitHub의 Atom 에디터를 위해 Atom Shell이라는 이름으로 시작되어 2015년에 개명되었고, 크로미움과 Node.js를 하나로 묶어 데스크톱 앱을 웹 기술로 만들 수 있게 해준 도구입니다. 슬랙과 디스코드, VS Code가 그 위에서 돌아간다는 사실은 이미 유명하지만, 같은 구조가 화면 하나짜리 전용 기기에도 그대로 들어간다는 점은 상대적으로 많은 이들이 모르는 사실입니다. TV 쪽도 비슷합니다. 찾아보니 LG전자는 webOS TV용으로 리액트 기반의 Enact라는 프레임워크를 오픈소스로 공개했고, 넷플릭스는 TV 기기용 UI에 리액트를 쓰기 위해 Gibbon이라는 별도 렌더링 계층을 썼다고 기술 블로그에서 밝힌 것으로 기억합니다. 웹 기술이 이렇게 기기로 번지는 데에는 이유가 분명합니다. 웹은 가장 널리 퍼진 UI 런타임이고, 개발자 풀이 넓으며, 디자이너와 개발자가 같은 언어(HTML과 CSS)로 소통할 수 있고, 화면 갱신을 네트워크로 배포하는 일이 네이티브 펌웨어를 다시 굽는 일보다 훨씬 가볍기 때문입니다. 2007년에 제프 앳우드(Jeff Atwood)가 남긴 “자바스크립트로 작성할 수 있는 모든 애플리케이션은 결국 자바스크립트로 작성될 것이다”라는 말은 농담 반 예언 반이었는데, 제조 현장에서 일하다 보면 이 문장이 꽤 진지하게 읽힙니다. 화면 뒤에서 일하는 타입스크립트 화면만 자바스크립트인 것은 아닙니다. 설비와 화면 사이에는 데이터를 모으고 가공하고 전달하는 층이 있는데, 이 층에서도 Node.js와 타입스크립트가 의외로 깊숙이 들어 있습니다. IBM에서 시작해 지금은 OpenJS 재단에서 관리되는 Node-RED는 자바스크립트로 만든 플로우 기반 도구로 IoT와 산업 현장의 데이터 흐름을 시각적으로 연결하는 데 널리 쓰이고, 경량 메시징 프로토콜인 MQTT(1999년 IBM에서 탄생해 2014년 OASIS 표준이 된)에는 브라우저와 노드 양쪽에서 쓰는 mqtt.js 같은 클라이언트가 있으며, 산업 통신 표준인 OPC UA(IEC 62541)에도 node-opcua 같은 구현이 존재합니다. 재미있게도 Node-RED 자체도 처음에는 MQTT 토픽 사이의 데이터 연결을 시각화하려는 작은 프로젝트에서 출발했다고 합니다. 2011년 RFC 6455로 표준화된 웹소켓은 이런 실시간 데이터를 브라우저나 웹뷰 화면까지 밀어 올리는 대표적인 통로입니다. 이 구조가 주는 이득은 언어 하나로 통일된다는 점보다 데이터 규약을 공유할 수 있다는 점에 있다고 생각합니다. 장치 메시지의 데이터 규약을 Zod 같은 런타임 스키마와 타입스크립트 타입으로 함께 정의해 공유 패키지로 관리하면 게이트웨이와 화면이 같은 정의를 참조하게 되고, 현장에서 필드 하나의 의미가 바뀌었을 때 그 변경이 퍼져나가는 지점을 컴파일러와 스키마 검증이 함께 알려줍니다. 타입스크립트의 타입은 실행 시점에 데이터를 검사해주지 않기 때문에, 장비에서 올라오는 값을 믿고 쓰려면 런타임 검증이 따로 필요합니다. 서로 다른 언어와 팀이 경계를 맞대고 있던 구조에서는 문서와 구두 합의가 하던 일을 스키마와 타입이 맡게 됩니다. 모니터링 화면의 대표 격인 그라파나(Grafana)가 프런트엔드를 리액트와 타입스크립트로 만든 대표적인 오픈소스 사례라는 점도, 이 조합이 산업 데이터를 다루는 화면과 잘 맞는다는 방증이 아닐까 생각합니다. 현장은 브라우저 탭보다 가혹하다 물론 웹 기술이 기기로 번졌다고 해서 웹 개발의 감각이 그대로 통하는 것은 아닙니다. 일반적인 소비자용 웹 페이지는 사용자가 잠깐 쓰다 닫는 경우가 많지만 기기 화면은 몇 주, 몇 달씩 종료되지 않은 채 동작하는 경우가 있어서, 작은 메모리 누수나 이벤트 리스너 중복 등록이 며칠 뒤에야 화면 멈춤으로 나타납니다. (……새벽 세 시의 메모리 그래프는 정직합니다.) 네트워크는 끊어지는 것이 정상 상태이므로 오프라인에서 어떤 화면을 보여주고 복구 후에 어떻게 재동기화할지가 설계에 들어가야 하고, 마우스 호버도 키보드 단축키도 없는 터치 환경에서는 버튼 크기와 간격, 오조작 방지, 유휴 시 초기 화면 복귀 같은 인터랙션 규칙을 처음부터 다시 생각해야 합니다. 저사양 기기에 크로미움 하나를 통째로 올리는 것은 메모리와 부팅 시간 면에서 만만한 선택이 아니어서, 자원이 빠듯한 기기에서는 웹 기술이 아닌 네이티브 방식이 여전히 합리적일 수 있고, 플러터 같은 다른 선언형 UI 도구도 기기 쪽으로 영역을 넓히고 있습니다. 무엇보다 중요한 선은 제어 루프입니다. 설비를 실제로 움직이고 멈추는 안전 관련 실시간 제어는 설비 전용 제어기의 몫이고, 결정론적 응답이 필요한 그런 제어를 가비지 컬렉션이 있는 일반적인 자바스크립트 런타임에 맡길 일은 아닙니다. 화면은 상태를 보여주고 명령을 전달하는 층이지 안전을 책임지는 층이 아니라는 구분만큼은 늘 의식하려고 합니다. 그러니 제가 말하는 것은 "현대 화면 개발은 리액트가 최고"라거나 "이제는 리액트의 시대도 끝나야 한다" 따위의 것들이 아니라, 그저 리액트가 어울리는 문제의 범위가 제가 생각했던 것보다 훨씬 넓었다는 것 정도입니다. 읽히는 문서인가, 조작되는 장치인가 이전까지 제가 피로감을 느꼈던 것은 리액트 자체가 아니라, 단순한 웹 문서를 보여주는 일에까지 애플리케이션 아키텍처를 들이대면서 그것을 정답처럼 여기는 분위기였던 것 같습니다. 문제의 크기와 도구의 크기가 어긋나는 데에서 오는 피로감이었다고 말할 수 있지 않을까요. 병원이나 자영업자의 소개 페이지처럼 단순한 화면에 하이드레이션 전략까지는 필요하지 않다는 생각은 지금도 여전합니다. 그러나 하루 종일 상태가 변하고, 사람이 끊임없이 만지고, 하드웨어와 서버가 번갈아 상태를 밀어 넣는 화면이라면 같은 도구가 전혀 다른 무게를 갖습니다. 그래서 요즘 저는 기술을 고르기 전에 질문 하나를 먼저 던집니다. 이 화면은 읽히는 문서에 가까운가, 조작되는 장치에 가까운가. 쇼핑몰처럼 둘이 섞인 경우가 많아 정답이 하나로 떨어지지는 않지만, 어느 쪽 성격이 강한지를 따져보는 것만으로도 SSR, 서버 컴포넌트, 상태 기계, 오프라인 전략 같은 선택지는 훨씬 빨리 정리될 수 있을 것입니다.

2026.09.28
개발
React에서 벗어나고 싶었던 어느 리액트 개발자 이야기

여러분이 보고 계시는 이 웹 사이트는 워드프레스와 php로 구축되었습니다. 태어나 처음으로 워드프레스와 php를 만져보면서 생각했던 것들을 정리해봅니다. 화면을 위한 라이브러리였던 리액트 저는 회사에서 리액트로 서비스를 개발하던 프런트엔드 개발자였습니다. 물론 지금은 AI의 도움으로 프런트엔드에 국한되지 않고 회사에서 필요한 게 있으면 닥치는 대로 개발하는 잡부 느낌이 강하긴 하지만, 어쨌든 저의 명함에는 꽤 오랫동안 "Frontend Engineer"라는 직함이 박혀 있었습니다. 개발자라는 직업을 얻게 된 이래로 저는 리액트를 사용하며 컴포넌트 단위로 UI를 설계하는 법을 배웠고, 선언형 렌더링이 주는 생산성을 체감할 수 있었습니다. 상태가 바뀌면 화면이 따라 바뀐다는 단순한 모델은 확실히 jQuery로 DOM을 직접 조작하던 시절과 비교하면 분명한 진보였을 것입니다...... 하지만 현업에서 리액트만을 전문으로 수 년을 다뤘던 리액트 개발자였던 제가, 어쩌다 어느새부턴가 "이제는 리액트 좀 그만 쓰고 싶다", 는 생각을 하고 있었습니다. 이번에 새 블로그를 구축하기 위해 생전 처음 다뤄보는 워드프레스 php를 사용해보면서, 저는 이 글에서 웹 개발에서 프런트엔드의 기술 스택으로 리액트를 선택하는 것이 마치 업계 전체의 기본값이 되어버린 것 같은 오늘날의 모습에 대한 지극히 개인적인 저의 생각들을 나눠보려고 합니다. 리액트는 처음에 스스로를 "사용자 인터페이스를 만들기 위한 자바스크립트 라이브러리"라고 소개했습니다. 개발자들 사이에서 리액트가 프레임워크냐 라이브러리냐에 관하여 논쟁도 꽤 있었던 것으로 기억합니다만 분명 리액트의 처음 시작은 "라이브러리"였었고, 이에 따른 리액트의 역할도 명확했습니다. "브라우저에서 가상 DOM을 기반으로 화면을 그리고, 상태 변화에 따라 필요한 부분만 갱신하는 것". 이 때 당시만 해도 라우팅 데이터 요청이나 서버 렌더링 따위는 리액트의 관심사가 아니었습니다. 성능과 SEO가 불러온 서버로의 회귀 문제는 클라이언트 사이드 렌더링(CSR)의 구조적 한계에서 시작됩니다. CSR 방식의 싱글 페이지 애플리케이션은 서버에서 사실상 비어 있는 HTML 문서와 자바스크립트 번들을 내려보냅니다. 실제 콘텐츠는 브라우저가 번들을 내려받고, 파싱하고, 실행한 뒤에야 만들어집니다. 실제 로딩 과정에서 CSR이 문제가 되는 지점은 조금 더 구체적입니다. 브라우저는 HTML을 파싱하면서 스크립트 태그를 발견하면 자바스크립트를 병렬로 내려받기 시작할 수 있고, 브라우저의 preload scanner는 메인 파서보다 앞서 리소스를 미리 찾아 요청하기도 합니다. 하지만 문제는 페이지의 핵심 콘텐츠나 그 콘텐츠를 위한 API 요청이 애플리케이션 자바스크립트의 실행 이후에야 발견되는 경우에 발생합니다. 페이지의 핵심 콘텐츠를 로드하는 것이나 그 콘텐츠를 위한 API 요청이 애플리케이션이 자바스크립트가 실행된 이후에야 시작될 수 있다는 것, 자바스크립트 실행이 완료되어야 컴포넌트 트리가 만들어지고, 그제야 API 요청이 시작되고, 응답이 돌아온 뒤에야 콘텐츠를 화면에 그릴 수 있다는 사실은 자바스크립트 실행 → API 요청 → 데이터 수신 → 렌더링까지의 각 과정이 순차적으로 그 바로 전 단계에 의존하고 있다는 것을 의미합니다. 여기서 LCP(Largest Contentful Paint)가 늦어지는 이유는 단순히 "자바스크립트가 느리다"는 문제만으로는 설명할 수 없습니다. 여기서의 진짜 문제는 핵심 콘텐츠가 자바스크립트 실행이나 클라이언트 API 요청에 의존하는 구조, 그 자체입니다. 자바스크립트는 네트워크로 내려받는 것만으로 끝나지 않습니다. 브라우저는 그것을 파싱하고, 컴파일하고, 실행해야 하며, CPU가 느린 모바일 기기에서는 이 비용이 더욱 커질 수밖에 없고, 가끔 정말 똥컴(...)이나 오래된 모바일 기기를 사용하다 보면 자바스크립트가 메인 스레드를 점유하는 동안에는 화면이 보이는데도 클릭과 입력이 반응하지 않는 상황이 만들어지기도 합니다. 검색 노출에 관한 문제는 조금 더 미묘합니다. 구글봇은 크로미움 기반 렌더러로 자바스크립트를 실행할 수 있습니다. 다만 CSR 페이지에서 핵심 콘텐츠가 초기 HTML에 존재하지 않는다면, Google은 렌더링 단계를 거쳐야 그 콘텐츠를 확인할 수 있습니다. 이 렌더링은 별도의 큐에서 처리되며, 페이지가 그 단계에 도달하기까지 시간이 걸릴 수 있습니다. 서버가 완성된 HTML을 응답한다면 크롤러는 HTTP 응답만으로 콘텐츠를 바로 발견하지만, CSR 구조에서는 자바스크립트를 발견하고, 렌더링하고, 그 결과에서 콘텐츠를 발견하는 단계가 더 얹어집니다. 게다가 모든 크롤러가 구글봇만큼 완전한 렌더러를 가지고 있는 것도 아니어서, 많은 링크 미리보기 크롤러는 자바스크립트 실행을 보장하지 않습니다. 자바스크립트 실행 이후 주입되는 오픈 그래프 메타 태그나 타이틀이 제대로 인식되지 않는 경우가 생기는 이유입니다. 이제 콘텐츠와 검색 유입이 중요한 서비스에서는, 핵심 콘텐츠를 초기 HTML에 포함시키기 위한 SSR이나 SSG, 프리렌더링이 중요한 선택지가 되었습니다. 리액트 생태계는 이 요구에 응답하기 위해 그 컨트롤 범위를 UI 영역에서 점점 서버 영역으로 확장시키게 됩니다. 리액트 18, UI 라이브러리에서 웹 아키텍처로 리액트가 서버로 확장된 흐름을 이해하려면 최근 5~6년 사이의 리액트 버전 변화를 짚고 넘어가는 것이 도움이 될 것 같습니다. 리액트 17은 사실상 기능 추가가 없는 릴리즈였습니다. 리액트 팀이 공식적으로 밝혔듯이 17은 "아무 새 기능도 없는" 버전이었고, 핵심 목적은 리액트를 점진적으로 업그레이드할 수 있도록 기반을 정리하는 것이었습니다. 서로 다른 버전의 리액트 트리를 한 페이지에서 공존시키기 쉽게 만들기 위해 이벤트 위임 위치를 document에서 각 root container로 옮긴 것도 그 맥락이었습니다. 버전 17 자체는 조용했지만, 그 조용함은 버전 18에서의 엄청난 지각변동급 변화를 준비하고 있었습니다. 리액트 18에서 일어난 가장 근본적인 변화는 동시성 렌더링(Concurrent Rendering)의 도입입니다. 기존의 ReactDOM.render를 대체하는 새로운 루트 API createRoot는 리액트 18의 새로운 렌더러와 기능을 사용할 수 있게 하는 기반이 되었습니다. 이전까지 리액트의 렌더링은 동기적이었습니다. 한 번 시작하면 중간에 멈출 수 없었고, 렌더링이 진행되는 동안 브라우저는 다른 작업을 할 수 없었습니다. createRoot 위에서 startTransition이나 Suspense 같은 concurrent feature를 사용하면, 리액트는 렌더링 작업의 우선순위를 나누고 낮은 우선순위 작업을 중단했다가 다시 이어갈 수 있습니다. useTransition과 startTransition이 그 진입점입니다. 급하지 않은 상태 업데이트를 startTransition으로 감싸면, 리액트는 그 렌더링을 후순위로 밀어두고 사용자 인터랙션에 먼저 반응합니다. 자동 배칭(Automatic Batching)도 리액트 18의 주요 변화 중 하나입니다. 리액트 17까지는 이벤트 핸들러 내부의 상태 업데이트만 묶어서 한 번에 처리했습니다. setTimeout, Promise, 네이티브 이벤트 핸들러 안에서의 상태 업데이트는 각각 별도의 렌더링을 유발했습니다. 리액트 18부터는 이런 비동기 상황에서의 업데이트도 자동으로 묶입니다. 사소해 보이지만, 불필요한 렌더링이 줄어드는 실질적인 성능 개선입니다. 그러나 뭐니뭐니해도 리액트 18에서 가장 큰 의미를 가지는 변화는 역시 서버 영역입니다. 리액트 18은 renderToPipeableStream과 renderToReadableStream이라는 새로운 서버 렌더링 API를 도입했습니다. 기존의 renderToString은 페이지 전체 HTML이 완성될 때까지 기다렸다가 한꺼번에 전송하는 방식이었지만, 이제 새 API는 Suspense 경계를 기준으로 준비된 부분부터 스트리밍으로 흘려보낼 수 있게 되었습니다. 서버가 느린 데이터를 기다리는 동안 이미 준비된 헤더와 본문 영역을 먼저 브라우저에 내려보내고, 댓글이나 추천 콘텐츠처럼 시간이 걸리는 부분은 준비되는 대로 이어 붙이는 방식입니다. 이렇게 되면 브라우저는 전체 HTML을 기다리지 않고서도 먼저 수신되는 순서대로 렌더링을 시작할 수 있습니다. 그리고 여기에 더해, 리액트 서버 컴포넌트(RSC)가 있습니다. RSC는 사실 리액트 18보다 먼저 등장했습니다. 리액트 팀은 2020년 말 처음 RSC 연구 결과를 공개했고, React 18이 출시된 2022년에도 이 기능은 여전히 실험 단계였습니다. React 18이 스트리밍 SSR과 Suspense 기반 서버 렌더링의 토대를 정식으로 제공했다면, RSC는 이후 Next.js App Router 같은 프레임워크를 통해 먼저 현실의 애플리케이션에 들어오기 시작했고, React 19에서야 리액트 차원의 안정 기능으로 자리 잡았습니다. 동시성 렌더링이 클라이언트에서의 렌더링 방식을 바꿨다면, RSC는 컴포넌트 자체의 실행 위치를 다시 정의했습니다. 이 두 변화가 합쳐지면서 리액트는 더 이상 브라우저에서 동작하는 "UI 라이브러리"라는 정체성만으로는 설명되지 않게 되었습니다. 리액트는 여전히 스스로를 UI 라이브러리라고 부릅니다. 다만 현재의 공식 문서는 동시에 'full-stack React architecture'라는 방향을 명시하고 있고, 새로운 애플리케이션을 시작할 때는 리액트만 직접 구성하기보다 프레임워크를 사용할 것을 권장합니다. jQuery식 직접 DOM 조작이 일반적이던 시대에 등장한 도구가 십여 년을 거치면서 서버 런타임, 캐시 전략, 번들 경계, 데이터 페칭 패턴까지 의견을 내는 존재가 된 것입니다. 라이브러리라는 이름은 그대로지만, 그 주변에 제안되는 아키텍처의 범위는 초기와 비교하기 어려울 정도로 넓어졌습니다. 그런데 여기서 한 가지 중요한 맥락이 있습니다. 리액트 서버 컴포넌트는 리액트 18보다 먼저 연구 단계에서 공개되었지만, 리액트 자체는 이를 당장 프로덕션에서 쓸 수 있는 완성된 형태로 제공하지 않았습니다. RSC는 서버와 클라이언트를 아우르는 컴포넌트 모델이기 때문에, 실제로 동작시키려면 서버 런타임, 라우팅, 번들링, 스트리밍 처리까지 통합하는 프레임워크가 필요합니다. 그 역할을 가장 먼저, 그리고 가장 적극적으로 맡은 것이 Next.js입니다. Next.js를 만드는 Vercel은 리액트 팀과 긴밀히 협력하며 App Router라는 형태로 RSC를 프로덕션에서 쓸 수 있도록 구현했고, 현재 리액트 공식 문서도 새 프로젝트를 시작할 때 리액트만으로 프로젝트를 구성하기보다는 프레임워크를 사용하도록 권장하며 그 목록 맨 앞에 Next.js를 올려두고 있습니다. 그 결과, 특히 RSC를 중심으로 한 현대 React의 풀스택 아키텍처를 이야기하자면 이제는 Next.js를 빼놓기 어려워졌습니다. 생각해도 너무 복잡하게 느껴지는 Next.js 여기서 이야기하는 "복잡함"이란 제가 주로 실무에서 경험했던 Next.js 13~15 App Router 시기의 모델을 기준으로 합니다. 이후 Next.js 15에서 fetch와 Route Handler의 기본 캐싱 정책이 바뀌었고, Next.js 16에서는 Cache Components와 use cache를 중심으로 캐시를 명시적으로 선택하는 새로운 모델이 도입되었습니다. 흥미롭게도 이러한 변화 자체가, 초기 App Router의 암묵적 캐싱 모델이 개발자들에게 얼마나 큰 혼란을 만들었는지를 보여주기도 합니다. Next.js를 실무에서 다루며 가장 크게 느낀 것은 단순히 '복잡하다'는 감각이 아니었습니다. 더 정확히 말하면, 제가 쓴 코드의 의미를 이해하는 것과 그 코드가 Next.js 시스템 안에서 어떻게 작동하는지를 이해하는 것이 전혀 다른 일이 된다는 데에 있었습니다. 개발자는 자신의 비즈니스 로직뿐 아니라 프레임워크의 렌더링 결정 규칙, 캐시 계층 구조, 컴포넌트의 실행 위치까지 머릿속에 들고 있어야 합니다. App Router는 이름과 달리 단순한 라우터가 아닙니다. 과거에 제가 주로 사용하던 React Router의 선언적 라우팅을 떠올려보면 이는 URL과 컴포넌트를 연결하는 것이 전부였습니다. 하지만 Next.js App Router에서 폴더 구조는 단순히 라우팅 URL만 정하지 않습니다. layout.tsx는 하위 페이지들이 공유하면서 클라이언트 내비게이션 중에도 유지되는 UI를 정의하고, loading.tsx는 해당 route segment에 Suspense 경계를 만들고, error.tsx는 오류 경계를 담당합니다. 여기에 template.tsx, not-found.tsx, route.ts, parallel route, intercepting route까지 더해집니다. 각각의 파일이 단순히 '이 URL에서 보여줄 화면'이 아니라 렌더링 생명주기의 서로 다른 단계를 담당하는 구조로써 결합되고 있습니다. 특히 개발자로서 주의 깊게 신경써야 하는 부분은 렌더링 전략이 결정되는 방식입니다. 겉으로 보기에는 그냥 데이터를 가져오는 서버 컴포넌트가 있다고 해봅시다. 그런데 어느 하위 컴포넌트에서 cookies()를 한 번 호출하면, 그 route 전체가 빌드 시점에 만들어지는 정적 페이지에서 요청마다 실행되는 동적 페이지로 전환됩니다. 코드의 지역적인(local) 의미는 단순합니다. "쿠키를 읽는다.", 하지만 Next.js 아키텍처 안에서의 의미는 다릅니다. 그 한 줄이 이 route의 렌더링 전략을 바꾸고, Full Route Cache의 적용 여부까지 결정합니다. 코드의 지역적인 의미와 시스템 전체에서의 의미가 달라지는 이런 비지역적 효과(non-local effect)가 많아질수록, 코드를 읽는 것만으로는 동작을 온전히 파악하기 어려워집니다. 이와 더불어 Next.js의 캐싱 전략은 개발자들로 하여금 많은 혼란을 야기하였습니다. App Router의 캐시 구조는 '캐시됨/캐시 안 됨'이라는 단순한 이분법으로 이해할 수 없습니다. Next.js 문서 기준으로는 네 가지 계층이 존재합니다. Request Memoization은 한 번의 서버 렌더링 중 동일한 fetch 호출이 여러 컴포넌트에서 반복될 때 중복 요청을 막는 React 레벨의 최적화로, 요청이 끝나면 사라집니다. 요청을 넘어 유지되는 것은 Data Cache, Full Route Cache, 그리고 브라우저의 Router Cache입니다. Data Cache는 서버 요청을 넘어 지속되는 캐시로, 동일한 데이터를 여러 사용자 요청에 걸쳐 재사용합니다. Full Route Cache는 렌더링 결과인 HTML과 RSC Payload 자체를 저장하며, Data Cache와는 별개의 계층이지만 서로 영향을 주는 구조입니다. 브라우저에도 Router Cache가 있어서 이전에 방문했거나 prefetch된 route의 RSC Payload를 메모리에 저장합니다. 그래서 DB를 수정했는데 화면이 그대로일 때, 개발자는 특히 요청을 넘어서 유지되는 이 세 계층이 얽힌 상황에서 어디에 오래된 값이 살아 있는지 하나씩 추적해야 합니다. 데이터를 갱신하는 코드가 DB 수정 한 줄로 끝나지 않고, 어느 캐시를 무효화할 것인지, revalidatePath인지 revalidateTag인지, 클라이언트까지 router.refresh()가 필요한지까지 포함하게 됩니다. App Router 초기에는 성능을 극대화하려는 방향으로 캐싱이 공격적이었습니다. 명시하지 않은 서버 fetch가 force-cache 방향으로 동작했고, GET Route Handler도 조건에 따라 기본 캐시 대상이 됐습니다. 개발자가 데이터를 가져오는 코드를 작성할 때 '지금 데이터를 가져오는 것'인지 'Next.js가 저장해둔 데이터를 쓰는 것'인지 코드만으로는 알 수 없었습니다. Next.js 15에서 이 기본값을 크게 바꾼 것은 Next.js 팀 스스로 성능을 우선한 공격적인 기본값이 실제 개발자의 직관과 충돌했음을 인정한 결과였습니다. 초기의 추상화와 기본값이 개발자 경험 측면에서 충분히 안정적이지 않았음을 보여주는 사례입니다. 호스팅 환경에 대해서도 한 가지 짚어둘 필요가 있습니다. Next.js는 공식적으로 self-hosting을 지원하고, next start를 실행하면 이미지 최적화, Middleware, ISR, Streaming 등 대부분의 기능이 동작합니다. 문제는 규모가 커졌을 때입니다. 여러 인스턴스를 띄우면 각 서버가 자체 로컬 캐시를 가지기 때문에, 한 인스턴스가 갱신한 캐시를 다른 인스턴스는 알 수 없습니다. 캐시 일관성이 필요한 경우에는 Redis나 S3 같은 공유 저장소를 기반으로 한 custom cache handler가 필요하고, Nginx를 앞에 두면 버퍼링 설정을 따로 조정해야 스트리밍이 제대로 동작합니다. 이것이 Next.js가 Vercel에서만 동작한다는 뜻은 아닙니다. 다만 프레임워크가 추상화해주던 인프라의 복잡도가 자체 인프라에 배포하는 순간 다시 개발팀의 책임으로 모습을 드러낸다는 뜻입니다. App Router를 구성하는 각각의 아이디어는 떼어놓고 보면 상당히 논리적입니다. 정적 페이지는 캐시하면 빠르고, 같은 데이터를 여러 컴포넌트에서 중복 요청할 이유가 없고, RSC를 쓰면 클라이언트 번들을 줄일 수 있고, 스트리밍을 쓰면 느린 데이터 하나 때문에 전체 페이지가 늦어지는 것을 막을 수 있습니다. 문제는 그것들이 합쳐지면 개발자가 '이 컴포넌트는 서버인가 클라이언트인가, 이 route는 정적인가 동적인가, 이 fetch는 어느 캐시 계층에 들어가는가, 데이터가 바뀌면 어느 캐시를 무효화해야 하는가, 여러 인스턴스를 띄울 때 캐시 일관성은 어떻게 유지하는가'를 모두 머릿속에 들고 있어야 한다는 것입니다. 그렇게 이해하고 나서 지금 만들고 있는 페이지를 다시 보면 단순한 회사 소개, 블로그, 서비스 소개, 문의 폼...일 수 있습니다....... 먼 길을 돌아 다시 제자리 이러한 복잡함을 겪으면서 제 안에서는 근본적인 질문이 계속되었습니다. 서버에서 완성된 HTML을 내려주는 것이 필요하다면, 원래 그렇게 동작하던 전통적인 웹 개발 방식을 쓰면 되지 않을까? 웹의 기본 모델은 단순합니다. 서버는 요청에 HTML 문서를 응답하고, 브라우저는 그 문서를 렌더링합니다. 그 HTML은 정적 파일일 수도 있고, PHP 같은 서버 프로그램이 요청마다 생성한 결과일 수도 있습니다. 상호작용이 필요한 부분에만 자바스크립트를 더하는 것, 이 구조에서 검색엔진은 아무런 추가 장치 없이 완성된 문서를 읽습니다. 우리는 이 방식을 떠나 클라이언트에서 모든 것을 그리는 방향으로 이동했다가, 그로 인해 생긴 문제를 해결하기 위해 다시 서버로 돌아오고 있습니다. 다만 돌아오는 과정에서 훨씬 복잡한 구조를 짊어지고 왔습니다. 전통적인 React SSR에서 대표적으로 따라오는 비용이 바로 하이드레이션(hydration)입니다. 서버가 HTML을 만들어 보내더라도, 브라우저는 서버에서 만들어진 DOM을 재사용하면서 해당 컴포넌트의 렌더링 로직을 자바스크립트로 다시 실행해 이벤트 핸들러를 연결하고 React 트리와 맞춰야 합니다. SSR은 자바스크립트를 없앤 것이 아니라, 자바스크립트를 실행하기 전에 보여줄 HTML을 먼저 만들어둔 것에 가깝습니다. 화면은 빨리 보이지만 실제로 상호작용이 가능해지기까지는 시간이 걸리며, 서버와 클라이언트의 렌더링 결과가 조금이라도 어긋나면 하이드레이션 불일치 오류가 발생합니다. 그럼에도 이 여정 자체를 부정하고 싶은 것은 아닙니다. 앞서 살펴본 것처럼 리액트가 서버 영역으로 확장된 데에는 실제로 존재하는 많은 문제들이 있었고, 그 해법은 그 문제를 가진 서비스로서는 분명히 가치가 있었을 겁니다. 돌이켜보면 리액트가 걸어온 길에는 흥미로운 왕복 운동이 있습니다. 서버가 HTML을 만들던 전통적인 방식을 떠나 브라우저에서 모든 것을 그리는 방향으로 갔다가, 그로 인해 생긴 성능과 검색 문제를 해결하기 위해 다시 서버로 돌아갔다는 것, 이번에는 서버 컴포넌트, 서버 함수, 캐시 전략, 클라이언트와 서버의 실행 경계까지 함께 결정해야 하는 훨씬 복잡한 구조를 짊어지고서 말입니다. 매우 먼 길을 돌아, 서버가 HTML을 만들어 보내던 웹의 오래된 구조를 훨씬 복잡한 형태로 다시 발견하고 있는 것은 아닐까요. 한두 페이지짜리 사이트에 리액트가 필요할까 회사 소개 페이지, 이벤트 랜딩 페이지처럼 한두 페이지로 끝나는 정적 사이트를 만드는 데에도 리액트가 당연하게 선택되는 경우를 자주 보았습니다. 이 경우 개발자는 번들러를 설정하고, 수백 개의 패키지가 들어간 node_modules를 관리하고, 빌드와 배포 파이프라인을 구성해야 합니다. 물론 node_modules의 크기가 그대로 사용자에게 전달되는 것은 아닙니다. 하지만 단순한 정적 HTML로 충분했던 페이지에 리액트 런타임과 하이드레이션을 위한 자바스크립트까지 전달한다면 그만큼 다운로드와 파싱, 실행 비용이 추가될 수 있습니다. 의존성이 늘어날수록 업데이트와 호환성 관리 부담도 함께 늘어납니다. 해결하려는 문제에 비해 개발 환경과 런타임의 복잡성이 커지는 셈입니다. 보안 측면에서도 마찬가지입니다. 리액트가 아닌 기술을 이야기하면 흔히 보안 취약성이 거론되지만, 리액트 생태계 역시 보안에서 자유롭지 않습니다. npm 생태계는 수많은 전이 의존성 위에 서 있고, 패키지 탈취나 악성 코드 삽입 같은 공급망 공격은 반복적으로 발생해 왔습니다. 리액트가 서버로 영역을 넓히면서 공격 표면도 함께 넓어졌습니다. 2025년에는 React Server Components의 서버 함수 payload 처리 과정에서 인증 없이 원격 코드 실행이 가능한 CVE-2025-55182가 공개되기도 했습니다. 서버에서 코드를 실행하는 순간, 서버 개발의 보안 책임도 함께 지게 되는 것입니다. 어떤 기술이든 보안은 관리해야 할 대상이며, 구조가 단순하고 의존성이 적을수록 관리해야 할 지점은 줄어듭니다. 저는 무엇보다도, 리액트가 아닌 기술을 "레거시"라는 한 마디로 폄하하는 분위기가 답답했던 것 같습니다. 기업이 리액트를 고집하는 데에는 채용 시장의 풍부함, 기존 코드베이스와의 연속성, 팀 내 지식의 공유 같은 현실적인 이유가 있습니다. 그러한 판단 자체는 이해할 수 있습니다. 하지만 조직의 관성이 기술적 판단을 대신하기 시작하면, 우리는 문제를 보는 대신 도구를 보게 됩니다. 웹 개발의 역사는 서버 렌더링에서 SPA로, 다시 서버 중심으로 흘러가며 순환해 왔습니다. 오늘의 표준이 내일의 레거시가 되고, 어제의 방식이 다시 재발견되는 것이 이 분야의 흐름입니다. 최근에는 서버 중심의 렌더링을 다시 적극적으로 활용하려는 흐름도 뚜렷해지고 있습니다. Astro는 페이지 대부분을 정적 HTML로 내보내고 상호작용이 필요한 영역만 독립적으로 하이드레이션하는 아일랜드 아키텍처를 내세웁니다. htmx는 HTML 속성만으로 서버와 통신해 페이지 일부를 교체하는 방식을 제안하며, Rails의 Hotwire와 Laravel의 Livewire도 서버가 HTML을 만들고 클라이언트는 최소한의 역할만 하는 구조를 지향합니다. 모두 "서버가 문서를 만들고, 필요한 곳에만 상호작용을 더한다"는, 웹이 원래 가지고 있던 철학을 다시 꺼내 든 것입니다. AI 시대의 바닐라 자바스크립트 이런 생각 끝에 저는 개인적인 작업에서는 가능한 한 바닐라 자바스크립트를 사용하고, 리액트는 꼭 필요한 경우에만 쓰겠다는 생각을 하게 되었습니다...... 아니, 가능한 한 바닐라 자바스크립트를 사용한다기보다는, 굳이 프레임워크가 필요 없는 간단한 작업에까지 프레임워크라는 거대한 짐을 이고 지고 짊어지진 않겠다는 말이 더 정확할 것 같습니다. 이 선택을 가능하게 한 것은 두 가지의 변화입니다. 하나는 웹 플랫폼 자체의 성숙도가 올라갔다는 점입니다. 과거에 프레임워크나 라이브러리가 필요했던 기능들 상당수가 이제 브라우저 표준으로 제공됩니다. ES 모듈을 통해 빌드 없이 코드를 분리할 수 있고, fetch로 비동기 통신을 처리하며, 템플릿 리터럴로 마크업을 조립할 수 있습니다. <dialog> 요소는 모달을, Web Components는 재사용 가능한 컴포넌트를, View Transitions API는 화면 전환 애니메이션을 표준으로 지원합니다. CSS 역시 :has() 선택자와 컨테이너 쿼리, 네이티브 중첩 문법을 갖추면서 예전에는 자바스크립트로 처리하던 일들을 상당 부분 흡수했습니다. 다른 하나로는, 역시 AI의 발달을 들 수 있겠습니다. 예전에는 바닐라 자바스크립트로 기능을 구현하려면 반복적인 코드를 직접 작성해야 했고, 그 수고를 덜기 위해서라도 프레임워크에 의존했습니다. 이제는 AI의 도움으로 그러한 비용이 크게 줄었습니다. 빌드 과정 없이 브라우저에서 바로 실행되는 코드는 디버깅이 직관적이고, 의존성 업데이트에 시달릴 일도 없습니다. 다만 이 방식에도 한계가 있다는 점은 분명히 해두고 싶습니다. 애플리케이션의 규모가 커지면 상태 관리, 효율적인 DOM 갱신, 컴포넌트 간 통신 같은 문제를 결국 직접 해결해야 하고, 그 과정에서 문서도 규칙도 없는 무근본 자체 프레임워크(프레임워크를 의도하지 않았지만 어찌 저찌 나도 모르게 프레임워크가 되어 버리는)가 만들어지기도 쉽습니다. AI가 생성한 코드가 일관된 구조 없이 쌓이면 유지보수는 오히려 어려워집니다. 팀 단위 개발에서 프레임워크가 주는 공통의 규칙과 어휘는 여전히 큰 가치를 지닙니다. 다만, 그저 저에게 있어서 바닐라 자바스크립트는 작은 규모의 작업에서 불필요한 복잡성을 걷어내는 선택지일 뿐인 것입니다. 처음 다뤄본 워드프레스와 PHP 그리고 지금 저는 개인 블로그를 구축하기 위해 처음으로 워드프레스와 PHP를 다루고 있습니다. 가장 먼저 놀란 것은 생태계의 규모입니다. 워드프레스는 전 세계 웹사이트의 40% 이상을 구동하는 것으로 알려져 있습니다. 블로그를 구축하기 위해 필요한 기능 대부분은 이미 테마나 플러그인으로 구현되어 있고, 관련 문서와 커뮤니티의 축적량도 방대합니다. 구조를 들여다보면 그 설계가 꽤 실용적이라는 것도 알게 됩니다. 워드프레스의 확장성은 훅(hook) 시스템에 기반합니다. 특정 시점에 코드를 실행하는 액션(action)과, 데이터가 출력되기 전에 값을 가공하는 필터(filter)를 통해 코어를 수정하지 않고도 거의 모든 동작을 바꿀 수 있습니다. 템플릿 계층 구조는 요청된 페이지의 종류에 따라 어떤 템플릿 파일을 사용할지를 규칙적으로 결정하므로, 파일 이름만으로도 페이지별 화면을 쉽게 분리할 수 있습니다. WP_Query로 원하는 조건의 글을 조회하고, 내장된 REST API를 통해 콘텐츠를 외부에 제공할 수도 있습니다. 흥미로운 점은 워드프레스의 블록 에디터 일부는 리액트로 만들어졌다는 사실입니다. 글을 작성하는 편집 화면처럼 상호작용이 복잡한 영역에는 리액트를 쓰고, 방문자에게 보여지는 페이지는 서버에서 PHP가 완성된 HTML로 렌더링합니다. 워드프레스에서는 기본적으로 서버에서 HTML을 만들지만, 필요한 블록이나 기능에 따라서는 클라이언트단에서 자바스크립트를 추가할 수 있는데, 저는 이것이 도구를 적재적소에 배치한 좋은 사례라고 생각합니다. 블로그처럼 콘텐츠가 중심인 사이트에서 이 구조는 매우 자연스럽습니다. 글을 발행하면 서버가 완성된 HTML을 응답하고, 검색엔진은 그 문서를 그대로 읽습니다. 검색엔진으로 하여금 본문을 보게 하기 위해 CSR이니 SSR이니 하는 전략을 따로 고민할 필요가 없습니다. 제가 리액트와 Next.js로 먼 길을 돌아 도달하려 했던 결과를, 워드프레스는 처음부터 기본 동작으로 제공하고 있었습니다. PHP는 레거시가 아니다 많은 웹 프런트엔드 개발자들이 PHP를 레거시 기술로 치부하지만, 실제로 지금 이렇게 저렇게 php를 만져보면서, 저는 이러한 평가에 쉽게 동의할 수 없다는 생각이 듭니다. 아마 php가 레거시라는 인식의 상당 부분은 PHP 5 시절, HTML과 SQL과 로직이 한 파일에 뒤섞인 코드와 잦은 보안 사고의 기억에서 비롯된 것이 아닐까 생각합니다. 현재의 PHP는 과거의 PHP와는 많이 다릅니다. PHP 7에서 엔진이 재설계되며 성능이 크게 향상되었고, PHP 8에서는 JIT(just-in-time) 컴파일러, 유니언 타입, match 표현식, 네임드 인수, 어트리뷰트가 도입되었습니다. 이후 버전에서도 열거형(enum), readonly 속성, 파이버(Fiber) 등이 추가되며 언어는 꾸준히 현대화되었습니다. 엄격한 타입 선언을 활용하면 정적 분석 도구와 함께 상당히 견고한 코드를 작성할 수 있고, Composer를 중심으로 한 패키지 생태계와 Laravel, Symfony 같은 프레임워크도 성숙해 있습니다. 무엇보다 전통적인 PHP-FPM 기반 웹 애플리케이션에서는 애플리케이션의 사용자 영역 상태가 기본적으로 요청 단위의 생명주기를 가진다는 장점이 있습니다. 요청 처리가 끝나면 다음 요청은 다시 초기화된 상태에서 시작하므로, 애플리케이션 프로세스에 상태를 오래 보관하는 서버와 비교하면 요청 간 상태 공유에 대해 신경 써야 할 지점이 적습니다. 물론 FPM worker 자체는 여러 요청에 걸쳐 재사용되고, OPcache나 persistent connection처럼 요청을 넘어 유지되는 상태도 있습니다. 최근의 FrankenPHP나 Swoole 같은 long-running PHP 런타임에서는 이 전제가 달라지기도 합니다. 하지만 전통적인 PHP 배포에서는 언어 자체가 필수적인 애플리케이션 빌드 단계를 요구하지 않기 때문에, 단순히 소스 코드를 배포하는 것만으로도 프로덕션 런타임 실행이 가능합니다. 저는 이것을 낡은 방식이 아니라 그저 단순한 방식이라고 부르고 싶습니다. 물론 워드프레스를 쓴다고 모든 것이 해결되는 것은 아닙니다. 워드프레스 생태계에서 공개되는 취약점의 상당수는 코어 자체보다 서드파티 플러그인과 테마에서 발견됩니다. 플러그인을 무분별하게 설치하면 성능 저하와 보안 위험이 함께 커지므로, 필요한 것만 신중하게 고르고 꾸준히 업데이트하는 관리가 필요합니다. 다만 이는 자바스크립트 또는 타입스크립트를 사용하면서 npm 의존성을 꾸준히 관리하는 것과도 비슷한 문제라고 저는 생각합니다. 어떤 생태계든, 외부 코드를 가져다 쓰는 순간 그에 따른 책임은 따라오기 마련입니다. 도구는 문제에 맞춰 고른다 다시 강조하지만, 저는 리액트를 쓰지 말자고 주장하는 것이 아닙니다. 상태가 복잡하게 얽힌 대시보드, 여러 사용자가 실시간으로 협업하는 도구, 화면 전환 없이 끊임없이 상호작용하는 웹 애플리케이션이라면 리액트는 여전히 훌륭한 선택입니다. 워드프레스의 에디터 일부가 리액트로 만들어진 것처럼, 리액트가 빛나는 자리는 분명히 존재합니다. 제가 말하고 싶은 것은, 그저, 도구는 문제에 맞춰 골라야 하며, 도구에 문제를 맞춰서는 안 된다는 것. 콘텐츠 중심의 블로그라면 워드프레스가 가장 합리적인 선택일 수 있습니다. 한두 페이지짜리 정적 사이트라면 HTML과 CSS, 약간의 자바스크립트로 충분합니다. 콘텐츠 사이트에 부분적인 상호작용이 필요하다면 Astro나 htmx 같은 선택지를 고려할 수 있습니다. 복잡한 웹 애플리케이션이라면 그때 리액트를 꺼내면 됩니다. 이 판단을 제대로 내리려면 여러 도구를 알아야 하고, 각각의 도구를 편견 없이 평가할 수 있어야 합니다. 리액트로 실무를 해본 경험이 있었기에 저는 지금 워드프레스와 PHP의 장점을 더 선명하게 볼 수 있습니다. 반대로 워드프레스와 PHP를 경험하면서, 리액트가 정말로 필요한 순간이 언제인지도 더 분명해졌습니다. 어느 한쪽을 버릴 필요는 없습니다. 각자의 자리에 두면 됩니다. "요즘 누가 그걸 써요"라는 말보다 "이 문제에는 무엇이 맞을까요"라는 질문이 더 자주 오가는 개발 문화를 바랍니다. 기술을 고르는 기준은 유행이 아닌 우리가 해결해야 할 문제 그 자체이기를 바라는 마음입니다.