Profile img

자손킴

@jasonkim@hackers.pub · 13 following · 31 followers

자손킴 shared the below article:

성공적인 AI 에이전트 시스템을 만들려면

Seo Sanghyeon @sanxiyn@hackers.pub

AI 에이전트 시스템을 구축하며 얻은 실전 경험을 바탕으로 효율적인 설계와 운영 전략을 심도 있게 다룹니다. 성공적인 에이전트를 위해 목표는 측정 가능하고 유용하며 달성 가능한 범위로 좁혀야 하며, 로그 인프라 구축과 정교한 평가 설계(evaluation design)를 통해 지속적인 개선의 토대를 마련하는 것이 필수적입니다. 특히 도메인 특화 지식을 스킬(skill) 형태로 패키징하여 모델의 추론 능력을 극대화하고, 프롬프트 캐싱과 적절한 모델 선택으로 비용 효율성을 확보하는 방법론을 제시합니다. 구체적인 구현 단계에서는 컨텍스트 윈도(context window) 관리를 위한 멀티 에이전트 구조와 서브 에이전트의 실행 제어 기법을 살펴봅니다. 또한 복잡한 도구 호출 대신 모델이 직접 코드를 생성하고 실행하게 함으로써 토큰 사용량을 혁신적으로 줄이는 코드 생성(code generation) 패턴의 효용성을 강조합니다. 이와 더불어 신뢰할 수 있는 파일 편집 방식과 샌드박스 기반의 강력한 인가 제어(authorization) 시스템 구축은 안전한 자율 시스템을 위한 핵심 요소로 작용합니다. 이 글은 빠르게 진화하는 AI 에이전트 분야에서 기술적 정확성과 실용성을 겸비한 아키텍처를 설계하려는 개발자들에게 구체적이고 실질적인 인사이트를 제공합니다.

Read more →
12
0
0

도커로 구축한 랩에서 혼자 실습하며 배우는 네트워크 프로토콜 입문 #5-4 SSL 오프로드

자손킴 @jasonkim@hackers.pub

TLS(SSL) 오프로드는 웹서버의 CPU 자원을 소모하는 암복호화 작업을 로드밸런서(Load Balancer)와 같은 전용 장비에 위임하여 애플리케이션의 처리 효율을 극대화하는 기술입니다. 중앙집중식 인증서 관리를 통해 운영 부담을 줄이는 장점이 있지만, 로드밸런서 통과 후 내부망에서 데이터가 평문으로 전달되는 보안 취약점이 발생할 수 있습니다. 특히 내부망이 항상 안전하다는 고정관념을 깨고 '결코 신뢰하지 말고 항상 검증하라'는 제로 트러스트(Zero Trust) 원칙에 따라, 상호 TLS(mTLS)를 활용한 마이크로 세그멘테이션의 중요성이 대두되고 있습니다. 하지만 L7 로드밸런서나 웹 애플리케이션 방화벽(WAF)이 HTTP 헤더와 경로를 분석하여 정교한 라우팅과 공격 탐지를 수행하려면 패킷의 내용을 확인할 수 있는 TLS 종료 과정이 여전히 필수적입니다. 이 포스팅은 성능을 위한 오프로드와 보안을 위한 재암호화 사이의 기술적 접점을 설명하며, 가시성과 안전성을 동시에 확보해야 하는 현대적인 네트워크 인프라 설계의 핵심적인 인사이트를 제공합니다.

Read more →
1

도커로 구축한 랩에서 혼자 실습하며 배우는 네트워크 프로토콜 입문 #5-3 DHCP

자손킴 @jasonkim@hackers.pub

DHCP(Dynamic Host Configuration Protocol)는 IP 주소와 서브넷 마스크 등 네트워크 접속에 필수적인 설정을 자동으로 배포하여 관리 효율성을 극대화하는 핵심 프로토콜입니다. 이 글은 수동으로 관리하는 정적 할당과 자동화된 동적 할당의 차이점을 비교하며, UDP 기반의 메시지 구조와 Discover부터 ACK로 이어지는 네 단계의 처리 과정을 상세히 다룹니다. 특히 할당받은 주소를 유지하기 위한 임대 시간(Lease Time) 관리와 갱신 메커니즘을 통해 네트워크 안정성이 어떻게 유지되는지 설명합니다. 또한 단순한 주소 할당을 넘어 옵션 필드를 활용한 네트워크 부팅(PXE) 기술을 소개하며, DHCP가 현대 인프라 자동화의 강력한 기반이 되는 과정을 보여줍니다. 이 포스팅은 네트워크의 기본 동작 원리부터 실무적인 확장성까지 폭넓은 인사이트를 제공하여 기술적 이해도를 한 단계 높여줄 것입니다.

Read more →
1

도커로 구축한 랩에서 혼자 실습하며 배우는 네트워크 프로토콜 입문 #5-2 DNS

자손킴 @jasonkim@hackers.pub

도메인 이름 시스템(DNS)은 숫자로 이루어진 IP 주소를 사람이 기억하기 쉬운 문자로 변환해주는 인터넷의 핵심 인프라입니다. 초기 아파넷(ARPANET)의 중앙 집중식 관리 방식에서 벗어나 계층적 트리 구조의 분산 데이터베이스로 발전한 DNS는 전 세계 네임서버들의 유기적인 협력을 통해 동작합니다. 사용자의 요청을 처리하는 스터브 리졸버(Stub Resolver)부터 최종 답변을 가진 권한 있는 네임서버까지, 재귀 쿼리와 반복 쿼리를 교차 활용하여 효율적인 이름 풀이를 수행합니다. 특히 도메인을 IP에 직접 매핑하는 A 레코드와 별칭을 부여하는 CNAME 레코드의 차이를 이해하면 유연한 네트워크 인프라 운영이 가능해집니다. 최근에는 평문 통신의 보안 취약점을 해결하기 위해 DNS over TLS(DoT)와 DNS over HTTPS(DoH) 같은 암호화 기술이 도입되었으며, 접속 대상의 노출을 막는 ECH 기술까지 등장하며 사용자 프라이버시 보호가 한층 강화되었습니다. 이 글은 복잡한 DNS의 내부 동작 원리와 최신 보안 프로토콜의 진화 과정을 상세히 다루며 현대 네트워크 시스템의 근간을 파악하는 데 필수적인 통찰을 제공합니다.

Read more →
2

Agent Skill도 Tool Use로 시작합니다.

자손킴 @jasonkim@hackers.pub

Anthropic(앤스로픽)이 공개한 Agent Skill은 에이전트가 특정 업무를 수행할 때 필요한 절차적 지식과 맥락을 효율적으로 전달하기 위한 오픈 스탠다드입니다. 이 기능은 작업 지시문과 스크립트, 리소스를 재사용 가능한 단위로 패키징하여 대규모 언어 모델이 겪는 컨텍스트 낭비와 일관성 저하 문제를 해결합니다. 핵심 원리인 점진적 공개(progressive disclosure)를 통해 초기에는 메타데이터만 로드하고, 필요할 때만 상세한 SKILL.md 파일과 리소스를 동적으로 호출하여 효율적인 컨텍스트 관리를 구현합니다. 실제 dev-browser Skill의 동작 과정을 보면, 에이전트가 지시문을 해석하여 실시간으로 코드를 생성하고 도구를 체이닝하는 구체적인 메커니즘을 확인할 수 있습니다. 또한 컨텍스트 분리를 목적으로 하는 서브에이전트(subagent)나 외부 시스템 연동을 위한 모델 컨텍스트 프로토콜(Model Context Protocol, MCP)과의 비교를 통해 각 기술의 고유한 역할을 명확히 구분합니다. 단순히 도구를 제공하는 수준을 넘어 도구의 올바른 사용법을 가르치는 Agent Skill은 에이전트의 실행 능력을 최적화하고 지능적인 업무 자동화를 완성하는 핵심적인 메타 도구입니다.

Read more →
7

MCP도 Tool Use를 사용합니다.

자손킴 @jasonkim@hackers.pub

MCP(Model Context Protocol)가 도구 사용(Tool Use) 메커니즘과 어떻게 결합하여 에이전트의 역량을 확장하는지 내장 도구인 서브에이전트(Subagent) 예시와 함께 심층적으로 다룹니다. LLM 입장에서는 내장 도구와 MCP 도구가 동일한 인터페이스로 인식되지만, 실제로는 실행 주체와 프로세스 경계에 따른 통신 방식에서 차이가 발생함을 설명합니다. 특히 다양한 외부 시스템을 유연하게 통합하기 위해 도입된 네이밍 규칙과 실행 흐름을 분석하며, 도구의 제공자와 사용자를 분리하는 MCP 아키텍처의 구조적 이점을 강조합니다. 또한 단순한 기능 호출을 넘어 데이터베이스 스키마와 같은 정적 정보를 제공하는 리소스(Resources), 재사용 가능한 프롬프트(Prompts), 그리고 서버가 역으로 LLM의 판단을 요청하는 샘플링(Sampling) 등 도구 사용 이상의 고급 기능들을 소개합니다. 이 글은 MCP가 기술적으로 어떻게 도구 사용을 확장하는지 명확히 규명하며, 클라우드 및 로컬 환경의 다양한 도구를 연결하여 강력한 AI 생태계를 구축하려는 이들에게 중요한 이정표를 제시합니다.

Read more →
4
1
0

스마일 PRO 라식 수술 후기

자손킴 @jasonkim@hackers.pub

오랫동안 안경 생활에 익숙해져 시력 교정의 필요성을 느끼지 못하던 저자가 스쿠버 다이빙 중 겪은 불편함을 계기로 스마일PRO(SMILE Pro) 수술을 결심하고 진행한 상세한 과정을 다룹니다. 정밀 검사를 통해 각막 두께와 안압의 정상 상태를 확인하고, 노안(presbyopia) 발생 가능성을 고려하여 교정 시력을 미세하게 조정하는 상담 과정을 거쳤습니다. 수술 과정에서 레이저 조사(laser irradiation) 시 초록색 불빛에 시선을 고정하는 기술적 고충과 개인별 안구 각도에 따른 정렬 최적화의 중요성을 생생하게 묘사합니다. 수술 직후 발생하는 일시적인 눈시림과 이물감을 극복하며 시력이 점진적으로 회복되는 단계별 변화를 기록하고 있으며, 철저한 사후 관리와 안약 투여의 필요성을 강조합니다. 이 글은 시력 교정술을 고민하는 이들에게 수술 당일의 긴장감 넘치는 진행 과정과 실제 회복 단계에서 얻을 수 있는 구체적인 인사이트를 제공하며 안경 없는 새로운 삶의 가치를 전달합니다.

Read more →
2

Subagent는 Tool Use입니다.

자손킴 @jasonkim@hackers.pub

Subagent는 Tool Use 메커니즘을 확장하여 특정 작업에 최적화된 독립적인 AI 에이전트를 운용하는 고도화된 방식입니다. 메인 에이전트가 'Task' 도구를 호출하면 전용 시스템 프롬프트와 제한된 도구 세트를 가진 새로운 메시지 루프가 생성되며, 각 Subagent는 자신의 독립적인 컨텍스트 내에서 전문화된 작업을 수행한 뒤 그 결과를 메인 에이전트에게 전달합니다. YAML 설정과 마크다운 본문으로 정의되는 Subagent는 탐색이나 설계 등 목적에 따라 가벼운 모델인 Haiku나 강력한 성능의 Opus를 취사선택할 수 있어 작업의 효율성을 극대화하며, 메인 대화의 컨텍스트가 불필요한 정보로 오염되는 것을 방지합니다. 비록 메인 대화 히스토리를 직접 공유하지는 않지만 CLAUDE.md와 같은 프로젝트 컨벤션을 자동으로 참조하여 일관성을 유지하며 복잡한 워크플로우를 자율적으로 해결합니다. 이러한 구조는 단순한 API 호출을 넘어 LLM이 또 다른 전문 LLM을 도구처럼 활용함으로써 AI 에이전트의 문제 해결 능력을 다각화하고 시스템의 확장성을 한 단계 높여주는 핵심적인 설계 패턴입니다.

Read more →
3

도커로 구축한 랩에서 혼자 실습하며 배우는 네트워크 프로토콜 입문 #5-1 TLS

자손킴 @jasonkim@hackers.pub

OSI 7계층 모델의 상위 계층이 현대 TCP/IP 모델에서 애플리케이션 계층으로 통합된 배경과 함께 네트워크 보안의 핵심인 TLS 프로토콜의 작동 원리를 깊이 있게 다룹니다. 도청, 변조, 스푸핑과 같은 보안 위협을 방어하기 위해 TLS가 사용하는 암호화, 해싱, 디지털 인증서 기술을 상세히 살펴보고, 특히 최신 표준인 TLS 1.3에서 성능과 보안성을 극대화한 X25519 키 교환과 Ed25519 디지털 서명 알고리즘의 메커니즘을 분석합니다. 대칭키 암호화의 키 전달 문제를 해결하는 과정부터 전방 비밀성(Forward Secrecy)의 중요성, 그리고 메시지 인증 코드(MAC)를 통한 데이터 무결성 보장까지 현대 암호학 기술이 어떻게 조화를 이루어 안전한 통신 채널을 구축하는지 명확하게 설명합니다. 이 글은 복잡한 보안 프로토콜의 내부 구조를 이해하고 더 안전한 애플리케이션을 설계하려는 개발자에게 실질적인 기술적 통찰을 제공합니다.

Read more →
6

Claude Code의 거의 모든 것은 Tool Use 입니다. MCP도 subagent도 Skills 역시요.

자손킴 @jasonkim@hackers.pub

Claude가 외부 도구를 호출하여 텍스트 생성 이상의 작업을 수행하는 도구 사용(Tool Use) 메커니즘을 상세히 다룹니다. 개발자가 도구의 이름, 설명, 입력 스키마(input schema)를 정의하면 Claude는 사용자 요청을 분석해 적절한 도구를 선택하고 필요한 파라미터와 함께 실행을 요청합니다. 이 과정에서 클라이언트인 에이전트는 모델의 응답을 파싱하여 실제 시스템 명령어나 함수를 실행한 뒤, 그 결과를 다시 모델에 전달하는 가교 역할을 수행합니다. 본문에서는 NestJS 프로젝트 분석 예시를 통해 Bash나 Glob 같은 도구가 어떻게 병렬로 요청되고 결과가 다시 피드백되는지 구체적인 API 대화 흐름을 보여줍니다. 특히 중단 사유(stop_reason)가 도구 사용으로 설정되는 과정과 실행 결과를 모델에 다시 알리는 구조를 이해하면 Claude Code나 MCP(Model Context Protocol) 기반의 확장 기능이 동작하는 핵심 원리를 명확히 파악할 수 있습니다. 이 글은 Claude를 단순한 대화형 AI를 넘어 실제 환경과 상호작용하는 능동적인 에이전트로 활용하려는 개발자에게 깊이 있는 기술적 통찰을 제공합니다.

Read more →
8

Claude API의 Request Body 분석

자손킴 @jasonkim@hackers.pub

Claude API를 효과적으로 활용하기 위해 반드시 이해해야 할 요청 본문(Request Body)의 네 가지 핵심 구성 요소를 살펴봅니다. 우선 시스템 메시지(System Messages)는 모델의 페르소나와 제약 사항을 정의하는 최상위 설정으로, 응답의 톤과 매너를 결정짓는 중추적인 역할을 수행합니다. 메시지(Messages) 배열은 사용자와 어시스턴트(assistant) 간의 대화 흐름을 관리하며, 특히 어시스턴트의 답변을 미리 작성하는 프리필(Prefill) 기법이나 도구 사용(tool_use) 및 결과(tool_result)를 주고받는 상호작용의 핵심이 됩니다. 여기에 제이슨 스키마(JSON Schema)를 기반으로 도구(Tools)를 정의하면 모델이 복잡한 작업을 수행하기 위해 필요한 기능을 스스로 판단하고 호출할 수 있게 됩니다. 마지막으로 모델 선택과 토큰 제한, 확장 사고(Extended Thinking) 예산 등을 조절하는 모델 및 구성(Model & Config) 옵션을 통해 API 동작의 세부 사항을 정교하게 제어할 수 있습니다. 이 네 가지 요소의 구조와 유기적인 연결 방식을 이해하면 Claude의 능력을 극대화하여 더욱 강력한 인공지능 애플리케이션을 설계할 수 있는 핵심적인 통찰을 얻게 될 것입니다.

Read more →
3

언제까지 (a:number, b:number) => a + b, (a:string, b:string) => a + b, <T>(a: T, b: T) => a + b 를 해줘야 하나고
그냥 대충 눈치껏 (a, b) => a + b 하면 'ba 와 더할 수 있어야 하는 타입이고 a 는 무언가와 더할 수 있는 타입이구나' 하고 추론할 수 있는 분석기가 달린 언어가 필요함

3

Claude Code가 모델이 하지도 않은 말을 했다고 하는 이유.

자손킴 @jasonkim@hackers.pub

Claude Code는 사용자의 첫 번째 요청을 처리할 때 대화 주제를 파악하고 제목을 생성하기 위해 '프리필(prefill)' 기법을 효과적으로 활용합니다. 이 기법은 API 요청의 마지막 메시지에서 어시스턴트(assistant)가 이미 응답을 시작한 것처럼 `{` 문자를 미리 제공하여, 모델이 자연스럽게 나머지 JSON 구조를 완성하도록 유도하는 방식입니다. 이는 단순히 특정 형식을 요구하는 지시보다 훨씬 강력하게 응답 형식을 강제할 수 있으며, JSON뿐만 아니라 특정 언어의 코드 블록이나 XML 등 다양한 정형 데이터를 생성할 때도 유용합니다. 인위적인 시작점 설정을 통해 모델의 출력을 정교하게 제어하는 이 전략은 안정적인 애플리케이션 개발을 위한 실무적인 프롬프트 엔지니어링(prompt engineering)의 핵심적인 사례를 보여줍니다.

Read more →
4

도커로 구축한 랩에서 혼자 실습하며 배우는 네트워크 프로토콜 입문 #4

자손킴 @jasonkim@hackers.pub

이 글은 네트워크 계층과 애플리케이션을 연결하는 L4 전송 계층의 핵심 개념을 소개합니다. 포트 번호를 통해 애플리케이션을 식별하고, UDP와 TCP 프로토콜의 특징과 패킷 형식을 설명합니다. UDP는 실시간성을, TCP는 신뢰성을 중시하며, TCP는 3-way handshake로 연결을 설정하고, 흐름 제어, 혼잡 제어, 재전송 제어를 통해 데이터 전송을 관리합니다. 특히 TCP 커넥션의 상태 전이 과정과 4-way handshake를 통한 연결 종료 과정을 상세히 다룹니다. 이 글을 통해 독자는 L4 전송 계층의 작동 방식과 TCP의 신뢰성 있는 데이터 전송 메커니즘에 대한 깊이 있는 이해를 얻을 수 있습니다.

Read more →
3

youknowone replied to the below article:

abab, asc, 123, abc

@disjukr@hackers.pub

흔히 사용되는 JavaScript의 배열 정렬 방식인 `arr.sort((a, b) => a - b)`는 코드를 읽는 개발자에게 혼란을 줄 수 있습니다. 이 글에서는 이러한 정렬 코드를 볼 때마다 오름차순인지 내림차순인지 확인해야 하는 번거로움을 줄이기 위해, 더 명확한 함수 이름을 사용할 것을 제안합니다. `sortAsc(arr)`와 같이 오름차순을 의미하는 함수명도 좋지만, `sort123(arr)` 또는 `sortAbc(arr)`처럼 정렬 방향을 직관적으로 나타내는 이름을 사용하면 코드의 가독성을 더욱 향상시킬 수 있습니다. 이처럼 명확한 이름은 코드를 이해하는 데 필요한 인지적 노력을 줄여주어, 개발 생산성 향상에 기여할 수 있다는 점을 강조합니다.

Read more →
7
3

도커로 구축한 랩에서 혼자 실습하며 배우는 네트워크 프로토콜 입문 #3-2

자손킴 @jasonkim@hackers.pub

이 글은 네트워크 라우팅의 기본 개념과 동작 방식, 그리고 NAT 기술에 대해 설명합니다. 라우팅은 IP 패킷이 목적지에 도달하기 위해 거쳐야 하는 경로를 결정하는 과정으로, 라우팅 테이블을 통해 넥스트 홉을 찾아 패킷을 전달합니다. 라우팅 방식에는 수동으로 설정하는 정적 라우팅과 라우터 간 정보 교환을 통해 자동으로 경로를 설정하는 동적 라우팅이 있습니다. 또한, NAT는 하나의 공인 IP 주소를 여러 장비가 공유할 수 있도록 IP 주소를 변환하는 기술로, 특히 NAPT는 IP 주소와 포트 번호를 함께 변환하여 효율적인 네트워크 사용을 가능하게 합니다. 이 글을 통해 독자는 네트워크 라우팅과 NAT의 핵심 원리를 이해하고, 실제 네트워크 환경에서 이들이 어떻게 활용되는지 파악할 수 있습니다.

Read more →
0

도커로 구축한 랩에서 혼자 실습하며 배우는 네트워크 프로토콜 입문 #3-1

자손킴 @jasonkim@hackers.pub

이 글은 네트워크 계층(L3) 프로토콜의 핵심인 IP에 대해 심도 있게 다룬다. L3 라우터의 역할부터 시작하여, IPv4의 구조, IP 단편화 과정, 그리고 PMTUD(Path MTU Discovery)의 중요성을 설명한다. IP 헤더의 각 필드(버전, 헤더 길이, ToS, 패킷 길이 등)에 대한 자세한 분석을 제공하며, IP 주소와 서브넷 마스크를 통해 네트워크와 호스트를 구분하는 방법을 설명한다. 클래스풀 주소 지정 방식과 클래스리스 주소 지정 방식의 차이점을 비교하고, 공인 IP 주소와 사설 IP 주소의 개념을 명확히 한다. 마지막으로, ICMP(Internet Control Message Protocol)를 통해 IP 레벨의 통신 상태를 확인하고 오류를 알리는 방법을 소개한다. 이 글을 통해 독자는 IP 프로토콜의 기본 원리를 이해하고, 네트워크 문제 해결 능력을 향상시킬 수 있을 것이다.

Read more →
4

도커로 구축한 랩에서 혼자 실습하며 배우는 네트워크 프로토콜 입문 #2

자손킴 @jasonkim@hackers.pub

이 글은 동일 네트워크 내 장비들이 L2 스위치를 통해 통신하는 방식에 대해 설명합니다. MAC 주소를 기반으로 통신하는 L2 계층은 통신 시작 시 IP 주소만 알고 MAC 주소를 모르는 상황을 해결하기 위해 ARP를 사용합니다. MAC 주소와 IP 주소의 역할, 이더넷 프레임 구조, 그리고 ARP의 동작 방식과 한계점을 상세히 다룹니다. 또한 L2 스위칭의 핵심인 MAC 주소 테이블과 flooding 과정을 설명하고, MAC 주소 중복 문제와 VLAN 기술을 소개합니다. 마지막으로, OVS 환경에서 VLAN 설정 시 vlan_mode와 tag의 의미를 명확히 구분하여 네트워크 구성에 대한 이해를 돕습니다.

Read more →
4

Ailrun (UTC-5/-4) replied to the below article:

공허한 참

박준규 @curry@hackers.pub

하스켈의 `all` 함수에 빈 리스트를 넣었을 때 왜 `True`가 반환되는지에 대한 의문을 "공허한 참(Vacuous truth)"이라는 개념을 통해 탐구합니다. 흔히 '구현이 그렇게 되어 있으니까'라고 생각할 수 있지만, 저자는 이 현상을 논리적으로 분석합니다. `all` 함수의 구현 방식과, 빈 리스트에 대한 연산 결과가 전체 결과에 미치는 영향을 설명하며, 공집합의 모든 원소가 짝수라는 명제가 참인 이유와 유사한 논리적 근거를 제시합니다. 이를 통해 코드와 수학 간의 연결고리를 발견하고, 마지막으로 ChatGPT가 생성한 유머러스한 이미지를 곁들여 독자에게 즐거움을 선사합니다.

Read more →
5

@curry박준규 all을 다음과 같이 정의하면 문제가 무엇일까요?

all p [] = False
all p [x] = p x
all p (x:xs) = p x && all xs

이 질문에 대한 대답 중 all의 의미에 관한 것이 있을 겁니다. 논리적으로 "모든 ...에 대해"를 어떻게 이해해야 하는냐에 대한 것 말이지요.

공집합을 직접 사용하는 것이 가장 간단한 예시겠지만, 좀 더 논리학에서 자주 사용되는 예시로는 "20세기의 모든 프랑스 왕은 대머리다"가 있겠습니다. 이는 무의미하게 (Vacuously) 참인데요, 왜냐면 19세기를 마지막으로 프랑스에는 더 이상 왕이 없기 때문이지요. 즉, 일반적으로 "모든 ...에 대해"에서 "..." 부분이 (결과적으로) 공집합일 경우 "모든 ..."에 의해 수식된 본문이 어떤 문장인지와는 상관 없이 참이라고 이해한다는 것이지요.

5

자손킴 shared the below article:

파서 콤비네이터: 하스켈 초보자를 위한 파싱

박준규 @curry@hackers.pub

이 글은 하스켈 초보자를 위한 파서 컴비네이터에 대한 입문 튜토리얼입니다. 파싱은 프로그래밍에서 흔히 발생하는 작업이지만, 정규 표현식이나 문자열 조작만으로는 복잡한 형식을 다루기 어렵습니다. 저자는 `Text.ParserCombinators.ReadP` 라이브러리를 사용하여 파서 컴비네이터를 소개하고, 이를 통해 더 읽기 쉽고 유지보수가 용이한 파서를 작성할 수 있음을 보여줍니다. METAR 보고서 파싱 예제를 통해 `satisfy`, `many1`, `<|>`, `option` 등의 기본적인 파서 콤비네이터 함수를 설명하고, 펑터와 모나드의 개념을 활용하여 파서를 구성하는 방법을 안내합니다. 또한, 파싱된 데이터의 유효성을 검사하고, 결과를 더 의미 있는 데이터 타입으로 변환하는 방법을 제시합니다. 이 튜토리얼을 통해 독자는 파서 컴비네이터의 기본 원리를 이해하고, 실제 데이터 파싱 작업에 적용할 수 있는 능력을 얻게 됩니다. 마지막으로, 저자는 독자들에게 배운 내용을 바탕으로 전체 METAR 보고서를 파싱하는 라이브러리를 만들어 Hackage에 제출해 볼 것을 권장하며, 파서가 없는 데이터를 만났을 때 `ReadP`를 자신 있게 사용할 수 있기를 바랍니다.

Read more →
11
4

stride 구현에 앞서 어떻게 동작하는건지 정리해봤다.

  • 모든 프로세스는 각자의 '보폭(stride)'을 가진다.
  • 스케쥴러가 프로세스를 실행시키면 해당 프로세스는 'stride'만큼의 '거리(pass)'를 이동한다.
  • 스케쥴러는 항상 가장 '짧은 거리를 이동한(pass가 가장 작은)' 프로세스를 실행시킨다.
  • 결과적으로 보폭이 작을수록 더 자주 실행된다.

몇가지 고려해야 할 것들이 떠올랐다.

  • stride로 바뀌면 lottery와는 달리 더 자주 실행되어야 할 프로세스에 작은 값을 부여해야한다. 사용자 입장에서 좋은 방식인가?
  • 신규 프로세스 실행 비율에 대한 공정성이 지켜지는지?
  • pass가 누적되면 overflow 될 가능성은 없나?
  • 가장 작은 pass를 찾는 효율적인 방법

그리고 다음과 같이 결정했다.

  • 우선순위를 정하는 API인 setticket은 그대로 유지하자.
  • tickets의 반비례되는 수인 stride를 만들기 위해 max_tickets(교재의 L)를 정한다.
    • stride = L / tickets
  • 신규 프로세스에는 현재 실행중인 프로세스중에서 가장 작은 pass를 부여하여 공정성을 유지한다.
  • pass를 uin64로 지정하고 max_tickets를 2^32로만 잡아도 최대 42.9억번 정도의 tick이 지나야 overflow가 발생한다. 지금은 고려하지 말자.
  • 초기 구현은 선형탐색으로 단순하게 구현하고 이후 최적화를 하자.
1

그동안 Conal이란걸 만들고 있었습니다. Classic FRP 라이브러리입니다.

또, 소개글 쓰려니까 머리 아파서, 클로드랑 즉석 팟캐스트를 열었습니다. 술술 읽혔으면 좋겠네요.

당장 프로덕션에 쓰려면 개선할 부분이 많습니다. 피드백과 기여 환영합니다.

8
8

스터디에 참여하고 계신 조교(?)님 께서 lottery scheduler 구현을 리뷰해주셨다. 혹시나 잘못 이해하고 구현한 부분이 있을까봐 걱정했는데, 리뷰해주신 덕분에 잘못된 부분은 없음을 확인했다. 더불어서 C로 코딩할때 유의해야 할 부분들을 배울 수 있었다.

0

lottery scheduler를 구현했다. 이어서 스케쥴러가 정해진 티켓 비율만큼 프로세스를 실행하는지 테스트하는 프로그램을 작성하기 위해 계획을 세웠다. 자식 프로세스의 pid를 알면 일정 주기마다 getpinfo를 호출하여 프로세스가 실행된 tick을 구해 계산 할 수 있을 것이다. 그런데 부모 프로세스가 자식의 pid를 알려면 어떻게 해야하지? 여기서 갑자기 혼란이 생겼다.

fork의 반환값은 0이면 자식이고 0보다 크면 부모이다. 0보다 작다면 실패이다. 이것을 사용하면 포크를 실행한 부모 프로세스인지 포크로 만들어진 자식 프로세스인지 알 수 있다.

내가 혼란스러웠던 부분은 코드를 작성하는 입장에서 fork의 호출은 한 번이지만 이후 실행은 2개로 갈라져서 반환 값이 2개가 된다는 사실을 정확히 인지하지 못해서였다. 부모인지 자식인지 판단하는 코드를 나눠서 생각하지 못하고 오로지 부모 입장에서만 생각하다보니 0도 부모가 리턴 받는다고 착각을 했던 것이다.

이제 부모가 자식을 더 잘 알 수 있게 되었으니 마저 코딩을 하도록 해야겠다.

0

settickets, getpinfo를 구현하고 ps를 구현했다. pstat을 전역 변수로 두고 관리하려 했으나 proc, pstat을 각각 관리하면 복잡해 진다는 것을 깨달았다. 다른 스터디원분이 먼저 작성하신 코드를 참고하여 proc에 ticks를 추가하고 getpinfo 호출시 pstat을 만드는 방향으로 계획을 바꿨다. 유저 공간에서 시스템콜에 포인터를 넘기고, 그 포인터에 값을 채워받는 것을 구현하는게 난관이었는데 Claude Code가 해결해줘서 넘어갔다.

0

스케쥴러가 어떤 프로세스를 실행중인지 확인해보기 위해 컨텍스트 스위칭 대상이 되는 프로세스의 pid를 출력해봤다. 기본 구현은 라운드 로빈이기 때문에 순서대로 순환되며 출력 될거라 예상했지만 순서가 뒤섞여서 출력이 되었다. 원인은 CPUS 옵션을 주지 않으면 기본값이 3으로 설정되기 때문에 여러 스케쥴러가 동시에 실행되어서 그런 것이었다. CPUS를 1로 설정하자 기대한대로 순서대로 순환되어 출력하는 것을 확인하였다.

0

scheduler 함수의 분석을 시작했다. scheduler는 컨텍스트 스위칭을 위해 swtch함수를 호출하는데, 이 함수는 어셈블리로 작성되어 있는지라 언제 리턴 되는지 더더욱 파악하기가 어려웠다. (사실 어셈블리가 아니었어도 파악하기는 쉽지 않았을거다.)

Claude Code에게 코드베이스 분석을 맡기고 몇가지 문답을 통해 타이머 인터럽트가 trap 핸들러를 호출하고, trap 핸들러가 yield->sched->swtch흐름으로 호출하여 scheduler함수로 돌아간다는 사실을 파악했다. 이 과정이 반복되며 프로세스는 순차 실행되고 그 사이사이에 scheduler가 교차 실행된다는 것을 알게 되었다.

책에 설명이 있긴 하지만 코드를 한땀한땀 분석했으면 오래 걸렸을텐데, Claude Code로 시간을 아낄 수 있었다. 예전엔 공부할 엄두가 안나던 것들이 LLM덕분에 조금은 가벼운 마음으로 시작해 볼 수 있게 되었다. 좋은 세상이다.

1

현재의 스케쥴러 구현인 라운드 로빈 방식을 이해해볼겸 루프안에서 fork를 사용해 n개의 프로세스를 생성하는 간단한 코드를 작성했다.

프로세스가 기대와 달리 n개가 생성되는게 아닌, (말 그대로) 기하급수적으로 생성되어서 원인을 생각해봤다. fork는 프로세스를 처음부터 실행하는게 아니라 현재까지 실행된 상태를 복제하여 새로운 프로세스를 만들고, 자기자신의 프로세스도 계속해서 실행하기 때문이다.

그렇기 때문에 n개의 프로세스를 만들려면 fork를 부모 프로세스만 실행할 수 있도록 자식 프로세스는 원하는 작업을 실행하고 루프를 탈출시켜야 한다는 일종의 fork 사용에 대한 관례를 배웠다.

사실 책 앞에 다 나왔던 내용인데 대충 읽었더니 이렇게 멀리 돌아가는 고생을 하고 있다. ㅋㅋㅋ

0

난수 생성기가 만만해보여 먼저 찾아봤다. 적당히 복붙해서 구현하려 했으나 균일성, 편향제거, 동시성, 병렬성등 고려해야 할게 많다는 사실을 새삼 깨달았다. 그동안 단일 스레드 환경에서 편하게 살았음을 실감했다.

1
0
4
1

여성향 커미션 중개 플랫폼 크레페를 운영하는 쿠키플레이스에서 시니어 백엔드 엔지니어 채용을 진행중입니다. 채용공고에 해당 직무 소개, 복지, 연봉, 회사문화의 내용이 포함돼 있습니다. 많은 관심 부탁드립니다. Node.js, TypeScript, GraphQL에 대한 높은 숙련도 및 지식으로 팀에 기여해주실 분을 쿠키플레이스에서 극진히 기대하고 있습니다.

크레페에서는 이런 기술스택을 사용합니다

  • Node.js, TypeScript, Vitest, Fastify
  • GraphQL  - Yoga, Relay, Pothos, Prisma
  • ElasticSearch, MongoDB, FCM
  • Docker, Github Actions
  • AWS  - ElasticBeanstalk, CloudWatch, Aurora PostgreSQL, Lambda, SES, S3, ElastiCache (Redis)
  • Grafana, Sentry

구성원의 성장과 덕질을 지원해요

  • 희망 도서 구매 (만화책 및 TRPG 룰북 포함)
  • 워크샵 및 교육 프로그램 지원
  • 전시, 공연 및 각종 행사 티켓 지원
  • 월 5만 크레페 포인트
  • 전동작탁 AMOS JP-EX COLOR
  • 6인용 TRPG/보드게임 테이블

지원자님이 예상하실 수 있는 처우는 이래요

  • 연봉: 최소 8000만원 ~ 최대 2억원 (주 40시간)
  • 스톡옵션 부여에 열려있는 포지션
크레페, 나만의 레시피, 나만의 창작물
10
1
0
0

자손킴 replied to the below article:

펑터Functor

lionhairdino @lionhairdino@hackers.pub

하스켈 펑터 입문자를 위한 이 글은 `Maybe Int` 타입의 값에서 `Int`를 직접 "꺼내올 수 없다"는 개념을 설명합니다. `Maybe`의 `fmap`이나 `fromJust`가 마치 값을 꺼내는 것처럼 보이지만, 이는 실제로는 값을 꺼내는 것이 아니라, 원본 타입(`Int`)의 구조를 보존하며 새로운 `Maybe Int` 타입의 값을 "생성"하는 과정이라는 것입니다. 미끄럼틀 비유를 통해, `Maybe Int`의 `Just 1`은 `Int` 값 `1`과 연관되어 있지만, `Just 1` 자체가 `1`을 의미하는 것은 아닙니다. 펑터는 원본 타입의 관계(구조)를 그대로 유지하며 다른 타입으로 변환하는 역할을 합니다. `fmap`은 `Maybe Int` 안의 `Int`를 직접 조작하는 것이 아니라, 원본 `Int` 값의 관계를 바탕으로 새로운 `Maybe Int` 값을 만들어내는 것입니다. 상자 메타포가 유용할 때도 있지만, 펑터의 본질을 오해하게 만들 수 있습니다. 상자 안의 값을 꺼내는 것이 아니라, 값의 "성격"은 값을 다루는 함수들의 동작에 따라 결정된다는 점을 강조합니다. 이 글은 "없을 수도 있는 수를 꺼낸다"는 표현의 모순을 지적하며, 펑터의 개념을 더 깊이 이해하도록 돕습니다.

Read more →
6
1

tanstack query의 initialPageParam에 대하여 오늘 배운 것

자손킴 @jasonkim@hackers.pub

TanStack Query의 `useInfiniteQuery` 훅을 사용할 때 `initialPageParam`이 어떻게 동작하는지에 대한 중요한 통찰을 공유합니다. 이 훅은 초기 렌더링 시 `initialPageParam`을 `pageParams[0]`으로 설정하고, 동일한 `queryKey`를 가진 캐시가 유지되는 동안 이 값을 계속 사용합니다. 따라서 여러 컴포넌트에서 동일한 `queryKey`로 `useInfiniteQuery`를 호출하면서 다른 `initialPageParam` 값을 제공하더라도, 처음 호출된 `initialPageParam` 값으로 고정됩니다. 이는 시작 커서가 다를 경우 `queryKey`를 다르게 지정해야 함을 의미합니다. 이러한 동작은 이해하고 나면 당연하지만, 익숙하지 않은 개발자에게는 혼란스러울 수 있습니다. `initialPageParam`이 `queryKey`와 강하게 연결되어 있다는 점이 InfiniteQueryOptions에서 타입 제약으로 더 명확하게 표현된다면 개발 경험이 향상될 것입니다.

Read more →
6