923 posts
NvChad로 NeoVim을 IDE처럼 꾸미기

NvChad로 NeoVim을 IDE처럼 꾸미기

NeoVim을 설치하고 기본적인 모달 편집에 익숙해졌는데, 막상 매일 쓰려니 뭔가 허전하지 않으셨나요? NeoVim 입문 가이드에서 다뤘듯이 플러그인을 하나씩 추가하면 IDE급 환경을 만들 수 있긴 한데, 그 "하나씩"이 문제입니다. 컬러 스킴 고르고, 상태바 설정하고, LSP 연결하고, 자동 완성 붙이고... 코딩은 안 하고 에디터 설정만 이틀째 하고 있는 자신을 발견하게 되죠. 😅 NvChad는 이 문제를 정면으로 해결합니다. 설치 한 줄이면 예쁜 UI에 빠른 시작 속도, 실용적인 플러그인 구성까지 한 번에 갖춰지거든요. 이

Tower Layer 직접 만들기: 커스텀 미들웨어 작성 가이드

Tower Layer 직접 만들기: 커스텀 미들웨어 작성 가이드

Tower 미들웨어 실전에서 본 빌트인 미들웨어로 대부분의 자리는 커버되지만, 가끔은 직접 만들어야 하는 순간이 옵니다. 사내 인증 토큰 검증, 도메인 특화 메트릭 수집, 비표준 헤더 처리 같은 자리죠. 이번 글에서는 Tower의 Service와 Layer를 직접 구현해서 미들웨어를 작성하는 방법을 정리해보겠습니다. 비동기 future를 직접 만드는 패턴까지 포함해서요. 입문 개념은 Tower 입문에서 다뤘으니, 이 글은 그 위에서 한 단계 깊이 들어가는 내용입니다. 만약 Future의 poll, Waker, Pin 같은 단어가 아

AdSense 자동 광고 형식 제대로 알고 쓰기

AdSense 자동 광고 형식 제대로 알고 쓰기

블로그를 몇 년 굴리다 보면 광고를 한번 붙여볼까 하는 생각이 들죠. 저도 그렇게 AdSense를 시작했습니다. 사이트에 코드 한 줄만 넣으면 된다기에 넣었더니 정말로 광고가 뜨더라고요. 여기까지는 쉬웠습니다. 이상했던 건 그다음이었습니다. 저는 광고 자리를 정한 적이 없는데 글 중간중간에 광고가 끼어들고, 화면 구석에도 붙고, 페이지를 넘길 때는 화면 전체를 덮기까지 하더라고요. 어느 날 아침에는 제 블로그 로고와 메뉴가 통째로 광고에 가려져 있었습니다. 😅 조절할 방법이 있겠거니 하고 설정 화면을 열어봤는데, 이번엔 처음 보는

GraphQL 명세 ⑦: 결과를 담아 돌려주는 응답(Response)

GraphQL 명세 ⑦: 결과를 담아 돌려주는 응답(Response)

지난 편에서 쿼리가 실행되어 데이터가 채워지는 과정까지 따라왔는데요. 이제 그 결과를 클라이언트에게 어떤 모양으로 돌려줄지를 정하는 마지막 단계, 명세 제7장 응답(Response) 차례입니다. 우리가 GraphQL을 쓸 때마다 마주하는 그 { "data": ... } JSON이 왜 항상 그렇게 생겼는지, 에러는 왜 별도의 배열로 따로 담기는지가 이번 편에서 분명해집니다. 응답은 명세에서 가장 짧은 장에 속하지만, 클라이언트 코드를 작성할 때 매일 부딪히는 부분이라 정확히 알아두면 두고두고 도움이 됩니다. 응답의 최상위에는 세 개의

Rhai 입문: Rust 앱에 임베디드 스크립트 박아 넣기

Rhai 입문: Rust 앱에 임베디드 스크립트 박아 넣기

Rust로 서비스를 짜다 보면 가끔 이런 욕심이 생깁니다. "이 분기 로직을 코드 변경 없이 운영자가 살짝 바꿀 수 있으면 좋을 텐데", "고객사마다 다른 헤더 변환 규칙을 그때그때 다른 바이너리로 빌드하긴 너무 무거운데"처럼요. 이런 상황을 위한 도구가 바로 임베디드 스크립트 엔진입니다. 이번 글에서는 Rust 생태계에서 자주 쓰이는 Rhai 스크립트 엔진을 소개합니다. 호스트 Rust 코드에 박아 넣는 방법부터 Rhai 자체 문법까지 한 번에 살펴보겠습니다. 임베디드 스크립트가 필요한 순간 서비스 본체는 Rust로 단단하게 컴파

Axum으로 REST API 서버 만들기: 라우팅, 추출자, 상태 관리

Axum으로 REST API 서버 만들기: 라우팅, 추출자, 상태 관리

Rust로 HTTP 서버를 짜다 보면 프레임워크 선택에서 한 번씩 막힙니다. actix-web은 성능이 검증됐지만 액터 모델이 낯설고, warp는 함수형 스타일이 깔끔한데 타입 에러가 미로처럼 느껴질 때가 있습니다. Axum은 Tokio 팀이 만든 웹 프레임워크입니다. "Tower 위의 얇은 라우팅 레이어"를 표방하는데, 이게 생각보다 실용적입니다. 타임아웃이나 인증 미들웨어를 Tower로 짜두면 Axum에 그대로 끼울 수 있고, 핸들러 함수 시그니처에 타입만 선언해두면 Axum이 요청에서 필요한 데이터를 알아서 꺼내줍니다. 이 글

LazyVim: 설정 없이 바로 쓰는 NeoVim

LazyVim: 설정 없이 바로 쓰는 NeoVim

NeoVim을 쓰기로 마음먹고 설정을 시작하면 끝이 안 보입니다. 플러그인 매니저를 고르고, LSP를 연결하고, 자동 완성을 붙이고, 컬러 스킴을 깔고, 상태바를 예쁘게 꾸미고... 코딩은 안 하고 에디터 설정만 사흘째 하고 있는 자신을 발견하게 되죠. 😅 NvChad처럼 미리 짜인 설정 프레임워크를 쓰면 이 문제가 줄어들긴 합니다. 그런데 NvChad는 프레임워크 자체의 구조를 따라야 하는 제약이 있어서 뭔가 바꾸고 싶을 때 NvChad의 동작 방식을 먼저 이해해야 하는 경우가 종종 생깁니다. LazyVim은 이 사이 어딘가를

Rust tokio::io::duplex: 실제 소켓 없이 비동기 I/O 코드 테스트하기

Rust tokio::io::duplex: 실제 소켓 없이 비동기 I/O 코드 테스트하기

Tokio로 TCP 에코 서버 같은 네트워크 코드를 짜고 나면 한 가지 고민이 생깁니다. 이걸 어떻게 테스트하지? 보통은 테스트 안에서 진짜 TcpListener로 포트를 열고, 클라이언트로 접속해서 데이터를 주고받습니다. 그런데 이 방식은 포트가 겹치면 충돌하고, 테스트를 병렬로 돌리기 까다롭고, 운영체제의 네트워크 스택을 거치느라 은근히 느립니다. 😮‍💨 그래서 Tokio는 tokio::io::duplex라는 도구를 제공합니다. 메모리 위에 소켓처럼 동작하는 양방향 파이프를 만들어주는데요. 실제 네트워크 없이도 "쓰면 반대편

GraphQL 명세 ⑥: 쿼리가 데이터로 채워지는 실행(Execution)

GraphQL 명세 ⑥: 쿼리가 데이터로 채워지는 실행(Execution)

지난 편에서 검증을 통과한 쿼리는 이제 실제로 데이터를 채워 넣을 준비가 됐습니다. 그 일을 다루는 것이 명세 제6장 실행(Execution) 인데요. GraphQL 명세에서 가장 흥미로운 동작들이 바로 이 장에 숨어 있습니다. 특히 "왜 필드 하나가 실패했는데 부모 객체까지 통째로 null이 되지?" 같은, 실무에서 한 번쯤 당황했을 동작의 정체가 여기서 밝혀집니다. 이번 편에서는 서버가 쿼리를 어떻게 한 필드씩 실행하는지, query와 mutation의 실행 순서가 왜 다른지, 그리고 에러가 났을 때 null이 어떻게 번지는지를

Tauri로 가벼운 데스크톱 앱 만들기

Tauri로 가벼운 데스크톱 앱 만들기

웹 개발자라면 한 번쯤 "내가 만든 웹 앱을 데스크톱 앱으로 배포할 수 있으면 좋겠다"고 생각해 보신 적 있을 겁니다. Electron이 이 영역을 오랫동안 지배해 왔지만, 앱 하나에 Chromium 전체를 번들하다 보니 설치 파일이 100MB를 넘어가는 건 일상이었죠 😅 Tauri는 이 문제를 풀려고 만들어진 프레임워크입니다. 프론트엔드는 기존 웹 기술을 그대로 쓰되 백엔드를 Rust로 작성하고, OS의 네이티브 웹뷰를 활용해서 앱 크기를 수 MB 수준으로 줄여 줘요. 이번 글에서는 Tauri 2로 데스크톱 앱을 처음부터 만들어

Rust Tower 미들웨어 실전: 타임아웃, 재시도, 레이트 리미트

Rust Tower 미들웨어 실전: 타임아웃, 재시도, 레이트 리미트

Tower 입문에서 Service/Layer/ServiceBuilder를 둘러봤다면, 이번에는 Tower가 기본으로 제공하는 미들웨어를 실무 시나리오에 맞춰 끼워보겠습니다. 외부 API를 호출하는 서비스나 가용성 보장이 필요한 게이트웨이를 만든다고 가정하면 거의 다 이 안에서 해결됩니다. 이 글에서 다루는 미들웨어는 모두 tower 크레이트의 기본 기능에 들어 있어서, Cargo.toml에 다음만 추가하면 시작할 수 있습니다. 타임아웃: 응답 시간 제한 가장 자주 쓰이는 미들웨어가 타임아웃입니다. "이 호출은 N초 안에 끝나야 한다

Cloudflare Email Routing으로 커스텀 이메일 주소 만들기

Cloudflare Email Routing으로 커스텀 이메일 주소 만들기

나만의 도메인을 가지고 있다면 한 번쯤 hello@mydomain.com 같은 이메일 주소를 만들어보고 싶지 않으셨나요? 브랜드 이메일 주소가 있으면 신뢰감을 줄 수 있고, 용도별로 주소를 나눠서 쓸 수도 있어서 여러모로 유용하거든요. 그런데 이메일 서비스를 직접 운영하는 건 서버 관리부터 보안까지 신경 쓸 게 너무 많습니다. Google Workspace 같은 유료 서비스를 쓰자니 개인 프로젝트나 소규모 사이트에는 부담이 되고요. Cloudflare Email Routing은 이런 고민을 깔끔하게 해결해줍니다. 도메인에 커스텀 이

Rust tokio::time::timeout: 비동기 작업에 시간 제한 걸기

Rust tokio::time::timeout: 비동기 작업에 시간 제한 걸기

비동기 코드를 짜다 보면 외부에 의존하는 작업을 마주하게 됩니다. 외부 API 호출, 데이터베이스 쿼리, 다른 서비스로의 gRPC 요청 같은 것들이죠. 이런 작업은 대부분 빠르게 끝나지만, 상대방이 느려지거나 응답을 아예 안 주면 우리 코드는 그 자리에서 하염없이 기다리게 됩니다. 이럴 때 필요한 게 시간 제한입니다. "이 작업은 3초 안에 끝나야 하고, 안 끝나면 포기한다"는 약속을 거는 거죠. Tokio는 이를 위해 tokio::time::timeout 함수를 제공합니다. 이번 글에서는 이 함수의 기본 사용법부터, 한 가지 짚고

Claude Artifacts: 대화만으로 앱을 만드는 경험

Claude Artifacts: 대화만으로 앱을 만드는 경험

"이거 간단한 계산기 하나만 만들어줘." Claude에게 이렇게 말했을 뿐인데, 화면 오른쪽에 진짜 동작하는 계산기가 나타났습니다. 버튼을 누르면 숫자가 입력되고, 사칙연산도 되고, C 버튼을 누르면 초기화까지 됩니다. 코드를 한 줄도 작성하지 않았는데 말이죠 🤔 이게 바로 Claude의 Artifacts 기능입니다. 그냥 대화를 나누면서 "이런 거 만들어줘"라고 하면 Claude가 실시간으로 코드를 생성하고 바로 실행 가능한 결과물을 보여줍니다. 이 글에서는 Artifacts가 정확히 무엇인지, 어떤 것들을 만들 수 있는지, 그

GraphQL 명세 ⑤: 실행 전에 쿼리를 거르는 검증(Validation)

GraphQL 명세 ⑤: 실행 전에 쿼리를 거르는 검증(Validation)

GraphiQL에서 존재하지 않는 필드를 입력하면, 실행하기도 전에 빨간 밑줄이 그어지면서 "그런 필드는 없다"고 알려주는 걸 보셨을 텐데요. 서버에 요청을 보내지도 않았는데 어떻게 틀렸다는 걸 알았을까요? 바로 GraphQL이 쿼리를 실행하기 전에 한 단계를 더 거치기 때문입니다. 그 단계가 이번 편의 주제인 검증(Validation) 입니다. 지난 편에서 본 인트로스펙션으로 스키마 정보를 손에 쥐면, 어떤 쿼리가 그 스키마에 맞는지 안 맞는지를 실행 없이도 판단할 수 있습니다. 명세 제5장은 바로 이 "맞는 쿼리"의 조건을 규칙

Rust Tower 입문: Service 트레이트와 Layer로 미들웨어 합성하기

Rust Tower 입문: Service 트레이트와 Layer로 미들웨어 합성하기

Rust로 HTTP 서버를 짜다 보면 신기한 일이 벌어지는데요. Hyper, Axum, Tonic 같은 프레임워크가 다 다르게 생겼는데, 한 번 만든 미들웨어를 그 사이에 그대로 옮겨 써도 작동합니다. 비밀은 이들이 공유하는 한 가지 추상화에 있는데요. 바로 Tower입니다. 이번 글에서는 Tower의 두 핵심 트레이트인 Service와 Layer를 살펴보고, ServiceBuilder로 미들웨어를 깔끔하게 합성하는 방법까지 정리해보겠습니다. 빌트인 미들웨어 활용은 Tower 미들웨어 실전에서, 직접 미들웨어를 만드는 방법은 Tow

Rust 기초: Cow로 불필요한 복사 줄이기

Rust 기초: Cow로 불필요한 복사 줄이기

문자열을 정규화하는 함수를 만든다고 해볼게요. 공백을 다듬고 소문자로 바꾸는 작업이 필요한데, 입력이 이미 깔끔할 수도 있습니다. 간단하죠. 그런데 한 가지 찜찜한 점이 있습니다. 입력이 이미 정규화된 상태라면 어떻게 될까요? 아무 변화도 없는데 to_lowercase()가 호출되는 순간 새로운 String이 힙에 할당됩니다. 초당 수백만 번 호출되는 코드라면 이 낭비가 꽤 아프게 다가오죠. "변경이 필요할 때만 복사하고, 그 외엔 빌린 채로 쓰자"는 아이디어를 타입으로 표현한 게 바로 Cow<'a, B>입니다. 이 글에서는 Cow

Rust anyhow 크레이트: 애플리케이션 에러를 간편하게 처리하기

Rust anyhow 크레이트: 애플리케이션 에러를 간편하게 처리하기

Rust 에러 처리를 다루면서 라이브러리용 에러 타입을 깔끔하게 정의하는 thiserror는 살펴봤는데요. 정작 그 단짝인 anyhow는 아직 다루지 않았습니다. 둘은 보통 한 쌍으로 거론되지만 역할이 정반대거든요. 애플리케이션 코드를 짜다 보면 함수 하나에서 파일도 읽고, 문자열도 파싱하고, 네트워크도 호출합니다. 그러면 std::io::Error, ParseIntError 등 종류가 다른 에러가 마구 쏟아지는데요. 이걸 일일이 enum으로 묶어 정의하는 건 과합니다. 어차피 최종적으로는 "어디서 왜 실패했는지" 로그를 남기고 프

GraphQL 명세 ④: 스키마가 자기 자신을 설명하는 인트로스펙션(Introspection)

GraphQL 명세 ④: 스키마가 자기 자신을 설명하는 인트로스펙션(Introspection)

GraphiQL이나 Apollo Studio 같은 도구를 써보셨다면, 필드 이름을 한 글자만 입력해도 가능한 필드 목록이 주르륵 뜨는 경험을 하셨을 텐데요. 신기하게도 도구는 우리가 쓰는 서버의 스키마를 미리 다 알고 있는 것처럼 동작합니다. 누가 그 정보를 알려준 걸까요? 답은 GraphQL 서버 자신입니다. GraphQL 스키마는 자기 자신에 대한 정보를 GraphQL 쿼리로 되물을 수 있도록 설계되어 있는데요. 이 능력을 인트로스펙션(Introspection) 이라고 부르고, 명세 제4장이 이걸 다룹니다. 지난 편에서 본 타입

AI가 바꿔버린 웹의 질서, Cloudflare가 던진 균형의 해법

AI가 바꿔버린 웹의 질서, Cloudflare가 던진 균형의 해법

최근 몇 년 사이, AI 모델 학습을 위한 대규모 웹 스크래핑이 보편화되면서 인터넷의 오랜 질서가 흔들리고 있습니다. 오랫동안 웹에는 창작자와 사용자 간에 암묵적인 상생 체계가 존재했습니다. 창작자는 콘텐츠를 무료로 공개함으로써 트래픽과 인용이라는 형태의 보상을 받았고, 사용자는 타인의 콘텐츠를 사용할 때 출처를 남기며 인정과 감사를 표했습니다. 이러한 관행은 단순한 예의 차원을 넘어, 웹의 성장 동력이자 지식 공유의 선순환 구조를 가능하게 했습니다. MIT나 Creative Commons 라이선스가 출처 표시(attribution

Discord