TypeScript readonly 이해와 사용법, 배열·객체 읽기 전용 타입 지정

개념/배경 readonly는 TypeScript 전용 타입 수정자이며 JavaScript 런타임에는 존재하지 않음 컴파일 타임에만 효력이 있으며, 읽기 전용으로 선언된 배열·객체 속성을 수정하려는 코드에 대해 타입 오류를 발생시킴 핵심 개념 배열 또는 객체 속성의 변경 금지 의도를 타입 수준에서 명시 예를 들어 onChainResult: readonly bigint[]는 블록체인에서 읽어온 결과 배열이 이후 코드 흐름에서 변형되지 않음을 보장하려는 의도 표현 읽기 전용 제약은 타입 체크 시점에만 적용되며, 트랜스파일된 JavaScript에는 제약이 남지 않음 동작과 제한 읽기 전용 배열은 변경 메서드가 제거된 ReadonlyArray 형태로 다뤄짐 객체의 readonly 속성은 재할당 금지, 단 객체 참조 자체는 다른 값으로 교체 가능할 수 있으므로 설계 시 구분 필요 타입 수준 readonly는 얕은 불변성에 해당하는 경우가 많음. 중첩된 구조까지 불변으로 보장하려면 계층별로 readonly를 적용하거나 별도 불변 모델을 설계해야 함 ...

January 18, 2026

CEI 패턴 Checks-Effects-Interactions로 재진입 방어

개념/배경 CEI 패턴은 Checks-Effects-Interactions의 약자 스마트 컨트랙트 함수에서 실행 순서를 명확히 해 재진입 공격을 줄이는 코드 규칙 핵심은 검증 후 상태 변경을 먼저 완료하고, 외부 호출을 마지막에 수행하는 흐름 유지 3단계 순서 1. Checks (검증) ↓ 2. Effects (상태 변경) ↓ 3. Interactions (외부 호출)이 순서를 지키면 외부로 제어권이 나가기 전에 내부 상태가 이미 안전하게 반영됨 재진입 시도는 변경된 상태에 의해 자연스럽게 차단됨 예시로 이해하기 잘못된 순서 위험 function withdraw(uint256 amount) external { // 1. Checks require(balances[msg.sender] >= amount); // 2. Interactions ← 너무 빠름 (bool success, ) = msg.sender.call{value: amount}(""); require(success); // 3. Effects ← 너무 늦음 balances[msg.sender] -= amount; }문제점 ...

January 17, 2026

NestJS 전역 예외 필터와 표준 오류 응답 설계 가이드

개요 API 에러 응답을 일관된 JSON 포맷으로 통일하고, 비즈니스 예외와 프레임워크 예외를 한 경로로 수집하는 전역 예외 필터 설계와 구현 정리 핵심은 표준 에러 코드 정의, AppError 기반의 명시적 예외 던지기, GlobalExceptionFilter에서의 단일 포맷 출력, ValidationPipe 결과의 구조화, traceId 기반 상관관계 추적 요청 흐름 개요 요청 진입 → ValidationPipe 검증 검증 실패 → 전역 필터에서 표준 응답 변환 검증 통과 → Controller/Service 실행 비즈니스 로직 예외 → AppError 서브클래스 throw → 전역 필터 처리 알 수 없는 예외 → 500으로 표준 응답 변환 최종 응답 포맷은 단일 구조 유지 ...

January 16, 2026

스마트 컨트랙트 재진입 공격 방지 가이드 — CEI 패턴과 ReentrancyGuard

개요 리엔트란시 재진입은 외부 호출 중 컨트랙트의 같은 함수 또는 다른 함수가 다시 호출되는 상황을 의미함 상태 변경 전 외부 호출이 발생하면 공격자가 재진입을 통해 상태 검증을 우회하거나 중복 실행을 유도할 수 있음 대표적 피해 사례로 The DAO 사건이 알려져 있음 실무 기본 원칙은 CEI 패턴 Checks-Effects-Interactions 준수와 ReentrancyGuard를 통한 보강 적용임 두 방법을 함께 쓰는 것이 표준에 가까움 유명한 사례와 최소 취약 패턴 취약한 순서 패턴 핵심 외부 전송 또는 외부 컨트랙트 호출이 상태 변경보다 먼저 발생 이후 상태 변경이 이루어져도 재진입 시점에는 이전 상태가 유효하여 중복 집행 가능 최소 취약 스니펫 예시 ...

January 15, 2026

ERC-721 승인 패턴 정리 approve vs setApprovalForAll 사용법과 권한 확인

개요 ERC-721에서 전송 권한 위임을 처리하는 두 가지 승인 방식 정리 권한 범위와 사용 시나리오가 달라 오용 시 과권한 위험 발생 가능 핵심 동작과 권한 확인 패턴 중심으로 정리 핵심 개념 approve(address to, uint256 tokenId) 특정 NFT 1개에 대한 전송 권한만 부여 예 123번 토큰만 지정한 대상이 전송 가능 토큰별 개별 승인 필요 setApprovalForAll(address operator, bool approved) 소유한 모든 NFT에 대한 전송 권한 일괄 부여 한 번 승인 시 현재 보유분 + 이후 수령분까지 포함 관리 편의성 높지만 권한 범위 큼 권한 확인 패턴 컨트랙트에서 호출 주체가 대상 토큰에 대해 승인 받았는지 확인 필요 두 방식 모두 대응하는 조건을 만족해야 안전 ...

January 14, 2026

API 성능 테스트와 모니터링 표준 가이드

개요 신규 API 개발 또는 로직 변경 시 서비스의 안정성과 성능을 사전에 검증하기 위한 표준 테스트 프로세스 정의 목적 코드 수준의 비효율 제거와 인프라 병목 식별을 분리해 진행하며, 동일 스택으로 로컬과 서버 환경을 일관되게 관찰하는 것을 권장 테스트 전략 개요 성능 테스트는 환경과 목적에 따라 두 단계로 구분 Phase 1 Local 목표 코드 레벨 최적화와 비효율 제거 관점 CPU 스파이크, 메모리 누수, 이벤트 루프 지연, 불필요한 I O 대기 도구 k6 로컬, Clinic.js Phase 2 Dev 서버 목표 시스템 레벨 검증과 병목 지점 확인 관점 DB Redis MQ 한계, 연결 풀 고갈, 큐 적체, 에러율 도구 k6 원격, Prometheus Grafana 도구 구성 부하 생성 k6 JS 기반 스크립팅으로 학습 비용 낮음 CI CD 파이프라인 연동 용이 로컬과 서버 환경 모두에서 실행 가능 모니터링 Grafana Prometheus 인프라 통합 관제에 적합 Redis DB MQ WAS 지표를 일관된 대시보드로 관찰 테스트 중 실시간 병목 구간 가시화 프로파일링 Clinic.js Node.js 내부 지표 심층 분석에 특화 CPU 스파이크, 메모리 누수, 이벤트 루프 지연 원인 파악에 유용 로컬 디버깅 우선 권장 단계별 진행 Step 1 로컬 프로파일링 Local Profiling 질문 내 코드에 논리적 비효율이 없는가 배포 전 로컬에서 가벼운 부하를 주고 코드 결함을 조기에 식별 ...

January 13, 2026

Atomic Swap 스마트 컨트랙트 개념과 설계 포인트

개요 Atomic Swap 스마트 컨트랙트는 블록체인에서 두 당사자의 자산을 맞교환할 때 모든 동작이 한 번에 완료되거나 전혀 일어나지 않음을 보장하는 메커니즘을 제공함 사용자 간 신뢰 없이도 안전하게 교환할 수 있게 만드는 자동화 에스크로 역할의 코드임 핵심 개념: 원자성 원자성은 트랜잭션이 더 쪼갤 수 없는 단위로 실행됨을 의미함 성공 시: A가 B에게 자산 X를 이전 AND B가 A에게 자산 Y를 이전, 두 동작이 한 묶음으로 처리됨 실패 시: 아무 변경 없음, 각자 자산 유지 중간 상태가 발생하지 않도록 보장하는 것이 핵심임 왜 필요한가 서로 신뢰가 없을 때 누가 먼저 보낼지에 대한 교착 상태 발생함 ...

January 12, 2026

NestJS @Module 핵심 정리: imports, providers, exports, forRoot, Symbol 토큰, useFactory

개요 NestJS에서 @Module은 기능 단위 의존성을 묶는 단위이자 DI 경계를 정의하는 컨테이너 개념임 핵심은 imports로 외부 의존성 수입, providers로 내부 의존성 등록, exports로 외부 공개 대상을 결정하는 흐름 이해가 전부임 Module의 imports, providers, exports @Module 선언의 기본 형태 @Module({ imports: [...], providers: [...], exports: [...] }) class SomeModule {} providers 이 모듈에서 새로 생성해 DI 컨테이너에 등록할 대상 목록 @Injectable 클래스들 중심 Service, Repository, Adapter 등 예시 providers: [BatchService, PortFetcher, StoreService, MergeService] imports 다른 모듈이 exports로 공개한 provider를 이 모듈에서 사용하겠다는 선언 예시 imports: [RepositoryModule, HttpModule, LoggerModule] exports 이 모듈 바깥에서도 사용 가능하도록 내보낼 provider 목록 예시 exports: [JSON_REPOSITORY, LogRepository]정리하면 providers는 내부 생성, imports는 외부 수입, exports는 외부 공개 대상 지정임 ...

January 11, 2026

자바스크립트 비동기와 이터레이터 정리 — 기다림, 동시성, 백프레셔

개요 비동기는 강력한 도구임. 다만 배열과 스트림 같은 이터레이터와 결합되면 누가 무엇을 언제 기다리는지 불명확해지기 쉬움 핵심 포인트 세 가지 기억 완료 보장 확보했는지 동시성 제어를 명시했는지 백프레셔로 생산 속도 ≤ 소비 속도 유지했는지 비동기가 의도대로 동작하지 않는 케이스 forEach + async 사용 콜백이 반환한 프로미스를 외부가 수집하지 않음 → 완료 보장 깨짐, 레이스와 누락 가능성 증가 items.forEach(async (x) => { await doAsync(x) // 외부에서 기다리지 않음 }) map + async 이후 기다리지 않음 ...

January 10, 2026

TypeScript에서 type과 interface 차이와 선택 기준

개요 TypeScript에서 type과 interface는 겹치는 부분이 많지만 용도와 확장 방식이 다름 객체 구조 설계와 복잡한 타입 표현 중 무엇을 우선하느냐에 따라 선택 달라짐 핵심 차이 포인트 중심으로 정리 핵심 개념 type 타입 별칭 정의 수단 기본 타입, 유니언, 튜플, 교차 타입 등 복합 표현에 유리 선언 병합 불가 interface 객체의 구조 정의 수단 확장과 선언 병합 지원 주로 객체와 클래스와의 계약 정의에 사용 // type 별칭 최소 예시 type ID = number | string type Point = [number, number] type Person = { name: string } & { age: number } // interface 최소 예시 interface User { name: string; age: number } interface Employee extends User { employeeId: number }차이점과 동작 표현 범위 ...

January 9, 2026