반응형
반응형

 

 ./input/ 폴더 안에 있는 엑셀파일을 찾아서 데이터 있는 셀의 앞뒤 공백을 삭제

 

# pip install pandas openpyxl


"""
    ./input/ 폴더 안에 있는 엑셀파일을 찾아서 데이터 있는 셀의 앞뒤 공백을 삭제

"""

import pandas as pd
import os

# 엑셀 파일이 있는 폴더 경로
input_folder = "./input/"

# 공백이 제거된 파일을 저장할 폴더 (원본 폴더에 저장)
output_folder = "./output/"

# 출력 폴더가 없으면 생성
if not os.path.isdir(output_folder):
    os.makedirs(output_folder)

# input 폴더 내의 모든 파일 목록 가져오기
files = os.listdir(input_folder)

print(f"'{input_folder}' 폴더에서 엑셀 파일을 찾고 있습니다...")

# 파일 목록을 순회
for filename in files:
    # 파일 확장자가 .xlsx 또는 .xls인지 확인
    if filename.endswith(".xlsx") or filename.endswith(".xls"):
        print(f"\n파일 '{filename}' 처리 중...")
        
        # 전체 파일 경로 설정
        file_path = os.path.join(input_folder, filename)
        
        try:
            # 엑셀 파일을 데이터프레임으로 읽어오기
            # 모든 시트를 읽어오기 위해 sheet_name=None 옵션 사용
            #excel_data = pd.read_excel(file_path, sheet_name=None) # 헤더 제외
            excel_data = pd.read_excel(file_path, sheet_name=None, header=0, dtype=str) # 모든 데이터를 문자열로 읽기
            
            # 수정한 내용을 저장할 새로운 엑셀 파일 객체 생성
            output_filepath = os.path.join(output_folder, f"{os.path.splitext(filename)[0]}_cleaned{os.path.splitext(filename)[1]}")
            
            with pd.ExcelWriter(output_filepath, engine='openpyxl') as writer:
                # 각 시트(Sheet)를 순회하며 작업
                for sheet_name, df in excel_data.items():
                    print(f"  - 시트 '{sheet_name}' 공백 삭제 중...")
                    
                    # 문자열 타입의 열만 선택하여 공백 제거
                    for col in df.columns:
                        if df[col].dtype == 'object':
                            # .str.strip() 메서드로 앞뒤 공백 제거
                            #df[col] = df[col].astype(str).str.strip()                            
                            df[col] = df[col].fillna('').astype(str).str.strip() # NaN 값이 있을 때 오류 방지
                            print(df[col])
                    
                    # 수정된 데이터프레임을 새로운 엑셀 파일의 해당 시트에 저장
                    df.to_excel(writer, sheet_name=sheet_name, index=False)
            
            print(f"'{filename}' 파일 처리가 완료되었습니다. '{output_filepath}'에 저장됨.")

        except Exception as e:
            print(f"  - 오류 발생: '{filename}' 파일을 처리할 수 없습니다. 오류: {e}")

print("\n모든 엑셀 파일 처리가 완료되었습니다.")
반응형
반응형

[Just Do Rust - 러스트 기초부터 고급까지](https://wikidocs.net/book/16747)

 

위키독스

온라인 책을 제작 공유하는 플랫폼 서비스

wikidocs.net

 

C언어를 처음 접한 것이 1990년입니다. 이후, C++/C#, Java, VBA, Python 등의 언어를 사용했고, 요즘 관심있는 언어가 Rust입니다.

관심 가지는 이유는 C언어의 성능과 Java나 Python 같은 안정성과 편리성을 가지고 있기 때문입니다. 특히, NSA(미국 국가안보국)에서 메모리 안전 문제로 C나 C++ 대신에 Rust와 같은 안전한 언어를 사용하도록 권고 했기에, 미국을 중심으로 기존의 C/C++로 된 코드를 Rust로 바꾸는 작업이 이루어지고 있고, 안전성이 요구되는 프로그램은 Rust로 개발되는 추세여서, 앞으로 Rust 언어의 활용이 많아질 것으로 보이기 때문입니다.

NSA가 권고하는 메모리 안전한 언어Python, Java, C#, Go, Delphi/Object Pascal, Swift, Ruby, Rust, Ada

성능까지 고려하면 Rust가 거의 유일한 C/C++ 대체 언어

필자가 생각하는 향후 Rust가 각광 받을 분야는,

  • 웹서버: 안전성과 성능이 좋아서, 현재 Java로 되어 있는 웹서버쪽은 Rust로 많이 전환될 것으로 예상
  • 암호 라이브러리: C/C++로 되어 있는 암호 라이브러리는 항상 Buffer overflow의 위험을 내재하고 있습니다. 이 부분도 Rust로의 전환이 예상됩니다.
  • 소형 기기 펌웨어: 구글은 이미 Android Virtualization Framework를 Rust로 포팅함. 대부분 C/C++로 작성되어 있어 메모리 안전성이 문제되는 펌웨어 단 모듈들은 Rust로 바꿔질 것임

성능도 좋고 안전하기도 한, 두 마리 토끼를 다 잡은 대신에, Rust 언어를 배우기는 쉽지 않습니다. 안전한 메모리 처리를 위해서 Rust에서 컴파일 전에 체크하는 '소유권', '에러처리', '타입 체크' 등을 개발자가 알아서 코드에 반영해야하기 때문입니다. 그렇지 않으면 아예 컴파일이 되지 않습니다. Java나 파이썬을 배우는 것 대비 2~3배 정도는 시간을 더 들여야 Rust에 익숙해질 것입니다.

이 책은 한국에 있는 개발자를 대상으로 Rust 언어를 보다 쉽게 익숙하게 익힐 수 있도록 제작되었습니다.

효율적으로 공부할 수 있도록, 실제 꼭 알아야하는 부분만을 추릴려고 노력했습니다. 따라서, 이 책에서는 Rust에서 제공하는 모든 내용을 담지는 않습니다. 메뉴얼이 아닙니다.
그러나, 꼭 필요한 부분은 가능한 자세하고 깊게 설명합니다.

 

 

챕터 내용을 익히는데 좀 더 도움이 되도록 챕터 내용을 그대로 따라 해볼 수 있는 유튜브 영상 링크입니다.

https://youtu.be/kPLuJgkpYVY

 

반응형
반응형

[python] python, rust 의 관계

 

파이썬(Python)과 러스트(Rust)는 서로 경쟁 관계라기보다는 상호 보완적인 관계에 가깝습니다. 두 언어는 설계 철학부터 특징까지 매우 다르며, 각각의 강점을 활용해 시너지를 낼 수 있습니다.

 

 

두 언어의 근본적인 차이점

특징 파이썬(Python) 러스트(Rust)
언어 레벨 고수준 언어 (High-level) 저수준 언어 (Low-level)
컴파일 방식 인터프리터 방식 (실행 시 해석) 컴파일 방식 (실행 전 기계어로 변환)
타입 시스템 동적 타입 (Dynamic) 정적 타입 (Static)
메모리 관리 자동 (가비지 컬렉터) 수동 (소유권 시스템)
주요 강점 생산성, 쉬운 문법, 방대한 라이브러리 성능, 안정성, 메모리 안전성
주요 단점 느린 속도, 높은 메모리 사용량 어려운 학습 곡선, 긴 개발 시간

 

상호 보완적인 관계: 왜 함께 사용하는가?

파이썬은 개발 속도가 빠르고 배우기 쉬워 전체 애플리케이션의 뼈대를 만드는 데 탁월합니다. 하지만 속도가 중요하거나 복잡한 계산을 처리해야 하는 작업에서는 성능의 한계가 명확합니다.

바로 이 지점에서 러스트가 파이썬의 단점을 완벽하게 보완해 줍니다. 러스트는 뛰어난 성능과 메모리 효율성을 자랑하므로, 파이썬으로 만든 애플리케이션의 '병목 현상(bottleneck)'을 해결하는 데 이상적입니다.

예시: 파이썬으로 웹 서버를 구축했다고 가정해 봅시다. 웹 서버의 전체적인 로직은 파이썬으로 빠르게 개발할 수 있습니다. 그러나 특정 요청을 처리하는 과정에서 데이터 분석이나 복잡한 이미지 처리와 같은 고성능 작업이 필요할 수 있습니다.

이 경우, 해당 고성능 작업 부분만을 러스트로 작성합니다. 러스트는 이 작업을 매우 빠르게 처리하고, 그 결과를 다시 파이썬으로 전달해 줍니다. 이렇게 하면 파이썬의 빠른 개발 생산성러스트의 탁월한 실행 속도를 모두 얻을 수 있습니다.

실제 협업 방식

러스트로 작성된 코드는 '파이썬 모듈' 형태로 컴파일될 수 있습니다. **PyO3**나 **rust-cpython**과 같은 라이브러리를 사용하면, 러스트의 함수나 클래스를 마치 파이썬 함수처럼 호출할 수 있는 모듈을 쉽게 만들 수 있습니다.

즉, 러스트는 파이썬의 '성능을 위한 보조 도구' 역할을 하며, 파이썬 생태계에 새로운 가능성을 불어넣고 있습니다.

 

 

 

러스트 재단에서 개발되고 있는 메모리 안전성과 성능 및 편의성에 중점을 둔 프로그래밍 언어이다. 가비지 컬렉터 없이 메모리 안전성을 제공하는 대표적인 언어다. C++의 대체재로서 등장했다.

https://youtu.be/5C_HPTJg5ek

 

반응형
반응형

[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

 

반응형
반응형

[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://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