반응형
반응형

[System] Everything I know about good system design, 좋은 시스템 설계

 


  • 좋은 시스템 설계
    란 복잡해 보이지 않고 오랜 기간 별다른 문제가 발생하지 않는 형태
  • 상태(state) 를 다루는 것이 시스템 설계에서 가장 어려운 부분이며, 가능한 한 상태를 저장하는 컴포넌트 수를 줄이는 방향이 중요
  • 데이터베이스는 주로 상태가 보관되는 위치로, 스키마 설계와 인덱싱, 병목 해소에 중점을 둔 접근이 필요
  • 캐싱, 이벤트 처리, 백그라운드 작업 등은 성능 및 유지보수를 위해 신중하게 도입해야 하며, 남용을 피하는 것이 좋음
  • 복잡한 설계보다는 충분히 검증된 간단한 컴포넌트 및 방법론을 적절하게 사용하는 것이 지속 가능하고 안정적인 시스템 구축에 핵심

시스템 설계의 정의와 전체적인 접근

  • 소프트웨어 설계가 코드의 조립이라면, 시스템 설계는 다양한 서비스를 조합하는 과정
  • 시스템 설계의 주요 구성 요소는 앱 서버, 데이터베이스, 캐시, 큐, 이벤트 버스, 프록시 
  • 좋은 설계는 "특별한 문제가 없다", "생각보다 쉽게 끝나다", "이 부분은 신경 쓸 필요가 없다"와 같은 반응을 이끌어냄
  • 반대로 복잡하고 눈에 띄는 설계는 근본 문제를 감추거나, 과도한 설계를 나타낼 수 있음
  • 복잡한 시스템은 초기부터 바로 도입하기보다는, 최소한의 작동 가능한 단순한 구조에서 점차 발전하는 방향이 유리함

상태(state)와 무상태(stateless)의 구분

  • 소프트웨어 설계에서 가장 까다로운 부분이 바로 상태 관리
  • 정보를 저장하지 않고 즉시 결과를 반환하는 서비스(GitHub의 PDF 렌더링과 같은)는 무상태적임
  • 반면 데이터베이스에 쓰기를 수행하는 서비스는 상태를 관리함
  • 시스템 내 상태 저장 컴포넌트를 최대한 줄이는 것이 좋음. 이는 시스템의 복잡도와 장애 발생 가능성을 낮춤
  • 상태 관리를 한 서비스에서만 수행하고, 나머지 서비스는 API 호출 혹은 이벤트 발생 등 무상태 역할에 집중하는 구조가 권장됨

데이터베이스 설계와 병목 지점

스키마 및 인덱스 설계

  • 데이터 보관을 위해서는 사람이 읽기 쉬운 형태의 스키마 설계가 필요함
  • 너무 유연한 스키마(예: 전체를 JSON 컬럼에 저장)는 애플리케이션 코드 및 성능에 부담을 줄 수 있음
  • 쿼리가 빈번하게 발생할 컬럼을 기준으로 적절한 인덱스를 설정해야 함. 모든 것에 인덱스를 거는 것은 오히려 쓸데없는 오버헤드 발생

병목 해결 방법

  • 데이터베이스 접근이 종종 무거운 병목이 됨
  • 가능한 한 복잡한 데이터를 애플리케이션에서가 아닌 데이터베이스 내에서 조인(JOIN) 등으로 처리하는 것이 성능상 유리함
  • ORM 사용 시, 루프 안에서 쿼리를 발생시키는 실수를 주의해야 함
  • 필요에 따라 쿼리를 분할하여, 데이터베이스의 부담이나 쿼리 복잡도를 조절하는 것도 한 방법
  • 읽기 쿼리는 복제본(read-replica)으로 분산하여, 주(Write) 노드의 부하를 줄이는 전략이 효과적
  • 대량의 쿼리가 몰릴 때 트랜잭션 및 쓰기 연산은 데이터베이스를 쉽게 과부하 상태로 만들 수 있으므로, 쿼리 스로틀링(제한) 처리를 고려해야 함

느린 작업과 빠른 작업의 분리

  • 사용자가 인터랙션하는 작업은 수백 밀리초 내 응답이 필요
  • 시간이 오래 걸리는 작업(예: 대용량 PDF 변환 등)은 최소한의 작업만 프론트에서 즉시 제공하고, 나머지는 백그라운드로 넘기는 패턴이 효과적
  • 백그라운드 작업은 일반적으로 큐(예: Redis)와 잡 러너가 묶여 동작
  • 멀리 예약된 작업 처리는 Redis보다 DB 테이블을 별도로 만들어 관리하고, 스케줄러를 이용하여 실행하는 형태가 실용적

캐싱

  • 캐싱은 동일하거나 비싼 연산을 반복하는 경우 비용 절감과 성능 향상에 기여
  • 보통 캐시를 처음 배운 주니어 엔지니어는 모든 것을 캐시하고 싶어하고, 경험 많은 엔지니어일수록 캐시 도입은 신중
  • 캐시는 새로운 상태를 도입하므로, 동기화 이슈/오류/스테일 데이터 등의 위험이 존재
  • 먼저 쿼리의 인덱스 추가 같은 성능 개선을 시도한 뒤 캐싱을 적용하는 것이 바람직
  • 대용량 캐시는 Redis/Memcached가 아니라 S3/Azure Blob Storage와 같은 문서 저장소에 주기적으로 저장하는 방식도 활용 가능

이벤트 처리

  • 대부분의 기업은 이벤트 허브(예: Kafka) 를 갖추고, 다양한 서비스가 이벤트 기반으로 분산 처리
  • 이벤트의 남발보다는, 단순한 요청–응답 API 설계가 로깅과 문제 해결 면에서 더 유용
  • 이벤트 기반 처리는 발신자가 수신자 동작에 신경 쓰지 않아도 될 때, 혹은 고용량·지연 허용 시나리오에 적합

데이터의 전달 방식: 푸시와 풀

  • 데이터 전달에는 Pull(요청 후 응답)  Push(변경 시 자동 전달) 두 방식이 있음
  • Pull 방식은 단순하지만 반복 요청/과부하 문제가 발생
  • Push 방식은 서버에서 데이터 변경 시 클라이언트에 즉시 전달하므로, 효율적이며 최신 데이터 유지에 유리
  • 대량 클라이언트 처리에는 각각 방식에 맞게 인프라(이벤트 큐, 여러 캐시 서버 등) 확장이 필요

핫패스(Hot Paths) 집중

  • 핫패스란 시스템 내에서 가장 중요하고 데이터가 많이 흐르는 경로를 의미
  • 핫패스는 선택지가 적고, 설계 실패 시 서비스 전체에 심각한 문제를 유발할 수 있으므로, 신중한 설계가 필수
  • 옵션이 다양한 마이너 기능보다, 핫패스에 집중하여 설계 및 테스트에 자원을 배분하는 것이 효과적

로깅, 메트릭, 추적

  • 장애 발생 시 원인 진단을 위해, 비정상 경로(unhappy path)에 대한 상세 로그 기록을 적극적으로 해야 함
  • 시스템 자원(CPU/메모리), 큐 크기, 요청/작업 시간 등 기본적인 관측성 지표 수집이 필요
  • 평균값만 보는 대신 p95, p99 지연 시간 같은 분포 지표도 반드시 관찰해야 함. 상위 소수의 느린 요청이 핵심 사용자의 문제일 수 있음

킬스위치, 재시도, 장애 복구

  • 킬스위치(시스템 일시 차단) , 재시도의 전략적 활용이 중요함
  • 무작정 재시도는 다른 서비스에 부담만 주며, 사전에 회로 차단기(circuit breaker) 등으로 요청을 제어해야 효과적임
  • Idempotency Key(멱등키) 도입으로 동일 요청 재처리 시 중복 작업 방지가 가능함
  • 일부 장애 상황에서 열린 실패(fail open) 또는 닫힌 실패(fail closed) 중 선택이 필요함. 예를 들어, Rate Limiting은 fail open(허용) 쪽이 사용자 영향이 적은 방향임. 반면 인증은 fail closed가 필수임

마무리

  • 서비스 분리, 컨테이너, VM 도입, 트레이싱 등 일부 주제는 생략됐으나, 잘 검증된 컴포넌트를 적재적소에 사용하는 것이 장기적으로 가장 안정적인 시스템 구축으로 이어짐
  • 기술적으로 특별한 설계는 실제로 매우 드물며, 지루할 정도로 단순한 설계가 오히려 실무에서 가장 자주 쓰임
  • 본질적으로 좋은 시스템 설계란 눈에 띄지 않고, 충분히 입증된 방법론을 안전하게 조합하는 과정임

 

https://news.hada.io/topic?id=22580

 

좋은 시스템 설계 | GeekNews

좋은 시스템 설계란 복잡해 보이지 않고 오랜 기간 별다른 문제가 발생하지 않는 형태상태(state) 를 다루는 것이 시스템 설계에서 가장 어려운 부분이며, 가능한 한 상태를 저장하는 컴포넌트 수

news.hada.io

 

반응형
반응형

원하는 목표를
이루지 못했다고 해서,
실패한 것은 아니에요. 목표를 향해
나아갔던 그 걸음걸음들이 당신만이 가진
하나뿐인 추억과 경험이 되었으니까요.
그것으로도 충분히 가치 있는
일이었답니다.


- 황제펭귄의 《구급책》 중에서 -


* 맞습니다.
실패란 없습니다.
실패는 때로 성공의 시작이기도 합니다.
실패의 경험, 그로부터 무엇을 깨닫고
배웠느냐에 따라 더 큰 성공의 길이
열립니다.

반응형

'아침편지' 카테고리의 다른 글

'행복의 정답'은 없다  (1) 2025.08.27
이유 없는 기쁨  (1) 2025.08.26
전율과 희열이 춤추는 무릉도원  (0) 2025.08.22
마음의 본성  (0) 2025.08.21
일석오조(一石五鳥)  (2) 2025.08.20
반응형

[SQL] 여러 개의 UPDATE 문을 실행한 후, 최종적으로 영향을 받은 전체 행의 개수를 세고 싶다

 

@@ROWCOUNT는 직전에 실행된 SQL 문이 영향을 준 행의 개수를 반환하는 전역 변수예요. 여러 개의 UPDATE 문을 실행할 경우, 각 UPDATE 문 직후에 이 값을 변수에 누적해서 더하면 최종 결과를 얻을 수 있어요.

 

-- 총 업데이트된 행 수를 저장할 변수 선언
DECLARE @TotalRowCount INT = 0;

-- 첫 번째 UPDATE 문 실행
UPDATE dbo.Customers
SET CustomerStatus = 'VIP'
WHERE TotalPurchases >= 100000;

-- 첫 번째 UPDATE의 영향을 받은 행 수를 변수에 더하기
SET @TotalRowCount = @TotalRowCount + @@ROWCOUNT;

-- 두 번째 UPDATE 문 실행
UPDATE dbo.Customers
SET CustomerStatus = 'Gold'
WHERE TotalPurchases >= 50000 AND TotalPurchases < 100000;

-- 두 번째 UPDATE의 영향을 받은 행 수를 변수에 더하기
SET @TotalRowCount = @TotalRowCount + @@ROWCOUNT;

-- 최종적으로 업데이트된 총 행 수 출력
PRINT '총 ' + CAST(@TotalRowCount AS NVARCHAR(10)) + '개의 행이 업데이트되었습니다.';
반응형
반응형

남해군 여행 - 공중화장실 안내

 

https://www.namhae.go.kr/tour/00012/00934/00971.web

 

 

공중화장실명 소재지 주소
창선생활체육관 창선면
경상남도남해군창선면동부대로2308
창선면 율도 창선면
경상남도남해군창선면서부로1067
창선생활체육공원2 창선면
경상남도남해군창선면상죽리10-13
창선생활체육공원1 창선면
경상남도남해군창선면동부대로2308
창선면 적량 창선면
경상남도남해군창선면흥선로1215
창선 가인리화석산지 창선면
경상남도남해군창선면흥선로767-3
창선연륙교죽방렴(관광안내소) 창선면
경상남도남해군창선면동부대로2964번길49-10
장항소공원 서면
경상남도남해군서면남서대로1517번길50
망운산 등산로 서면
경상남도남해군서면남서대로2240번길635
나비 화장실 서면
경상남도남해군서면스포츠파크길36
유포체험마을 서면
경상남도남해군서면남서대로2381번길60
비자인조구장 서면
경상남도남해군서면남서대로1687번길14
서면 그라운드골프장 서면
경상남도남해군서면남서대로1687번길2
스포츠파크 서면
경상남도남해군서면스포츠파크길74
서면 여객선 터미널(서상게스트하우스야외화장실) 서면
경상남도남해군서면남서대로1687번길28-12
자연휴양림 삼동면
경상남도남해군삼동면금암로658
내산 고향의 강 삼동면
경상남도남해군삼동면봉화리2453
내산 배움별곡 삼동면
경상남도남해군삼동면봉화리2517
나비생태공원 삼동면
경상남도남해군삼동면금암로562-23
은점 해안쉼터 삼동면
경상남도남해군삼동면동부대로942번길8-16
독일마을 입구 삼동면
경상남도남해군삼동면독일로4
지족(다리 밑) 삼동면
경상남도남해군삼동면죽방로24-1
지족 정보화 마을(지족갯마을화장실) 삼동면
경상남도남해군삼동면죽방로105
삼동면 동천 삼동면
경상남도남해군삼동면동천리1128
지족어촌관광단지 삼동면
경상남도남해군삼동면죽방로69
요트학교 삼동면
경상남도남해군삼동면동부대로1030번길42-26
지족공설시장 삼동면
경상남도남해군삼동면동부대로1876번길30-1
둔촌 삼동면
경상남도남해군삼동면동부대로1496
내산 화천 주차장 삼동면
경상남도남해군삼동면금암로125-4
독일마을 주차장(봉화방면) 삼동면
경상남도남해군삼동면독일로180
파독전시관 삼동면
경상남도남해군삼동면독일로89-7
원예예술촌(주차장) 삼동면
경상남도남해군삼동면예술길3
원예예술촌(매표소 옆) 삼동면
경상남도남해군삼동면봉화리2571-2
삼동면 물건2 삼동면
경상남도남해군삼동면동부대로1030번길79-27
삼동면 물건1 삼동면
경상남도남해군삼동면동부대로1030번길70
덕월녹색농촌체험마을 남면
경상남도남해군남면남서대로1179번길40-153
숙호숲 남면
경상남도남해군남면남면로219-25
사촌 해수욕장 남면
경상남도남해군남면남면로1229번길50
월포 해수욕장 남면
경상남도남해군남면남서대로611-17
항촌 소공원 남면
경상남도남해군남면남면로1031번길58
선구 몽돌밭 남면
경상남도남해군남면남면로1103번길23
사촌 주차장 남면
경상남도남해군남면남면로1229번길27
선구다목적광장 남면
경상남도남해군남면남면로1156-50
가천 다목적광장 남면
경상남도남해군남면남면로702
두곡해수욕장(주차장) 남면
경상남도남해군남면남서대로575-10
오리숲 남면
경상남도남해군남면남서대로1179번길93
구미숲 남면
경상남도남해군남면남서대로1249번길33-7
남면 홍현2 남면
경상남도남해군남면남면로389-89
남면공설운동장 남면
경상남도남해군남면남서대로748
남면공설시장 남면
경상남도남해군남면남서대로785-5
바래길 공중화장실 남면
경상남도남해군남면남면로1555-103
가천대형주차장 남면
경상남도남해군남면남면로654
가천암수바위 남면
경상남도남해군남면남면로679번길41
평산 작은미술관 남면
경상남도남해군남면남면로1739번길46
사촌해수욕장입구주차장 남면
경상남도남해군남면남면로1229번길6
상주 동편방파제 상주면
경상남도남해군상주면남해대로675번길80
두모 탐방로 상주면
경상남도남해군상주면양아리산47-7
상주 소량 상주면
경상남도남해군상주면양아로355번길33
두모선착장 상주면
경상남도남해군상주면양아리1975
두모야영장 상주면
경상남도남해군상주면양아로533번길77
두모체험장 상주면
경상남도남해군상주면양아로533번길18
상주은모래비치5 상주면
경상남도남해군상주면남해대로675번길26-6
상주은모래비치4 상주면
경상남도남해군상주면상주로17-4
상주은모래비치3 상주면
경상남도남해군상주면상주로65-9
상주은모래비치2 상주면
경상남도남해군상주면상주로65-7
상주은모래비치1 상주면
경상남도남해군상주면상주로65-13
상주은모래비치 주차장 상주면
경상남도남해군상주면남해대로675번길8-5
상주체육공원2 상주면
경상남도남해군상주면상주로60번길47-44
상주체육공원1 상주면
경상남도남해군상주면상주리1861
보리암 인근 상주면
경상남도남해군상주면상주리산258
금산주차장 상주면
경상남도남해군상주면남해대로918-13
상주면벽련매표소 상주면
경상남도남해군상주면남해대로1299번길69
바다정원 이동면
경상남도남해군이동면죽방로877
호구산 백련암 이동면
경상남도남해군이동면용문사길197
용문사 일주문 이동면
경상남도남해군이동면용문사길133
이동 원천마을 이동면
경상남도남해군이동면남해대로1553번길16-10
군민동산(앵강고개) 이동면
경상남도남해군이동면남해대로1856-3
이동 원천항 이동면
경상남도남해군이동면신전리1149
이동면 화계 이동면
경상남도남해군이동면성남로175번길4
어울림문화센터(이동공설시장) 이동면
경상남도남해군이동면무림로63번길41-3
바래길탐방안내센터 이동면
경상남도남해군이동면성남로99
남해국제탈공연예술촌 야외화장실/탈의실 이동면
경상남도남해군이동면남해대로2412
복곡제2주차장 이동면
경상남도남해군이동면보리암로586
복곡제3주차장 이동면
경상남도남해군이동면신전리1-8
복곡제1주차장 이동면
경상남도남해군이동면신전리2
복곡제1주차장 매표소 옆 이동면
경상남도남해군이동면신전리1540
미조북항 미조면
경상남도남해군미조면미조로8
미조물미항도전망대 미조면
경상남도남해군미조면동부대로374
미조 도심지(면사무소 옆) 미조면
경상남도남해군미조면미송로60
설리마을2 미조면
경상남도남해군미조면미송로303번길70
설리마을1 미조면
경상남도남해군미조면미송로303번길44
미조면 항도 미조면
경상남도남해군미조면동부대로310번길32-22
미조항 미조면
경상남도남해군미조면미조로9
송정솔바람해변3 미조면
경상남도남해군미조면미송로483번길50
송정솔바람해변2 미조면
경상남도남해군미조면미송로483번길4-79
송정솔바람해변1 미조면
경상남도남해군미조면송정리1175-6
송정솔바람해변 주차장 미조면
경상남도남해군미조면미송로483
미조면 천하 미조면
경상남도남해군미조면송정리1380
미조 공설운동장 미조면
경상남도남해군미조면남해대로257-11
노량 나루터공원 설천면
경상남도남해군설천면노량로268
충렬사(노량주차장) 설천면
경상남도남해군설천면노량로183번길27
왕지로타리 설천면
경상남도남해군설천면설천로816
노량 보건진료소 옆 설천면
경상남도남해군설천면노량로196
남해각 설천면
경상남도남해군설천면노량로178
설천면 월곡 설천면
경상남도남해군설천면남해대로4033번길46-3
화방사 고현면
경상남도남해군고현면화방사길104
이락사 고현면
경상남도남해군고현면남해대로3829
고현면 도심지 고현면
경상남도남해군고현면탑동로51
동도마 이동식 화장실 고현면
경상남도남해군고현면도마리199-7
순국공원2 고현면
경상남도남해군고현면남해대로3843
순국공원1 고현면
경상남도남해군고현면남해대로3807
심천해안도로 남해읍
경상남도남해군남해읍남해대로2984번길68-122
오동 수원지 남해읍
경상남도남해군남해읍오동로153
읍 시장2 남해읍
경상남도남해군남해읍화전로112
읍 시장1 남해읍
경상남도남해군남해읍화전로110
읍 도심지 남해읍
경상남도남해군남해읍화전로81
토촌 남해읍
경상남도남해군남해읍입현리산121
남해실내체육관 남해읍
경상남도남해군남해읍화전로43번길16
공설운동장 동편 남해읍
경상남도남해군남해읍망운로9번길42-17
공설운동장 정문 남해읍
경상남도남해군남해읍망운로9번길42-17
남산공원(충혼탑) 남해읍
경상남도남해군남해읍화전로43번길20-5
봉황산 나래숲 남해읍
경상남도남해군남해읍망운로10번가길20-34
남산공원(회차장) 남해읍
경상남도남해군남해읍망운로61번길61-21
남산공원(어울마당) 남해읍
경상남도남해군남해읍망운로61번길57
남산공원(아이나라) 남해읍
경상남도남해군남해읍망운로9번길42-69
유배문학관 야외(구운몽호) 남해읍
경상남도남해군남해읍남해대로2745
남해읍공영주차장 남해읍
경상남도남해군남해읍북변리327-2
터미널2 남해읍
경상남도남해군남해읍남해대로2835
터미널1 남해읍
경상남도남해군남해읍남해대로2835
반응형
반응형

그림을 본다는 건 꿈을 꾼다는 것
그림을 본다는 건 사랑을 한다는 것
세상살이 모든 고달픔과 시름과 걱정 내려놓고
어디론가 잠시 샛길로 빠져 걸어본다는 것
여럿이서도 좋겠지만 혼자라면
더욱 홀가분하고 좋은 것
(나태주의 시 중에서)


- 김두엽의《그림 그리는 할머니 김두엽 입니다 》중에서 -


* 그림을 보는 것만으로도
꿈을 꾸고 사랑도 할 수 있는데
그림을 직접 그리면 어떨까요? 아마도
더 많은 꿈, 더 아름다운 사랑을 하지 않을까요?
글을 쓰고 시(詩)도 쓰고 그림을 그리는 것은
무에서 유를 만드는 창조 행위입니다.
전율과 흥분과 희열이 춤을 추는
무릉도원입니다.

반응형

'아침편지' 카테고리의 다른 글

이유 없는 기쁨  (1) 2025.08.26
더 큰 성공의 길  (1) 2025.08.25
마음의 본성  (0) 2025.08.21
일석오조(一石五鳥)  (2) 2025.08.20
황홀경의 행복감  (0) 2025.08.19
반응형

개발자들이 조심해야 할 함정들

https://qouteall.fun/qouteall-blog/2025/Traps%20to%20Developers#summarization-of-traps

 

Traps to Developers | qouteall notes

A summarization of some traps to developers. There traps are unintuitive things that are easily misunderstood and cause bugs.

qouteall.fun

  • 개발자들이 흔히 빠지는 직관적이지 않은 함정을 정리하여, 발생하기 쉬운 버그의 원인을 소개함
  • HTML, CSS, Unicode/텍스트 인코딩, 부동소수점, 시간 등 다양한 기술에서 자주 발생하는 문제점들을 다룸
  • 각각의 언어와 프레임워크에서 문법 및 동작의 미묘한 차이로 인해 오해나 오류가 생길 수 있음을 강조
  • 동시성, 네트워킹, 데이터베이스 등 백엔드 핵심 영역에서 실제 운영 환경에서 발생할 수 있는 함정들을 예시로 설명함
  • 다양한 예제와 참고 링크를 통해 문제 상황과 해결법, 그리고 예기치 않은 동작 개선점을 안내함

 

HTML과 CSS

  • Flexbox/Grid에서 min-width 기본값
    • min-width는 기본적으로 auto
    • min-width: auto는 콘텐츠 크기에 의해 결정되며, flex-shrink, overflow: hidden, width: 0, max-width: 100%보다 우선 적용
    • 권장: min-width: 0 명시
  • CSS에서 가로와 세로의 차이
    • width: auto는 부모 공간 채우기를 시도, height: auto는 콘텐츠에 맞춤
    • inline, inline-block, float 요소의 width: auto는 확장하지 않음
    • margin: 0 auto는 가로 중앙 정렬, margin: auto 0은 세로 중앙 정렬 불가 (단, flex-direction: column에서는 세로 중앙 가능)
    • 마진 병합은 세로에서만 발생
    • writing-mode: vertical-rl 등 레이아웃 방향이 바뀌면 동작도 반전
  • Block Formatting Context (BFC)
    • display: flow-root로 BFC 생성 (그 외 overflow: hidden/auto/scroll, display: table 등도 가능하나 부작용 존재)
    • 세로 인접 형제 마진이 겹치거나, 자식 마진이 부모 밖으로 새는 현상은 BFC로 방지 가능
    • 부모가 float 자식만 포함하면 높이가 0으로 무너짐 → BFC로 수정 가능
    • border나 padding이 있으면 마진 병합 발생하지 않음
  • Stacking Context
    • 새로운 stacking context를 만드는 조건
      • transform, filter, perspective, mask, opacity 등 렌더링 속성
      • position: fixed 또는 sticky
      • z-index 지정 + absolute/relative 위치 지정
      • z-index 지정 + flexbox/grid 내부 요소
      • isolation: isolate
    • 특징
      • z-index는 stacking context 내부에서만 적용
      • position: absolute/fixed 좌표는 가장 가까운 positioned 조상 기준
      • sticky는 stacking context를 넘어서 동작하지 않음
      • overflow: visible도 stacking context에 의해 잘림
      • background-attachment: fixed는 stacking context 기준으로 배치
  • 뷰포트 단위
    • 모바일 브라우저에서 주소창/네비게이션바 스크롤 시 화면에서 사라지면 100vh 값이 달라짐
    • 최신 해결책: 100dvh 사용
  • Absolute Position 기준
    • position: absolute는 부모가 아닌, 가장 가까운 relative/absolute 또는 stacking context 조상을 기준
  • Blur 동작
    • backdrop-filter: blur는 주변 요소를 고려하지 않음
  • Float 무효화
    • 부모가 flex 또는 grid면 자식의 float는 효과 없음
  • 퍼센트 단위 width/height
    • 부모의 크기가 사전에 결정되지 않으면 작동하지 않음 (순환 참조 회피 목적)
  • Inline 요소 특성
    • display: inline은 width, height, margin-top, margin-bottom 무시
  • Whitespace 처리
    • 기본적으로 HTML의 줄바꿈은 공백으로 취급, 연속 공백은 하나로 축소
    • <pre>는 공백 축소 방지하지만 시작/끝 부분 동작 특이
    • 대부분 콘텐츠 시작/끝 공백은 무시되나 <a>는 예외
    • inline-block 사이의 공백/줄바꿈은 실제 간격으로 표시됨 (flex/grid에서는 발생 안 함)
  • text-align
    • 텍스트 및 inline 요소 정렬에는 적용되지만 block 요소 정렬에는 적용되지 않음
  • box-sizing
    • 기본값은 content-box → padding/border 포함 안 됨
    • width: 100% + padding 설정 시 부모 영역 넘침 가능
    • 해결: box-sizing: border-box
  • Cumulative Layout Shift
    • <img>에 width와 height 속성을 지정하지 않으면 이미지 로딩 지연으로 레이아웃 흔들림 발생
    • 권장: 속성 지정으로 CLS 방지
  • Chrome에서 파일 다운로드 네트워크 요청
    • DevTools 네트워크 패널에 표시되지 않음 (다른 탭으로 처리됨)
    • 분석 필요 시 chrome://net-export/ 사용
  • HTML 내 JavaScript 파싱 문제
    • <script>console.log('</script>')</script> 같은 경우 첫 </script>를 종료 태그로 인식
    • 참고: Safe JSON in script tags

Unicode와 텍스트 인코딩

  • 코드 포인트와 그래프림 클러스터
    • 그래프림 클러스터는 GUI에서의 "문자 단위"
    • 가시적 ASCII 문자는 코드 포인트 1개 = 그래프림 클러스터 1개
    • 이모지는 여러 코드 포인트로 구성된 하나의 그래프림 클러스터일 수 있음
    • UTF-8에서 코드 포인트는 1~4바이트, 바이트 수와 코드 포인트 수는 일치하지 않음
    • UTF-16에서 코드 포인트는 2바이트 또는 4바이트(서로게이트 페어)
    • 표준은 클러스터 내 코드 포인트 수 제한을 두지 않으나, 구현에서는 성능상 제한 존재
  • 언어별 문자열 동작 차이
    • Rust: 내부 문자열 UTF-8 사용, len()은 바이트 수, 직접 인덱싱 불가, chars().count()는 코드 포인트 수, UTF-8 유효성 엄격 검증
    • Golang: 문자열은 사실상 바이트 배열, 길이와 인덱싱은 바이트 단위, 주로 UTF-8 사용
    • Java, C#, JS: UTF-16 기반, 2바이트 단위로 길이 측정, 인덱싱도 2바이트 단위, 서로게이트 페어 존재
    • Python: len()은 코드 포인트 수 반환, 인덱싱은 코드 포인트 하나를 포함하는 문자열 반환
    • C++: std::string은 인코딩 제약 없음, 바이트 벡터처럼 동작, 길이/인덱싱은 바이트 단위
    • 언급된 언어 중 그래프림 클러스터 단위로 길이/인덱싱하는 언어는 없음
  • BOM (Byte Order Mark)
    • 일부 텍스트 파일은 BOM을 가짐, 예: EF BB BF → UTF-8 인코딩 표시
    • 주로 Windows에서 사용, 비-Windows 소프트웨어는 BOM 처리 못할 수 있음
  • 기타 주의사항
    • 바이너리 데이터를 문자열로 변환 시, 잘못된 부분은 � (U+FFFD)로 대체됨
    • Confusable characters 존재 (서로 비슷해 보이는 문자)
    • 정규화(Normalization): 예) é는 U+00E9(단일 코드 포인트) 또는 U+0065+U+0301(두 코드 포인트)로 표현 가능
    • Zero-width characters  Invisible characters 존재
    • 줄바꿈 차이: Windows는 CRLF \r\n, Linux/MacOS는 LF \n
    • 한자 통합(Han unification): 언어별로 모양이 조금 다른 문자가 동일 코드 포인트 사용
      • 폰트가 언어별 변형을 포함하여 적절히 렌더링
      • 국제화 시 올바른 폰트 변형 선택 필요

부동소수점 (Floating point)

  • NaN 특성
    • NaN은 자기 자신을 포함한 어떤 값과도 같지 않음 (NaN == NaN은 항상 false)
    • NaN != NaN은 항상 true
    • NaN을 포함한 연산 결과는 대부분 NaN으로 전파됨
  • 특수한 값
    • +Inf와 -Inf 존재, NaN과는 다름
    • -0.0은 +0.0과 구분되는 값
      • 비교 연산에서는 동일하지만, 일부 계산에서는 다르게 동작
      • 예: 1.0 / +0.0 == +Inf, 1.0 / -0.0 == -Inf
  • JSON과의 호환성
    • JSON 표준은 NaN과 Inf를 허용하지 않음
      • JS JSON.stringify는 NaN, Inf를 null로 변환
      • Python json.dumps(...)는 NaN, Infinity를 그대로 출력 (표준 위반)
        • allow_nan=False 옵션 시 NaN/Inf가 있으면 ValueError 발생
      • Golang json.Marshal은 NaN/Inf 존재 시 에러 반환
  • 정밀도 문제
    • 부동소수점 직접 비교는 실패 가능 → abs(a - b) < ε 형태 권장
    • JS는 모든 숫자를 부동소수점으로 처리
      • 안전한 정수 범위는 -(2^53 - 1) ~ 2^53 - 1
      • 이 범위를 벗어나면 정수 표현이 부정확
      • 큰 정수에는 BigInt 사용 권장
      • JSON에 안전 범위를 넘어선 정수가 포함되면 JSON.parse 결과 값은 부정확할 수 있음
      • 밀리초 단위 타임스탬프는 287,396년까지 안전, 나노초 단위는 문제 발생
  • 연산 법칙 비적용
    • 연산 순서에 따라 정밀도 손실로 인해 결합법칙, 분배법칙이 엄밀히 성립하지 않음
    • 병렬 연산(행렬 곱셈, 합계 등)은 비결정적 결과를 만들 수 있음
  • 성능
    • 나눗셈은 곱셈보다 훨씬 느림
    • 동일한 수로 여러 번 나눌 때는 역수를 먼저 구해 곱하는 방식으로 최적화 가능
  • 하드웨어에 따른 차이
    • FMA(Fused Multiply-Add) 지원 여부: 일부 하드웨어는 더 높은 정밀도로 중간 계산
    • Subnormal range 처리: 최신 하드웨어는 지원하지만 일부 구형은 0으로 처리
    • 반올림 모드 차이
      • RNTE(가장 가까운 짝수로 반올림), RTZ(0으로 절단) 등 존재
      • x86/ARM은 스레드 로컬 mutable 상태로 설정 가능
      • GPU는 명령어 단위로 반올림 모드가 다름
    • 삼각함수, 로그 등 수학 함수 동작 차이
    • x86은 레거시 80비트 FPU와 per-core rounding mode 존재 → 사용 비권장
    • 이 외에도 다양한 요인으로 하드웨어별 부동소수점 결과가 달라질 수 있음
  • 정밀도 향상 방법
    • 계산 그래프를 얕게 구성 (곱셈 연속 구조 줄이기)
    • 중간 값이 매우 크거나 매우 작은 경우 피하기
    • FMA 같은 하드웨어 연산 활용

시간 (Time)

  • 윤초(Leap second)
    • Unix 타임스탬프는 윤초를 무시
    • 윤초 발생 시 주변 구간에서 시간이 늘어나거나 줄어듦(Leap smear)
  • 시간대(Time zone)
    • UTC 및 Unix 타임스탬프는 전 세계 공통
    • 사람이 읽는 시간은 지역별 시간대에 의존
    • DB에는 타임스탬프를 저장하고 UI에서 변환하는 방식 권장
  • 서머타임(DST)
    • 일부 지역에서는 여름철에 1시간 시계 조정
  • NTP 동기화
    • 동기화 과정에서 시간이 "뒤로 가는" 상황 발생 가능
  • 서버 시간대 설정
    • 서버는 UTC로 설정 권장
    • 분산 시스템에서 노드별 시간대가 다르면 문제 발생
    • 시스템 시간대 변경 후 DB 재설정 또는 재시작 필요
  • 하드웨어 시계 vs 시스템 시계
    • 하드웨어 시계는 시간대 개념 없음
    • Linux: 하드웨어 시계를 UTC로 처리
    • Windows: 하드웨어 시계를 로컬 시간으로 처리

Java

  • ==는 객체 참조 비교, 객체 내용 비교는 .equals 사용 필요
  • equals와 hashcode를 오버라이드하지 않으면 map/set에서 객체 동일성을 참조 기반으로 판단
  • map의 key 객체나 set 원소 객체의 내용을 변경하면 컨테이너 동작이 깨짐
  • List<T> 반환 메서드는 경우에 따라 mutable ArrayList 또는 immutable Collections.emptyList() 반환, 후자 수정 시 UnsupportedOperationException 발생
  • Optional<T>를 반환하는 메서드가 null을 리턴하는 경우 존재 (권장되지 않음)
  • finally 블록에서 return 시, try 또는 catch에서 발생한 예외가 무시되고 finally 반환 값이 적용됨
  • interrupt 무시하는 라이브러리 존재, IO 포함한 클래스 초기화 과정이 interrupt로 깨질 수 있음
  • thread pool에서 .submit()으로 전달한 task의 예외는 기본적으로 로그에 출력되지 않고 future로만 확인 가능, future 무시하면 예외 확인 불가
    • scheduleAtFixedRate 작업은 예외 발생 시 조용히 중단됨
  • 숫자 리터럴이 0으로 시작하면 8진수 처리 (0123 → 83)
  • 디버거는 지역 변수의 .toString()을 호출, 일부 클래스의 toString()에 부작용이 있어 디버깅 시 코드 동작이 달라질 수 있음 (IDE에서 비활성화 가능)

Golang

  • append()는 capacity 여유 시 메모리 재사용, subslice에 append 시 부모 메모리까지 덮어쓸 수 있음
  • defer는 함수 리턴 시 실행, 블록 스코프 종료 시가 아님
  • defer는 mutable 변수 캡처
  • nil 관련
    • nil slice와 empty slice는 다름
    • string은 nil 불가, 빈 문자열만 존재
    • nil map은 읽기는 가능하지만 쓰기는 불가
    • interface nil 특이 동작: data pointer가 null이지만 type info가 null이 아니면 nil과 같지 않음
  • Dead wait: Go에서 실제 동시성 버그 사례 존재
  • Timeout 종류 다양, net/http에서 상세히 다룸

C/C++

  • std::vector 원소 포인터 저장 후 vector가 grow되면 재할당 발생, 포인터 무효화
  • 리터럴 문자열로 생성된 std::string은 임시 객체일 수 있음, c_str() 호출 시 위험
  • 반복 중 컨테이너 수정 시 iterator 무효화 발생
  • std::remove는 실제 삭제가 아닌 원소 재배열, 삭제는 erase 필요
  • 숫자 리터럴이 0으로 시작하면 8진수 처리 (0123 → 83)
  • Undefined behavior (UB): 최적화 과정에서 UB는 자유롭게 바뀔 수 있어 의존 시 위험
    • 초기화되지 않은 메모리 접근 UB
    • char*를 struct 포인터로 변환 시 객체 수명 시작 전 접근으로 UB, memcpy로 초기화 권장
    • 잘못된 메모리 접근 (null 포인터 등) UB
    • 정수 overflow/underflow UB (unsigned는 0 아래로 underflow 가능)
    • Aliasing: 서로 다른 타입 포인터가 동일 메모리 참조 시 strict aliasing rule에 의해 UB 발생
      • 예외: 1) 상속관계 타입 2) char*, unsigned char*, std::byte* 변환 (역변환은 적용 안 됨)
      • 강제 변환은 memcpy 또는 std::bit_cast 권장
    • Unaligned memory 접근 UB
  • 메모리 Alignment
    • 64비트 정수는 주소가 8로 나누어 떨어져야 함
    • ARM에서 unaligned 접근은 crash 가능
    • 바이트 버퍼를 struct로 직접 해석 시 alignment 문제 발생
    • alignment는 struct padding을 만들어 메모리 낭비 가능
    • 일부 SIMD 명령어(AVX 등)는 정렬된 데이터만 처리 가능, 보통 32바이트 alignment 필요

Python

  • 함수 기본 인자는 호출 시마다 새로 생성되지 않고 최초 값이 그대로 저장됨

SQL Databases

  • Null 처리
    • x = null은 동작하지 않고 x is null을 사용해야 함
    • Null은 자기 자신과 같지 않음 (NaN과 유사)
    • Unique index는 Null 중복 허용 (단, Microsoft SQL Server는 예외)
    • select distinct에서 Null 처리 방식은 DB마다 다름
    • count(x)와 count(distinct x)는 Null 값이 있는 행을 무시
  • 일반 동작
    • 날짜 암묵 변환은 timezone 의존적일 수 있음
    • 복잡한 join + distinct는 중첩 쿼리보다 느릴 수 있음
    • MySQL(InnoDB)에서 string 필드가 utf8mb4가 아니면 4-byte UTF-8 문자 삽입 시 오류 발생
    • MySQL(InnoDB)은 기본적으로 대소문자 구분 없음
    • MySQL(InnoDB)은 암묵적 변환 허용: select '123abc' + 1; → 124
    • MySQL(InnoDB) gap lock은 deadlock 유발 가능
    • MySQL(InnoDB)에서는 group by와 select 컬럼 불일치 시 비결정적 결과 반환
    • SQLite에서는 strict가 아니면 필드 타입이 크게 의미 없음
    • Foreign key는 암묵적 lock을 발생시켜 deadlock을 유발할 수 있음
    • Locking은 DB별로 repeatable read isolation을 깨뜨릴 수 있음
    • 분산 SQL DB는 locking 미지원이거나 특이한 동작 가능 (DB별 상이)
  • 성능/운영
    • N+1 query 문제는 각 쿼리가 빠르기 때문에 slow query log에 나타나지 않음
    • 장기 실행 트랜잭션은 lock 문제 등 유발 → 트랜잭션은 빠르게 끝내는 것이 권장됨
    • 전체 테이블 lock 사례
      • MySQL 8.0+에서는 unique index/foreign key 추가 시 대부분 동시 처리 가능
      • 구버전 MySQL은 전체 테이블 lock 발생 가능
      • mysqldump에 --single-transaction 옵션 없으면 전체 테이블 read lock
      • PostgreSQL에서 create unique index나 alter table ... add foreign key는 전체 테이블 read lock 유발
        • 회피: create unique index concurrently 사용
        • foreign key는 ... not valid  validate constraint 방식 사용
  • Range 쿼리
    • 겹치지 않는 범위:
      • 단순 조건 p >= start and p <= end는 비효율적 (복합 인덱스 있어도)
      • 효율적 방식:
        select *   
        from (select ... from ranges where start <= p order by start desc limit 1)   
        where end >= p  
        
        (start 컬럼 인덱스만 필요)
    • 겹칠 수 있는 범위:
      • 일반 B-tree 인덱스로는 비효율적
      • MySQL은 spatial index, PostgreSQL은 GiST 사용 권장

Concurrency and Parallelism

  • volatile
    • volatile은 lock을 대체할 수 없으며 atomicity 제공 안 함
    • lock으로 보호된 데이터는 volatile 필요 없음 (lock이 memory order 보장)
    • C/C++: volatile은 일부 최적화만 방지, memory barrier 추가 안 됨
    • Java: volatile 접근은 sequentially-consistent ordering 제공 (필요 시 JVM이 memory barrier 삽입)
    • C#: volatile 접근은 release-acquire ordering 제공 (필요 시 CLR이 memory barrier 삽입)
    • 메모리 읽기/쓰기 재정렬 관련 잘못된 최적화 방지 가능
  • TOCTOU (Time-of-check to time-of-use) 문제
  • SQL DB에서 응용 계층 제약 조건 처리
    • 단순 unique index로 표현 불가한 제약(예: 두 테이블 간 유니크, 조건부 유니크, 기간 내 유니크)을 애플리케이션에서 강제하는 경우:
      • MySQL(InnoDB): repeatable read 레벨에서 select ... for update 후 insert, 그리고 유니크 컬럼에 인덱스가 있으면 gap lock 덕분에 유효 (단, gap lock은 고부하 시 deadlock 유발 가능 → deadlock detection 및 retry 필요)
      • PostgreSQL: repeatable read 레벨에서 동일 로직은 동시성 상황에서 불충분 (write skew 문제)
        • 해결책:
          • serializable isolation level 사용
          • 애플리케이션 대신 DB 제약 사용
            • 조건부 유니크 → partial unique index
            • 두 테이블 간 유니크 → 별도 테이블에 중복 데이터 삽입 후 unique index
            • 기간 배타성 → range type + exclude constraint
  • Atomic reference counting
    • Arc, shared_ptr와 같이 많은 스레드가 동일 카운터를 자주 변경하면 성능 저하
  • Read-write lock
    • 일부 구현은 read lock에서 write lock으로 업그레이드 지원하지 않음
    • read lock 보유 상태에서 write lock 시도 시 deadlock 발생 가능

Common in many languages

  • Null/None/nil 체크 누락이 흔한 오류 원인
  • 반복문 중 컨테이너 수정 시 단일 스레드 데이터 경쟁 발생 가능
  • 가변 데이터 공유 실수: 예) Python에서 [[0] * 10] * 10은 올바른 2D 배열 생성 아님
  • (low + high) / 2는 overflow 가능 → 안전한 방식은 low + (high - low) / 2
  • 단락 평가(short circuit): a() || b()는 a가 true면 b 실행 안 됨, a() && b()는 a가 false면 b 실행 안 됨
  • 프로파일러 기본값은 CPU time만 포함 → DB 대기 등은 flamegraph에 나타나지 않아 오해 유발
  • 정규 표현식 dialect가 언어마다 다름 → JS에서 동작하는 정규식이 Java에서 동작 안 할 수 있음

Linux and bash

  • 디렉터리 이동 후 pwd는 원래 경로, 실제 경로는 pwd -P
  • cmd > file 2>&1 → stdout+stderr 모두 파일, cmd 2>&1 > file → stdout만 파일, stderr는 그대로
  • 파일 이름은 대소문자 구분 (Windows와 다름)
  • 실행 파일은 capability 시스템 존재 (getcap으로 확인)
  • Unset 변수 위험: DIR unset이면 rm -rf $DIR/  rm -rf / 실행 위험 → set -u로 방지 가능
  • 환경 적용: 스크립트를 현재 shell에 적용하려면 source script.sh 사용 → 영구 적용하려면 ~/.bashrc에 추가
  • Bash는 명령어 캐싱: $PATH 내 파일 이동 시 ENOENT 발생 → hash -r로 캐시 갱신
  • 변수 미인용 사용 시 줄바꿈이 공백으로 처리
  • set -e: 스크립트 오류 시 즉시 종료하지만, 조건문 내부(||, &&, if)에서는 동작 안 함
  • K8s livenessProbe와 디버거 충돌: 브레이크포인트 디버거는 앱 전체를 멈추게 하여 health check 응답 실패 → Pod가 종료될 수 있음

React

  • 렌더링 코드에서 state 직접 수정
  • Hook을 if/loop 안에서 사용 → 규칙 위반
  • useEffect dependency array에 필요한 값 누락
  • useEffect에서 정리(clean up) 코드 누락
  • Closure trap: 오래된 state 캡처로 인해 버그 발생
  • 잘못된 위치에서 데이터 변경 → 불순한 컴포넌트
  • useCallback 사용 누락 → 불필요한 리렌더링 발생
  • 메모된 컴포넌트에 비메모 값 전달 시 memo 최적화 무효화

Git

  • Rebase는 히스토리 재작성
    • rebase 후 일반 push는 충돌 → 반드시 force push 필요
    • remote branch 히스토리 변경 시 pull도 --rebase 사용
    • --force-with-lease는 일부 경우 다른 개발자 commit 덮어쓰기 방지 가능, 단 fetch만 하고 pull 안 하면 보호 안 됨
  • Merge revert 문제
    • Merge revert는 효과 불완전 → 동일 브랜치 다시 merge 시 아무 변화 없음
    • 해결책: revert의 revert 실행 또는 깨끗한 방법(backup → reset → cherry-pick → force push)
  • GitHub 관련 주의사항
    • API 키 같은 secret을 commit 후 force push로 덮어도 GitHub에는 기록이 남음
    • private repo A를 fork한 B가 private이라도, A가 public이 되면 B의 내용도 공개됨 (삭제 후에도 접근 가능)
  • git stash pop: conflict 발생 시 stash가 drop되지 않음
  • .DS_Store는 macOS가 자동 생성 → .gitignore에 **/.DS_Store 추가 권장

Networking

  • 일부 라우터·방화벽은 유휴 TCP 연결을 조용히 끊음 → HTTP 클라이언트·DB 클라이언트의 커넥션 풀 무효화 가능 → 해결: TCP keepalive 설정
  • traceroute 결과는 신뢰성 낮음 → 경우에 따라 tcptraceroute가 더 유용
  • TCP slow start는 대기시간 증가 원인 → tcp_slow_start_after_idle 비활성화로 해결 가능
  • TCP sticky packet 문제: Nagle 알고리즘은 패킷 전송 지연 → TCP_NODELAY 활성화로 해결 가능
  • Nginx 뒤에 백엔드 배치 시 커넥션 재사용 설정 필요 → 미설정 시 고부하 환경에서 내부 포트 부족으로 연결 실패
  • Nginx는 기본적으로 패킷 버퍼링  SSE(EventSource) 지연 발생
  • HTTP 표준은 GET·DELETE 요청 body를 금지하지 않음 → 일부는 body 사용하지만 많은 라이브러리·서버가 지원하지 않음
  • 하나의 IP에 여러 웹사이트 호스팅 가능 → 구분은 HTTP Host 헤더와 TLS의 SNI가 담당 → 단순 IP 접속 불가 사이트 존재
  • CORS: 다른 origin 요청 시 브라우저는 응답 접근 차단 → 서버에서 Access-Control-Allow-Origin 헤더 설정 필요
    • 쿠키 전달 포함 시 추가 설정 필요
    • 프론트엔드와 백엔드가 동일 도메인·포트라면 CORS 문제 없음

Other

  • YAML 주의사항
    • YAML은 공백 민감  key:value는 오류, key: value가 올바름
    • 국가 코드 NO는 따옴표 없이 쓰면 false로 해석되는 문제 발생
    • Git commit hash를 따옴표 없이 쓰면 숫자로 변환될 수 있음
  • Excel CSV 문제
    • Excel은 CSV 열 때 자동 변환 수행
      • 날짜 변환: 1/2, 1-2  2-Jan
      • 대형 숫자 부정확 변환: 12345678901234567890  12345678901234500000
    • 원인은 Excel이 내부적으로 floating point로 숫자를 처리하기 때문
    • 이슈로 인해 유전자 이름 SEPT1이 잘못 변경된 사례 존재

 

 

 

반응형

+ Recent posts