반응형
반응형

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

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이 잘못 변경된 사례 존재

 

 

 

반응형
반응형

"개발자가 대체된다"는 유행은 왜 반복될까 ?

The Recurring Cycle of 'Developer Replacement' Hype

 

https://alonso.network/the-recurring-cycle-of-developer-replacement-hype/

 

 

  • NoCode부터 AI까지, 개발자를 대체하겠다는 기술은 반복적으로 등장하지만 실제로는 기술 변화에 따라 역할이 변형
  • NoCode는 개발자를 없애지 않고 NoCode 전문가와 통합 기술자를 탄생시켰고, 클라우드는 DevOps 엔지니어라는 고급 직군을 만들었음
  • 현재 AI 개발도구도 비슷한 길을 걷고 있으며, AI가 코드를 짜는 시대에도 시스템 아키텍처 설계 능력은 여전히 핵심임
  • AI는 로컬 최적화는 잘하지만 전체 시스템 설계에는 약하며, 빠른 생성 속도로 인해 구조적 실수를 빠르게 고착화할 위험이 있음
  • 개발자 대체는 결국 기술 스택 변화에 따른 진화와 고도화일 뿐, 본질적 역할은 계속 필요함

From NoCode to AI-Assisted

  • 몇 년 주기로, 소프트웨어 개발자를 대체할 것이라 주장하는 새로운 기술이 등장함
  • "코딩의 종말", "이제 누구나 앱을 만들 수 있음", "아이도 코딩한다" 등 과장된 기대가 포함된 유사한 제목들이 반복적으로 생성됨
  • 경영진과 컨설턴트들이 이 흐름에 주목하고, 예산이 이동하는 모습이 나타남
  • 하지만 현실은 항상 “대체”가 아니라 “변형”이었음
    • 복잡해진 기술을 다루는 새로운 역할 고도화된 전문직이 탄생하고, 임금 수준도 상승하는 경향이 반복적으로 드러남
  • NoCode는 전문 기술자 없이 앱을 만들 수 있다는 기대를 만들었지만, 결국 데이터 모델링, 통합, 유지보수 등 복잡한 문제가 존재했고 이를 해결할 새로운 직군이 탄생함
  • 클라우드는 시스템 관리자 없이 운영 가능하다는 믿음을 줬지만 실제로는 DevOps 엔지니어라는 고급 전문성을 요구하게 되고, 임금도 상승함
  • AI도 마찬가지로, “AI가 코드를 대신 작성”할 수 있을 것 같지만 실제로는 AI를 관리·오케스트레이션 할 수 있는 숙련 개발자의 중요성이 더욱 커짐

반복되는 대체 약속의 회전목마(The Endless Carousel of Replacement Promises)

NoCode/LowCode 혁신

  • 직관적인 인터페이스로 모든 사용자가 앱을 만들 수 있다는 NoCode/LowCode 혁신이 등장
  • 하지만 실제 현장에서는 데이터 모델 설계, 기존 시스템과 데이터베이스 통합, 예외 처리, 유지 관리 등 신규 문제가 발생함
  • 이에 따라 단순 개발자가 아닌, 도메인 지식과 기술적 한계를 동시에 이해하는 NoCode 전문가가 필요해짐
  • 이들은 기존 개발자보다 더 높은 연봉을 받음

클라우드 혁명

  • 클라우드로 이전하면 시스템 관리자가 필요 없어질 거라는 기대가 컸음
  • 하지만 클라우드 관리 전문성 복잡성이 오히려 증가함
  • 기존 시스템 관리자는 DevOps 엔지니어로 변신하여 더 높은 급여를 받고, 인프라 자동화, 배포 파이프라인, 분산 시스템 관리 등 업무 수준이 고도화됨
  • 업무는 사라진 것이 아니라, 새로운 작업 형태로 진화함
  • 마이크로서비스 전환에서도 복잡성이 커지고, 결국 근본적으로 시스템을 관리하는 전문가의 역할이 중요함이 드러났음

오프쇼어(Offshore) 개발 바람

  • 해외 아웃소싱으로 비용을 절감할 수 있다는 믿음이 생겨났지만, 커뮤니케이션 문제, 품질 저하, 도메인 지식 부족으로 어려움 발생
  • 결국 분산 팀 구조조, 명확한 소유권, 강력한 아키텍처 등으로 전략이 변화하며, 초기 기대했던 것보다 전체 비용이 증가하는 결과를 낳음

AI 코딩 어시스턴트 혁명

  • 이제는 AI가 코드를 자동으로 생성한다는 약속이 화두임
  • 초기 현실에서는, AI가 만들어주는 코드는 종종 미묘한 오류와 일관성 문제를 내포함
  • 시니어 엔지니어가 AI 결과를 검토·수정하는 데 많은 시간을 쓰며, 경험 있는 개발자일수록 훨씬 더 많은 가치를 창출함
  • AI 보조만으로 구축된 시스템은 체계적인 아키텍처가 부재한 경우가 많음
  • 즉, 기술이 기술자를 대체하는 것이 아니라, 더 높은 추상화 계층으로 기술자의 전문성을 끌어올리는 것임

이번 사이클이 특별한 이유

  • 사람들이 간과하는 핵심: 코드는 자산이 아니라 부채
  • 빠르고 쉽게 코드를 만들수록, 유지보수와 보안, 리팩터링의 부담도 커짐
  • AI는 함수 단위 최적화는 가능하지만 전체 시스템 설계 능력은 부족
  • 구현 속도가 빨라질수록 구조적 실수를 빠르게 고착화할 위험 존재
  • 결국, AI 시대에도 진정한 자산은 시스템 아키텍처 설계 능력이며, 이는 대체가 아닌 강화의 대상
  • "AI가 개발자를 대체한다"는 주장은 다음의 근본적 오해에서 비롯됨
    • 코드는 자산이 아니라 부채라는 사실
    • 코드는 지속적인 유지·검증·보안 관리·교체가 필요하며, 그 라인 수만큼 부채가 증가함
  • AI가 코드를 빠르게 만들어준다는 것은, 부채를 그만큼 빠르게 발생시킨다는 것에 불과함
  • 즉, AI는 로컬 최적화(함수, 부분 기능)는 잘하지만, 글로벌 설계·아키텍처 결정은 부족함
  • 구현 속도가 빨라질수록, 잘못된 설계가 시스템 전체에 '굳어지는' 위험성이 커짐
  • 일회성 단기 사이트 제작에는 문제가 없으나, 장기적으로 발전하는 시스템에는 치명적임
  • 기술 혁신의 패턴은 변함없이 유지됨
    • 시스템 관리자는 DevOps 엔지니어가 되고, 백엔드 개발자는 클라우드 아키텍트가 됨
  • 하지만 AI는 모든 것을 가속화함. 살아남고 발전하는 기술은 코드 작성이 아님
  • 그것은 바로 시스템을 설계하는 것(Architecting systems). AI가 할 수 없는 유일한 일이 바로 그것임

 

 

반응형
반응형

AI 시대의 기술 위축을 피하는 방법

 

최고의 미래 개발자는, 오늘날의 AI로 인해, 스스로 생각하는 법을 잊지 않은 사람이 될 것임

 

https://addyo.substack.com/p/avoiding-skill-atrophy-in-the-age

 

Avoiding Skill Atrophy in the Age of AI

How to use AI coding assistants without letting your hard-earned engineering skills wither away.

addyo.substack.com

  • AI 도구로 인한 생산성 증가는 개발자들의 핵심 기술 쇠퇴(skill atrophy) 위험을 초래함
  • AI를 과도하게 의존하면 비판적 사고 문제 해결 능력이 점점 약화됨
  • 디버깅, 아키텍처 설계, 기억력 등 중요한 기술이 점차 퇴화할 수 있음
  • AI를 도구로 삼되, 스스로 사고하고 학습하는 습관을 반드시 유지해야 함
  • AI와 협력하는 방식으로 사용하면, 생산성과 기술 숙련도를 모두 향상시킬 수 있음

AI 시대에 기술 쇠퇴를 피하는 방법

  • 코딩 분야에서 AI 도우미의 부상은 생산성 향상과 함께 기술 쇠퇴(skill atrophy) 위험을 초래함
    • 기술 쇠퇴는 사용 부족이나 연습 부재로 인해 시간이 지남에 따라 기술이 약화되는 현상을 의미함
  • 반복적 작업을 AI에 맡기는 것은 유익할 수 있지만, 과도하면 핵심 능력 상실로 이어질 수 있음
  • 인지적 오프로드(cognitive offloading) 현상으로 인해, 문서나 튜토리얼을 스스로 학습하는 대신 AI에 의존하는 경향이 강해짐
  • 예를 들어, GPS 사용이 길 찾기 능력을 약화시킨 것처럼, AI 자동완성과 코드 생성 기능이 사고력을 저하시킬 수 있음
  • AI가 보일러플레이트 코드를 처리해줌으로써 대규모 프로젝트에 도전할 수 있는 기회가 생겼지만, 자동화와 기술 쇠퇴 사이 경계 설정이 중요함

비판적 사고가 희생양이 되고 있는가?

  • Microsoft와 Carnegie Mellon 연구팀의 2025년 연구에 따르면, AI 의존도가 높을수록 비판적 사고 감소 현상이 발생함
  • AI에 대한 과신은 사람들이 스스로 사고하는 대신 자동 조종 상태로 전환하게 만듦
  • 쉬운 작업일수록 더욱 경계를 풀게 되고, 이로 인해 장기적인 독립 문제 해결 능력 감소가 초래됨
  • AI 도움을 받는 작업자는 동일 문제에 대해 덜 다양한 해결책을 제시하는 경향이 있으며, 이는 사고력 균질화로 이어짐
  • 연구진은 이를 비판적 사고의 저하로 정의함
  • 비판적 사고를 저해하는 장벽들
    • 인지적 장벽: 반복적인 작업일수록 AI에 과도하게 의존하는 경향
    • 동기적 장벽: 시간 압박이나 직무 범위 제약으로 깊은 사고를 회피하게 됨
    • 능력적 장벽: AI의 답변을 스스로 검증하거나 개선하는 데 어려움을 느낌
  • 한 엔지니어는 12년 경력에도 불구하고 AI의 즉각적 도움으로 인해 스스로를 더 못하는 개발자로 느끼게 되었음을 고백함
    • 문서 읽기 중단: LLM이 즉각 설명해주기 때문에 공식 문서를 읽을 필요성을 느끼지 않음
    • 디버깅 능력 감소: 스택 트레이스나 에러 메시지를 직접 분석하는 대신 AI에 복붙하여 해결하려 함
    • 깊이 있는 이해 상실: 문제를 진정으로 이해하려는 노력 없이 AI 제안만 반복 적용하게 됨
    • 감정적 반응 변화: 과거에는 버그를 해결하는 데서 얻던 기쁨이, 이제는 AI가 5분 안에 답을 못 주면 좌절로 바뀜
  • LLM에게 사고를 위탁하면서, 개발자는 장기적 숙련도를 잃고 단기적 편리성을 얻는 교환을 하게 됨"우리는 AI 덕분에 10배 개발자가 된 것이 아니라, AI에 10배 더 의존하게 된 것"
    "우리가 스스로 해결할 수 있는 문제 AI가 해결하도록 할 때마다, 우리는 장기적인 이해 단기적인 생산성으로 바꾸고 있음"

기술 쇠퇴의 미묘한 징후들

  • AI 의존이 단순한 가설이 아니라 실제로 개발 기술의 약화로 이어질 수 있음
  • 몇 가지 뚜렷한 징후를 통해 자신의 기술 쇠퇴 여부를 점검할 수 있음
  • 디버깅 포기 현상
    • 에러가 발생할 때 디버거를 사용하거나 스택 트레이스를 직접 읽지 않고, 바로 AI에 의존하는 경향
    • 과거에는 버그를 직접 분석하고 해결하면서 성장했지만, 이제는 그 과정을 AI에 전가하는 경우가 많아짐
    • AI가 해결하지 못하거나 사용할 수 없는 상황에서는, 기본적인 문제 진단조차 어려운 상태에 빠질 위험이 있음
  • 이해 없이 복붙하는 코딩
    • 보일러플레이트 코드를 AI가 작성하는 것은 괜찮지만,  그렇게 동작하는지 이해하지 못한 채 복사하여 사용하는 경우 문제 발생
    • 특히 젊은 개발자들은 AI 덕분에 빠르게 코드를 작성하지만, 그 선택의 이유나 예외 처리 방식을 설명하지 못하는 경우가 많음
    • 다양한 대안을 고민하는 과정이 사라지면서 기초적인 사고 훈련이 결여됨
  • 아키텍처 및 시스템적 사고력 약화
    • 복잡한 시스템 설계는 단일 프롬프트로 해결할 수 없음
    • 작은 문제를 AI로 해결하는 데 익숙해지면, 고차원적 설계 작업에 대한 두려움이나 회피가 생길 수 있음
    • AI는 특정 컴포넌트나 패턴을 제안할 수 있지만, 성능, 보안, 유지보수성 등 전체 맥락을 이해하는 것은 개발자 본인의 몫임
    • 시스템 수준 사고력을 사용하지 않으면 점차 약화됨
  • 기억력 및 회상력 감소
    • 자주 쓰는 API 호출이나 언어 문법조차 기억이 흐려질 수 있음
    • AI 자동완성 기능에 익숙해지면서, 스스로 코드를 작성하는 능력이 약화됨
    • 이는 수학 계산기를 지나치게 의존하는 학생처럼, 기본 계산 능력 상실에 비유할 수 있음
  • 시간이 흐름에 따라 일부 기술이 자연스럽게 사라지는 것은 정상적인 현상임
    • 예를 들어, 어셈블리어로 메모리를 직접 관리하거나, 손으로 긴 나눗셈을 하는 능력은 더 이상 필수적이지 않음
    • 하지만 어떤 기술은 유지해야 하고, 어떤 기술은 버려도 되는지 구분하는 것이 중요함
    • 긴급 상황에서 디버깅할 수 있는 능력은 여전히 필수 기술로 간주해야 함
    속도와 지식의 트레이드오프:
    AI는 빠른 답을 제공하지만 (높은 속도, 낮은 학습),
    전통적인 방법(Stack Overflow, 공식 문서)은 느리지만 깊은 이해를 구축해줌
  • 즉각적 답변을 좇다가, 진정한 전문가로 성장하는 데 필요한 맥락 이해와 깊이를 놓칠 위험이 있음

AI 과의존의 장기적 위험

  • AI 도구에 대한 과도한 의존이 통제되지 않을 경우, 경력상 비판적 사고 위기에 직면할 가능성이 있음
  • AI가 대부분의 사고 과정을 대신하게 되면, 도구가 실패하거나 해결하지 못하는 문제에 대해 스스로 대응할 능력을 잃게 됨"AI를 많이 쓸수록 뇌를 덜 쓰게 됩니다. 그러면 AI가 해결할 수 없는 문제에 부딪혔을 때, 당신은 스스로 해결할 수 있는 기술이 있을까요?"
  • 실제로 AI 코딩 도우미 장애로 개발자들의 워크플로우가 완전히 멈춘 사례도 발생함
  • 자기 실현적 예언(Self-Fulfilling Prophecy)
    • Microsoft 연구팀은 AI에 의한 직업 상실을 걱정하면서도 "무비판적(uncritically)으로 AI를 사용"할 경우, 스스로 경쟁력을 잃게 될 수 있음을 경고함
    • 특히 신입 개발자들은 "어려운 길"을 건너뛰고 빠른 생산성에만 집중하여, 심화 학습 없이 조기에 성장 정체에 빠질 위험이 있음
    • 결과적으로, 스스로 문제를 해결하는 기쁨이나 깊은 이해를 경험해보지 못한 버튼 누르는 인력(button-pushers) 집단이 생겨날 수 있음
    • 이들은 AI에게 질문하는 방법은 능숙할지 몰라도, 정답을 진정으로 이해하지 못하는 상황에 빠질 수 있음
    • AI가 사소하게 틀렸을 때 그 오류를 발견하지 못하고, 버그나 보안 취약점이 코드에 섞여 들어가는 문제도 발생할 수 있음
  • 팀 문화와 조직 역동성
    • 모든 개발자가 AI 도우미만 사용하게 되면, 멘토십 비공식적 학습(osmosis learning) 이 약화될 수 있음
    • 주니어 개발자들이 동료 대신 AI에 의존하면, 시니어 개발자들이 지식을 전수하기 어려워짐
    • 기초가 약한 주니어들이 많아질 경우, 시니어들은 AI가 만들어낸 오류를 고치는 데 시간을 소모하게 됨
    • 결국 팀은 개별 구성원이 AI에 의존하는 집합체로 전락할 수 있으며, 비판적 리뷰나 공동 품질 유지 문화가 사라질 수 있음
    • 버스 팩터(bus factor) 에 사실상 "AI 서비스 장애"도 포함이 가능함
      • "프로젝트가 무너지려면 몇 명이 버스에 치여야 할까?"
  • 아날로그 방식으로 돌아가자는 것이 아니라, AI를 신중하게 사용해야 한다는 경고
    • AI를 활용하면서도, 작업 그 자체뿐 아니라 사고력 자체까지 아웃소싱하지 않도록 주의해야 함
    • 목표는 AI의 혜택을 최대한 누리되, 동시에 자기 자신의 기술과 사고력을 견고히 유지하는 것

AI를 목발이 아닌 협력자로 사용하기

  • AI 코딩 도우미의 생산성 향상을 누리면서도, 사고력과 기술을 유지하기 위해서는 의식적인 사용 습관이 필요함
  • AI를 전능한 답변자가 아니라, 주니어 페어 프로그래머 러버덕 디버깅 파트너처럼 대해야 함
  • 다음은 고려해봐야할 구체적 실천 전략들
  • "AI hygiene(위생)" 실천 – 항상 검증하고 이해하기
    • AI의 결과물이 그럴듯해 보여도 무조건 신뢰하지 않고 검증하는 습관을 들여야 함
    • AI가 생성한 함수나 코드에 대해 의도적 테스트를 수행하고, 엣지 케이스를 찾아야 함
    • "왜 이 솔루션이 작동하는가?", "한계는 무엇인가?"를 스스로 질문함
    • AI에게 코드를 줄 단위로 설명하거나 대안 접근법을 요청해 학습에 활용함
    • AI의 답변을 심문하면 수동적인 답변을 능동적인 교훈으로 바꿀 수 있음
  • 기본기 훈련 – 때로는 고생도 필요함
    • 매주 일정 시간을 "AI 없는 코딩시간" 으로 설정하여 순수한 수작업으로 문제를 해결하는 시간 확보
    • 경험 많은 개발자들은 "No-AI Day" 를 지정하여 직접 코드 작성, 에러 분석, 문서 검색을 실천함
    • 초기에는 느리고 답답하지만, 시간이 지나면서 자신감과 깊이 있는 이해를 회복할 수 있음
    • AI 없이 꾸준히 코딩하면 기본 실력이 엔트로피로 떨어지는 것을 방지할 수 있음
    • 이는 개발자 두뇌를 위한 크로스 트레이닝과 같음
  • AI한테 묻기전에 문제에 스스로 먼저 도전하기
    • 문제를 접했을 때 곧바로 AI에 묻지 않고, 먼저 접근 방법을 고민
    • 최소한 의사 코드(pseudocode) 나 간단한 아이디어라도 스스로 세워본 후 AI를 활용함
    • 버그가 발생하면 최소 15~30분 정도는 스스로 디버깅해보는 시간을 갖기
    • 이러면 문제 해결 능력을 키울 수 있으며, AI 답변과 자신의 접근법을 비교하며 능동적으로 학습이 가능
  • AI를 사용하여 코드 검토를 대체하는 것이 아니라 증강하기
    • AI가 생성한 코드도 인간 동료가 작성한 것처럼 철저히 리뷰
    • 가능하다면 AI 코드에 대해 인간 코드 리뷰를 병행하여 팀 차원의 품질을 유지함
    • 이를 통해 팀 지식을 루프에 유지하고, AI를 신뢰할 때 단독 개발자가 놓칠 수 있는 문제를 포착함
    • 이는 "AI가 초안을 만들 수는 있지만, 우리가 코드를 소유한다"는 태도를 장려
    • 누가 작성했는지에 관계없이 팀이 저장소에 있는 모든 코드를 이해하고 유지관리 할 책임이 있음
  • 능동적 학습 – 후속 질문과 반복 학습
    • AI가 제시한 솔루션이 잘 작동해도, 그 자리에서 학습을 강화하는 시간을 가짐
    • 복잡한 정규 표현식이나 알고리듬을 AI로 작성한 경우, 그 구조를 스스로 설명하거나, AI에 왜 이 방법을 썼는지 질문
    • AI를 단순 답변 제공자가 아니라, 무한 인내심을 가진 튜터처럼 대화형으로 활용함
      • ChatGPT가 생성한 코드에 대해 "왜 이 방법은 안 돼?" 라고 묻기
    • 이렇게 하면 AI는 단순한 코드 배포자가 아닌 멘토가 됨
  • 학습 일지 및 "AI 어시스트" 목록을 기록하기
    • AI에 반복적으로 묻는 주제를 기록하여 지식 공백을 파악함
    • 예를 들어, CSS에서 div 정렬이나 SQL 쿼리 최적화를 반복해서 묻는다면, 해당 주제를 집중 학습함
    • 플래시카드나 짧은 연습 문제를 만들어 반복 학습하여 장기 기억으로 전환함
    • 다음에 비슷한 문제에 직면하게 되면 AI 없이 문제를 풀어보고 그 방법을 기억하는지 확인해 볼 것
    • AI를 첫 번째 해결책이 아닌, 마지막 안전망으로 사용하는 태도를 유지함
  • AI와 페어 프로그래밍하기
    • AI를 질문 처리 API처럼 대하는 대신, 페어 프로그래밍 파트너처럼 대화함
    • 예를 들어, 내가 함수 초안을 작성하고 AI에게 개선점을 제안받거나, 반대로 AI가 초안을 작성하면 내가 수정함
    • 대화 예시: "이 함수는 작동하는데, 더 명확하게 리팩토링할 방법이 있을까?"
    • 이렇게 하면 당신이 운전석에 앉아있게 함. 단순히 답변을 소비하는게 아니라, AI가 기여할 수 있도록 큐레이션하고 지시
    • AI를 감독이 필요한 주니어 개발자로 취급하고, 최종 책임자는 인간 개발자임을 명확히 함
  • 이런 습관을 통해 AI 사용은 순수한 이득이 되며, 스스로의 능력도 잃지 않게 됨
  • 실제로 AI를 활용하여 생소한 코드를 설명하거나, 복잡한 케이스로 AI를 시험하는 과정은 개인 기술 향상에도 매우 유익함
  • 예를 들어, AI를 사용하여 익숙하지 않은 코드를 설명하면 지식을 심화할 수 있고, 까다로운 사례로 AI를 당황하게 만들면 테스트 사고방식을 향상시킬 수 있음
  • 핵심은 수동적 소비자가 아니라 능동적 사용자로 남는 것임

결론: 날카로움을 유지하기

  • 소프트웨어 산업은 AI 기반 코드 생성의 시대를 향해 가속 중이며, 이제 되돌릴 수 없는 흐름이 됨
  • 이러한 도구를 받아들이는 것은 불가피할 뿐만 아니라, 대체로 이득이 되는 일
  • 그러나 AI를 워크플로우에 통합하면서, 각자 기계에게 양보할 것과 스스로 유지해야 할 것 사이에서 신중한 선택이 필요함
  • 코딩을 사랑한다면, 단순히 빠르게 기능을 출시하는 것뿐 아니라, 문제를 해결하는 장인정신과 즐거움도 유지해야 함
  • AI를 능력 증폭기(amplifier) 로 활용하되, 대체자(replacement) 로 만들지 말아야 함
  • AI가 반복 작업을 대신할 수 있도록 하고, 그 freed-up 시간을 창의적이고 복잡한 작업에 투자함
  • 그러나 기초 기술이 퇴화하지 않도록 주의해야 하며, 항상 "어떻게"와 "왜"를 탐구하는 호기심을 유지해야 함
  • 디버깅 본능 시스템 사고력을 계속 갈고닦아야 하며, AI가 제시하는 지름길만 탐색해서는 안 됨
  • "간단히 말해서, AI를 당신의 목발이 아닌 협력자로 삼을 것"
  • 성공하는 개발자는 인간적 직관과 경험을 AI의 초능력과 조화롭게 결합할 줄 아는 사람일 것임
    • autopilot이 있거나/없거나 상관없이 코드베이스를 탐색할 줄 아는
  • 자기주도적 연습과 도전을 통해, fancy한 도구가 실패하거나 새로운 문제에 직면해도 스스로 문제를 해결할 수 있어야 함
  • "AI가 당신을 대체할까봐 걱정하지 말고, 당신을 대체 불가능하게 만드는 기술을 키우지 않는 것에 대해 걱정할 것"
  • "AI가 제공하는 답변을, 엔지니어의 마음으로 이해해야 한다"는 원칙을 항상 지키면, AI 열풍에 타면서도 쓸려가지 않을 것
  • 보너스
    • 다음에 AI가 기능 전체를 코딩해줄 때 유혹을 느낀다면, 스스로 직접 일부를 작성해보라는 신호로 받아들여야 함
    • 놀랍게도 많은 것을 기억하고 있고, 다시 직접 손으로 코딩하는 기쁨을 느낄 수 있음
    • AI를 생산성 향상의 도구로 삼되, 능동적으로 기술을 연마하는 습관을 절대 멈추지 말아야 함

최고의 미래 개발자는, 오늘날의 AI로 인해, 스스로 생각하는 법을 잊지 않은 사람이 될 것임

반응형
반응형

내가 싫어했던 매니저가 나에게 가르쳐준 교훈 

https://www.blog4ems.com/p/the-manager-i-hated

 

The manager I hated and the lesson he taught me

How a tough manager changed my approach to leadership (and why I’m grateful now)

www.blog4ems.com

  • 지금은 엔지니어링 매니저가 되었지만 내가 소프트웨어 엔지니어로 일하던 시절, 복잡한 기능을 며칠간 작업해 PR를 올렸음
  • 피드백은 단호하고 냉정했음 “오버 엔지니어링임. 복잡함. 리팩토링하시오”는 간단한 문장이 전부였음
  • 칭찬 한마디 없이 비판만 받은 경험에 분노했으나, 그 매니저와의 일화는 단지 시작에 불과했음

감정을 배려하지 않는 리더 스타일

  • 이 매니저는 기존에 알고 있던 리더들과 달랐음
  • 손을 잡아주지도, 부드러운 말도 하지 않음
  • 다음과 같은 특징이 있었음
    • 설익은 아이디어는 바로 거절함
    • 복잡함을 위한 복잡함을 싫어함
    • 깔끔하고 유지 보수 가능한 효율적인 코드만 중요시함
  • 회고에서도 돌려 말하지 않고 문제를 직접 지적함
  • 처음에는 냉혹한 성격이라 생각했지만, 그 이면에는 다른 철학이 있었음

자존심을 흔든 피드백의 전환점

  • 스프린트 리뷰에서 자신 있는 기능을 시연했지만 매니저는 중간에 끊고 물음“이건 취약해. 부하 상황에선 어떻게 돼? 롤백 계획은?”
  • 대답을 제대로 하지 못하자 매니저는 말함:“지금 넌 코더처럼 생각하고 있어. 엔지니어처럼 생각해야 해”
  • 처음엔 화났지만, 결국 스스로의 코드 스타일이 회복력보다는 영리함에 치중했다는 걸 자각하게 됨

진짜 교훈: 그 매니저는 나를 개인적으로 공격한 게 아니었음

  • 사고방식에 큰 변화가 생김
    • “똑똑한” 코드 대신 읽기 쉬운 코드를 작성함
    • 실패 상황을 대비한 설계에 집중함
    • 본인을 위한 코드가 아니라 후속 개발자를 위한 코드를 작성함
  • 이후 그 매니저의 코드 리뷰는 거침없이 통과됨
  • 매니저가 달라진 게 아니라, 나 자신이 성장했기 때문임

내 리더십 스타일에 남긴 영향

  • 엔지니어링 매니저가 된 후 그 경험을 많이 떠올렸음
  • 사람들이 싫어하는 리더는 되고 싶지 않았지만, 부드럽기만 한 리더도 되고 싶지 않았음
  • 다음과 같은 방식으로 스타일을 정립함
    • 배경 설명이 있는 직설적인 피드백을 줌
    • 시스템적 사고를 강조함
    • 높은 기준은 유지하되 인간적인 피드백을 제공함
  • 엔지니어들은 도전받는 걸 원하지만 무시당하는 느낌은 싫어함

단호한 매니저가 필요할 때

  • 리더십에는 자존심, 마감, 압박이 얽혀 있어 혼란스러움
  • 단호한 매니저는 다음을 통해 이 혼란을 걷어냄
    • 기능이 아닌 확장성을 생각하게 함
    • 영리한 코드보다 유지 가능한 코드를 쓰게 함
    • 실패와 예외 상황을 미리 대비하게 함
  • 감정보다 코드의 생존 가능성을 더 중요하게 여김

단호한 매니저 아래에서 생존하고 성장하는 방법

  • 숨 막히는 리더 아래에 있다면 다음과 같이 대처할 수 있음
    • 개인적인 공격으로 받아들이지 말 것: 피드백은 코드에 대한 것
    • 피드백 이후 “왜?”를 물어볼 것: 대부분 단호한 리더는 호기심을 존중함
    • 실패 지점을 스스로 먼저 생각해 볼 것: 매니저처럼 사고하기 시작해야 함
  • 리더라면 다음을 실천해야 함
    • 높은 기준을 제시하되, 그 기준이 중요한 이유를 설명할 것
    • 모호한 피드백 대신 구체적으로 말할 것
    • 성공보다 성장을 축하할 것: 개발자가 매니저보다 먼저 문제를 포착했다면 칭찬할 것

거절된 Pull Request가 준 최고의 선물

  • 처음엔 자존심이 상했지만, 지금 돌아보면 그 거절된 PR은 인생 최고의 기회였음
  • 코딩을 개인 프로젝트가 아닌 시스템 구축으로 보게 되는 계기였음
  • 단호한 매니저는 기분을 좋게 해주진 않지만, 개발자로서 성장하게 함
  • 진정한 성장은 PR이 통과될 때가 아니라, 거절될 때 시작됨

 

저는 여전히 소프트웨어 엔지니어였습니다.

모든 것은 코드 리뷰에서 시작되었습니다.

며칠 동안 복잡한 기능을 작업했습니다. 수백 줄의 코드, 엣지 케이스 처리, 성능 조정까지 완료했습니다. 저는 그것이 자랑스러웠습니다. "풀 리퀘스트 생성"을 누르고 피드백을 기다렸습니다. 아마도 한두 개의 댓글 정도를 예상했습니다.

제가 받은 것은 잔혹했습니다.

"오버 엔지니어링. 너무 많은 움직이는 부분. 리팩토링."

그게 전부였습니다. "잘 했어요"도, "좋은 시도였어요"도 없었습니다. 그냥 단호한 중단이었습니다.

저는 화가 나서 앉아 있었습니다. '이 사람은 사람들을 깎아내리는 걸 즐기는 걸까?'라고 생각했습니다.

하지만 이건 시작에 불과했습니다.

내 감정 따위는 신경 쓰지 않는 매니저

그는 제가 함께 일했던 다른 리더들과는 달랐습니다.

어떤 손길도, 허세도 없었습니다.

그는 반쯤 익은 아이디어를 눈 하나 깜짝하지 않고 거절했습니다.

그는 영리함을 위한 복잡성을 혐오했습니다.

그는 한 가지, 즉 깨끗하고 유지 보수 가능하며 효율적인 코드에만 관심이 있었습니다.

스프린트 회고에서 그는 상황을 미화하지 않았습니다. 마감일을 놓쳤나요? 그는 "우리가 범위를 잘못 잡았어. 고치자."라고 말했습니다. 확장성이 없는 것을 만들었나요? "그건 기술 부채야. 감당할 수 없어."라고 말했습니다.

처음에는 그가 그저 엔지니어를 불행하게 만드는 그런 매니저라고 생각했습니다. 하지만 더 깊은 무언가가 있었습니다.

이런 게시물을 즐겨 읽으신다면, 제 작업을 지원하고 이 뉴스레터를 구독해 보세요.

무료 구독자는 다음을 얻습니다.

  • ✉️ 주간 게시물 1개
  • 🧑‍🎓 엔지니어링 매니저 마스터클래스 이용 권한

유료 구독자는 다음을 얻습니다.

  • 🔒 50개 이상의 템플릿과 플레이북 (79달러 상당)
  • 🔒 EM이 직면하는 실제 과제에서 나오는 주간 "당신이라면 어떻게 하시겠어요?" 시나리오 및 분석
  • 🔒 전체 아카이브에 대한 완전한 액세스 권한 고성능 팀을 만드는 것에 대한 주간 기사를 읽는 최고의 엔지니어링 리더들과 함께 하세요!

구독하기

모든 것을 바꿔놓은 자아 점검

결정적인 순간은 스프린트 리뷰 중에 찾아왔습니다.

저는 그에게 깊은 인상을 줄 것이라고 확신했던 기능을 시연했습니다. 대신 그는 중간에 저를 끊었습니다.

"이건 약해. 부하가 걸리면 어떻게 되지? 롤백 계획은?"

저는 답을 찾기 위해 더듬거렸지만 제대로 된 답이 없었습니다. 그는 잠시 멈추더니 말했습니다. "당신은 코더처럼 생각하고 있어, 엔지니어처럼 생각하고 있지 않아. 실패를 견딜 수 있는 것을 만들어."

그것은 저에게 힘든 순간이었습니다.

저는 밤새도록 그 말을 곱씹었습니다. 처음에는 화가 났습니다. 하지만 생각할수록 그가 옳다는 것을 깨달았습니다. 저는 회복력이 있는 해결책이 아닌 영리한 해결책에 너무 집중하고 있었습니다.

진정한 교훈: 그것은 나에 대한 것이 아니었다

저는 제 일에 접근하는 방식을 바꾸기 시작했습니다.

저는 "똑똑한" 코드를 쓰는 것을 멈추고 읽기 쉬운 코드를 쓰기 시작했습니다.

저는 이상적인 경우뿐만 아니라 실패 시나리오를 염두에 두고 설계했습니다.

저는 저 자신을 위해 코딩하는 것을 멈추고 다음에 제 코드베이스를 건드릴 사람을 위해 코딩하기 시작했습니다.

그리고 놀라운 일이 일어났습니다.

그가 검토하는 제 풀 리퀘스트가 막힘없이 통과되기 시작했습니다.

그가 부드러워진 것이 아니었습니다. 제가 마침내 성장한 것입니다.

그것이 제 자신의 리더십 스타일에 미친 영향

제가 결국 엔지니어링 매니저가 되었을 때, 저는 그 경험에 대해 많은 생각을 했습니다.

저는 사람들이 싫어하는 그런 리더가 되고 싶지 않았습니다. 하지만 부드럽기만 한 리더도 되고 싶지 않았습니다.

그래서 저는 효과가 있었던 부분을 훔쳤습니다.

  • 맥락이 뒷받침되는 잔혹할 정도의 솔직함. "이건 엉망이야"라고 말하는 대신 "이건 숨겨진 기술 부채를 만들어. 이유는 이거야."라고 말합니다.
  • 시스템 사고에 집중. 저는 엔지니어들에게 그들의 티켓을 넘어 그들의 코드가 더 큰 그림에 어떻게 들어맞는지 생각하도록 밀어붙입니다.
  • 높은 기준, 하지만 인간적인 피드백. 저는 단지 결함을 지적하는 것이 아니라 나아갈 길을 제시합니다.

저는 엔지니어가 도전을 원하지만, 그 과정에서 무시당하는 느낌을 받고 싶어하지 않는다는 것을 알게 되었습니다.

왜 터프한 엔지니어링 매니저가 당신에게 꼭 필요한 존재일 수 있는가

리더십은 엉망진창입니다. 자아, 자존심, 마감일, 그리고 압박이 있습니다.

터프한 매니저는 그 소음을 뚫고 나아갑니다. 그들은:

  • 기능뿐만 아니라 확장성에 대해 생각하도록 강요합니다.
  • 영리한 코드뿐만 아니라 유지 보수가 가능한 코드를 작성하도록 밀어붙입니다.
  • 엣지 케이스와 실패는 일어날 것이기 때문에 그것들을 계획하도록 가르칩니다.

이러한 매니저들은 당신이 어떻게 느끼는지보다는 당신의 코드가 프로덕션 환경에서 살아남을 수 있을지에 더 관심을 가집니다. 그리고 그것은 나쁜 것이 아닙니다.

터프한 매니저 밑에서 살아남고 번성하는 방법

만약 당신이 현재 목덜미에 숨결을 불어넣는 것처럼 느껴지는 매니저 밑에 있다면, 이것이 효과를 발휘하게 만드는 방법입니다.

  • 개인적으로 받아들이지 마세요. 피드백이 코드에 대한 것이라면, 그것은 당신에 대한 것이 아닙니다.
  • 모든 피드백 후에 "왜"를 물어보세요. 대부분의 터프한 매니저는 호기심을 존중합니다.
  • 그들이 지적하기 전에 실패 지점을 예측하세요. 그들이 하는 것처럼 생각하기 시작하세요.

만약 당신이 엔지니어를 관리하고 있다면:

  • 기준을 높게 설정하되, 무엇이 걸려 있는지 설명하세요. 엔지니어는 높은 기준이 왜 중요한지 알 때 그것을 존중합니다.
  • 피드백을 구체적으로 하세요. 모호한 비판은 사람들을 좌절시킵니다. 요점을 말하세요.
  • 성공뿐만 아니라 성장을 축하하세요. 누군가가 당신보다 먼저 문제를 발견하는 첫 번째 순간은요? 그것을 칭찬하세요.

내가 거절당해서 기쁜 풀 리퀘스트

그 잔혹했던 풀 리퀘스트를 돌이켜보면, 그것은 엔지니어로서 저에게 일어난 최고의 일 중 하나였다고 말할 수 있습니다.

그것은 제가 코딩을 개인적인 예술 프로젝트로 취급하는 것을 멈추고 시스템 구축자처럼 생각하기 시작하도록 강요했습니다. 엔지니어처럼요.

터프한 매니저는 당신을 기분 좋게 만들지는 않을 것입니다. 하지만 그들은 당신을 더 나은 존재로 만들 것입니다. 그리고 당신이 당신의 자아를 넘어서면, 그들이 당신에게 남기는 교훈은 당신의 경력 전체에 걸쳐 지속될 것입니다.

때때로, 최고의 PR은 거절당하는 PR입니다. 왜냐하면 그곳이 진정한 성장이 일어나는 곳이기 때문입니다.

 

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

반응형
반응형

https://www.cio.com/article/3950506/%ec%a0%95%ec%b2%a0%ed%99%98-%ec%b9%bc%eb%9f%bc-%ec%bd%94%eb%94%a9%eb%a7%8c-%ec%9e%98%ed%95%98%eb%a9%b4-%eb%90%a0%ea%b9%8c-%eb%af%b8%eb%9e%98%ec%9d%98-%ea%b0%9c%eb%b0%9c%ec%9e%90%ea%b0%80-%ea%b0%96.html

 

정철환 칼럼 | 코딩만 잘하면 될까? 미래의 개발자가 갖춰야 할 역량

미래의 개발자는 단순한 프로그램 코딩을 넘어서, 해결하고자 하는 도메인의 문제 해결자로 거듭나야 한다. 즉 단순한 ‘코드 작성자’가 아니라, 문제를 해결하고 가치를 창출하는 전략적 사

www.cio.com

미래의 개발자는 단순한 프로그램 코딩을 넘어서, 해결하고자 하는 도메인의 문제 해결자로 거듭나야 한다. 즉 단순한 ‘코드 작성자’가 아니라, 문제를 해결하고 가치를 창출하는 전략적 사고를 가진 전문가가 되어야 한다.


오래전, 아마도 1990년대로 기억하는 시기에 우리나라 최초의 SI기업이었던 쌍용정보통신의 대표가 신문에 기고했던 칼럼의 내용이 아주 인상깊게 각인이 된 적이 있다. 요약하면 ‘후진국은 저렴한 임금을 무기로 선진국과 제조업 경쟁에서 우위를 가지고 성장했지만 제조업 종사자의 개인별 생산성 측면에서는 선진국이 후진국보다 경쟁력이 높다. 하지만 제조업에서의 개인별 생산성 차이는 커야 두세배에 지나지 않는다. 임금이 1/10이라면 비록 후진국의 개인별 생산성이 뒤져도 비용대비 생산성은 충분한 경쟁력이 나온다. 하지만 소프트웨어 분야에서는 그렇지 않다. 후진국과 선진국 개발자의 생산성 차이가 많게는 100배 이상도 날 수 있기 때문이다. 따라서 소프트웨어 산업은 저렴한 임금을 무기로 후진국이 선진국을 따라잡을 수 없다’라는 내용이다.

여전히 미국은 세계 최고의 경쟁력을 가진 소프트웨어 강국이다. 실리콘밸리의 임금 수준은 세계 최고 수준을 자랑하지만 여전히 강력한 경쟁력을 유지하고 있다. 이는 미국 소프트웨어 기업의 개발자 수준이 세계 최고이기 때문이다. 하지만 미래는 어떻게 될까?

지금까지 개발자의 실력을 좌우하는 것은 코딩 실력이라고 생각돼 왔다. 즉 ‘코딩을 잘하는 개발자’가 개발자로의 성공의 중요한 조건이었지만, IT 산업이 빠르게 변화하면서 이제는 그 이상이 요구되고 있다. 단순히 뛰어난 코딩 실력만으로는 우수한 개발자가 되는 것은 고사하고 살아남기조차 어려운 시대가 오고 있는 것이다. 그렇다면 미래의 개발자는 어떤 역량을 갖춰야 할까?


우선 문제 해결 능력과 논리적 사고력을 강화해야 한다. 1990년대 클라이언트/서버 붐이 한창이던 시절 갑작스러운 개발자 수요 폭발로 인해 초급 개발자를 구하는 것이 매우 어려운 시절이 있었다. 그때 회자되었던 농담이 ‘개발자의 전공 중 제일 많은 비중을 차지하는 것인 불문과다’라는 것이다. 개발자 채용에 대부분의 기업이 ‘전공 불문’ 이라는 조건을 달았기 때문이었다.

그래서 당시 유명했던 비트컴퓨터 학원의 6개월 개발자 과정을 이수한 인력들이 개발 시장에 많이 투입되었다. 이들은 프로그램 코딩의 문법과 작성에 대해 잘 배웠지만 실전에서 보면 컴퓨터공학이나 전산학을 전공한 인력과 분명한 차이가 있었다.

프로그램 코딩이 단순히 문법을 익히는 것이 아니라 논리를 구현하는 작업인 것처럼, 개발자에게는 문제 해결 능력이 필수적이다. 단순히 요구사항을 구현하는 것이 아니라, 문제의 본질을 파악하고 최적의 해결책을 찾는 능력이 중요하다. 이를 위해 알고리즘, 데이터 구조, 디자인 패턴 등 기본 CS 지식은 여전히 강력한 무기다. 이런 기본적인 배경 지식이 있는 것과 없는 것은 장기적으로 분명한 차이를 가져온다. 이를 위해 개발자는 알고리즘 & 데이터 구조 학습, 시스템 설계, 문제 해결 역량 등을 강화하여야 한다.


다음으로 커뮤니케이션과 협업 능력이 중요하다. 과거에는 개발자가 코드만 작성하면 됐지만, 이제는 기획자, 디자이너, 마케팅 팀과의 협업이 필수적이다. 특히 생성형 인공지능의 발전으로 단순 코딩 영역이 점차 자동화되는 상황으로 발전하는 상황에서 개발자의 역할이 단순한 ‘기능 구현자’에서 ‘문제 해결사’로 확장되면서, 비개발자와 원활하게 소통하는 능력이 중요해지고 있다. 이와 관련하여 코드 리뷰, 기술 문서 작성, 프레젠테이션 등의 소통 스킬도 필수적이다.

또한 생성형 인공지능 기반의 자동화된 코딩 시대가 오면 개발자의 실력을 차별화할 수 있는 핵심 역량은 시스템 개발과 관련된 업무 도메인 지식과 비즈니스 이해력이 될 수 있다. 기술은 결국 특정 문제를 해결하기 위한 도구일 뿐이다. 개발자가 자신이 속한 산업(예: 제조, 금융, 헬스케어, 커머스 등)에 대한 이해가 깊을수록, 더 가치 있는 솔루션을 제공할 수 있다. 즉 단순히 ‘어떻게 개발할까?’가 아니라, ‘왜 이 기능이 필요한가?’를 고민할 줄 아는 개발자가 경쟁력을 갖게 된다. 이러한 역량을 키우기 위해서는 특정 산업의 동향 분석, 데이터 기반 의사결정 역랑을 강화해야 할 것이다.

그리고 1990년대부터 지금까지 변하지 않는 중요한 개발자의 역량은 지속적인 학습 능력 및 기술 트렌드에 대한 파악 노력이다. IT분야의 기술은 빠르게 변하고, 현재 주류인 기술이 몇 년 후면 사라질 수도 있다. 그렇기 때문에 IT분야 대학교수들 사이에서 수학이나 물리 심지어 역사학 분야의 교수들을 부러워한다는 우스개 소리도 있는 이유일 것이다. 이와 관련하여 새로운 언어나 프레임워크가 등장했을 때 빠르게 적응할 수 있는 능력도 중요하다. 이러한 역량을 키우기 위해서는 유명한 기술 블로그 구독, 사이드 프로젝트 진행, 오픈소스 기여 등을 통해 가능하다.


‘피할 수 없으면 즐겨라’라는 말처럼 점점 발전하고 있는 생성형 인공지능 기술을 위협으로만 받아들이지 말고 적극적으로 자동화 및 생산성 도구를 활용하는 능력을 키워야 한다. 어차피 미래에는 개발자가 직접 코드를 작성하는 시간이 점점 줄어들게 될 것이기 때문이다. 또한 개발 환경의 대세가 되고 있는 CI/CD, 테스트 자동화, 코드 생성 AI(GitHub Copilot, ChatGPT) 등을 적극적으로 활용하면 개발자의 생산성을 크게 향상시킬 수 있다. 결국 단순 반복적인 업무를 자동화할 줄 아는 개발자가 더 높은 가치를 제공할 수 있다. 이를 위해 데브옵스 기본 개념, AI 코딩 도구 활용, 스크립트 자동화 등의 영역에 대한 역량을 키우는 것을 추천한다.

결국 미래의 개발자는 단순한 프로그램 코딩을 넘어서, 해결하고자 하는 도메인의 문제 해결자로 거듭나야 한다. 즉 단순한 ‘코드 작성자’가 아니라, 문제를 해결하고 가치를 창출하는 전략적 사고를 가진 전문가가 되어야 한다는 것이다. 뛰어난 개발 관련 기술력은 기본이고, 원활한 커뮤니케이션과 협업 능력, 비즈니스 이해력과 지속적인 학습 태도가 필수적이다.

당신은 어떤 개발자가 되고 싶은가?

반응형
반응형

일부 IT 리더들은 AI가 코드 작성에 더 능숙해지면서 소프트웨어 개발팀이 시니어 몇 명 수준으로 축소될 수 있다고 내다봤다.
 
초기 성과는 각기 다르지만, 결과는 분명해 보인다. 생성형 AI 코딩 어시스턴트가 소프트웨어 개발팀의 구성 방식을 바꾸고, QA와 주니어 개발자의 일자리는 위험에 처할 수 있다는 것이다. 

일부 IT 리더는 AI 어시스턴트가 코드 작성을 더 잘하게 되면서 CIO와 개발 리더들이 AI 전문가와 선임 개발자를 중심으로 팀을 재편해 AI 생성 코드를 감독하게 할 수 있다고 말했다.

클라이밋 테크 전략 어드바이저의 설립자이자 차량-그리드 간 애플리케이션 제공업체 페르마타 에너지의 전 개발팀장인 안나 데메오는 애플리케이션 개발팀이 더 간소화되고, 남은 시니어 개발자들이 제품 요구 사항을 소프트웨어 개발로 옮기는 일에 집중하게 될 것이라고 전망했다.

데메오는 특히 기업들이 AI 코딩 어시스턴트에 의존하면서 주니어 개발자, 인턴, 경우에 따라서는 제품 관리자의 역할을 AI로 대체할 것이라고 예상했다. 그는 “큰 팀에는 항상 A 플레이어와 B 플레이어가 있다. C 플레이어는 없길 바라지만 그들도 존재한다. AI는 어떤 면에서 C나 B 플레이어의 설 자리를 더 줄일 수 있다”라고 말했다. 

그는 남은 개발자들이 이제 비즈니스 요구사항을 이해하고 제품 전문가, 마케팅 부서, 기타 직원들과 교차 기능팀에서 활약할 수 있는 비판적 사고를 가져야 한다고 조언했다. 

‘편집자’로서의 개발자
데메오는 이미 일부 고객사가 AI를 중심으로 개발팀을 재편하고 있으며 시니어 개발자나 소프트웨어 아키텍트가 AI 생성 코드를 감독 및 수정하고 있다고 말했다. 그는 다양한 역할에 영향을 미치고 있는 이런 변화를 소설 출판 과정에 비유했다.

데메오는 “개발자는 더 이상 작가가 아니라 편집자다. 시니어 개발자는 콘텐츠와 독자가 누구인지, 다시 말해 고객이 누구이며 조직이 무엇을 달성하려고 하는지 이해해야 한다”라고 설명했다.

세일즈포스용 데브옵스 플랫폼 제공업체 코파도(Copade)의 에반젤리즘 담당 수석 부사장인 데이비드 브룩스는 미래의 개발팀이 제품 매니저 또는 비즈니스 분석가, UX 디자이너를 비롯해, AI 도구로 프로토타입을 생성한 다음 출시 준비가 될 때까지 코드를 조정하는 소프트웨어 아키텍트 등으로 구성될 것이라고 말했다. 그는 보안 및 규정 준수 검토 등의 나머지 소프트웨어 개발 역할을 AI가 담당할 가능성이 높다고 언급했다.

브룩스는 “언젠가는 현재의 소프트웨어 개발 일자리가 없어질 수 있다. 그렇다면 주니어 소프트웨어 개발자가 가장 먼저 피해를 볼 것"이라며 "소프트웨어 아키텍트는 코딩 대신 더 높은 수준의 시스템을 설계하며 AI가 생성한 솔루션을 확인하는 일을 주로 맡게 될 수 있다"라고 설명했다.

브룩스는 몇 가지 난관도 있다면서, 특히 다음 세대의 소프트웨어 아키텍트를 양성하는 일이 주요 과제라고 언급했다. 주니어 개발자 일자리가 줄어들면 더 높은 직급으로 자연스럽게 올라갈 수 있는 길인 도제식 교육도 이뤄질 수 없기 때문이다.

확산되고 있는 코딩 어시스턴트
개발팀 재편이 얼마나 빨리 이뤄질지는 불분명하지만, 깃허브가 최근 실시한 설문조사에 따르면 개발자들 사이에서 AI 코딩 어시스턴트의 사용은 이미 확산되고 있다. 4개국 개발자의 97% 이상이 직장에서 AI 코딩 어시스턴트를 사용한 적이 있다고 답했는데, 이는 코딩 어시스턴트가 오늘날 생성형 AI의 최대 인기 사용 사례 중 하나라는 업계의 관측과 일맥상통한다.

깃허브는 지난 1월 말 기준 코파일럿 코딩 어시스턴트 사용자가 130만 명으로 전 분기 대비 30% 증가했다고 밝혔다. 마이크로소프트에 따르면 지난 7월 말까지 7만 7,000개 이상의 조직에서 코파일럿을 도입했다.

한편 온라인 교육 제공업체 플루럴사이트의 최근 연구 결과에 따르면, 조사에 참여한 IT 전문가의 약 4분의 3이 AI로 인해 자신의 기술이 쓸모없게 될 것을 우려하고 있었다.

또한 일부 전문가는 많은 개발팀이 빠른 시일 내에 AI를 최대한 활용하기 위해 노력하는 상황에서 AI의 영향이 장기적으로 나타날 전망이라고 언급했다.

IT 컨설팅 및 서비스 제공업체 인텔리버스(Intelibus)의 설립자 에드 와탈은 기존 팀의 생산성을 높이고 AI 프롬프트 엔지니어링 기술을 구축하는 데 추가 코치가 필요하기 때문에 향후 1~2년 내에 개발팀 규모가 실제로 더 커질 수 있다고 말했다. 하지만 3명의 소프트웨어 엔지니어가 과거 5~6명이 하던 코딩 업무를 할 수 있기 때문에 장기적으로는 개발팀이 점점 더 축소될 것이라고 덧붙였다.

와탈은 더 많은 직원이 AI와 로우코드/노코드 도구를 사용해 애플리케이션을 작성하게 되면 기존 개발팀의 혼란이 가중될 수 있다면서, “직원들은 AI 생성 코드가 어떻게 작동하는지 깊이 이해하지 못할 수 있지만 코드를 작성할 역량은 충분하다”라고 언급했다.

많은 IT 리더들이 AI 코딩 어시스턴트가 궁극적으로 개발자 일자리를 줄일 것이라고 예측했지만, 일부 개발 리더들은 AI를 사용한 코드 작성과 디버깅이 현명한 방법인지 의문을 제기하기도 했다.

과대 평가된 장점?
코드 테스트 솔루션 기업 소스랩스의 수석 테스트 전략가인 마커스 머렐은 일부 조직이 AI 코딩 어시스턴트로 절약되는 시간을 과대 평가했을 수 있다고 말했다. 그는 개발자 생산성을 약 30% 개선한다는 것이 좋은 출발점으로 작용할 수는 있지만 근본적인 변화로 이어질 정도는 아니라고 지적했다. 

머렐은 “오늘날 현장에서는 팀들이 이런 도구를 통해 엄청난 이익을 얻을 수 있다고 생각해 도구에 과잉 투자하거나, 구조 및 프로세스 변경을 과도하게 진행하거나, AI 도구의 예상되는 장점만 갖고 이미 계획했던 직원 감축을 한층 더 심화하는 모습을 볼 수 있다”라고 지적했다. 

머렐은 생성형 AI가 개발자 일자리를 대체할 것이라고 생각하지 않으며, 그보다 로우코드/노코드 도구가 더 큰 영향을 미칠 수 있다고 내다봤다. AI 코딩 실험이 적당한 성공을 거두며 계속되더라도 결국 AI 대기업들은 막대한 투자액만큼의 수익을 거둬야 하기 때문이다.

머렐은 “앞으로 2~3년간 이 기술에서 온갖 생산성을 짜내기 위해 노력한 다음에는, 결국 허울에 불과했다는 것을 인정하는 데까지 매우 오래 걸릴 수 있다. 우려되는 점은 도구에 익숙해지고 나면 기업들이 모델을 운영하는 데 드는 비용을 청구하기 시작한다는 것이다. 그 때가 되면 시스템에는 큰 충격을 줄 수 있다”라고 진단했다.

 

https://www.ciokorea.com/news/350438

 

AI 코딩 도구의 급부상, 최대 피해자는 주니어 개발자?

일부 IT 리더들은 AI가 코드 작성에 더 능숙해지면서 소프트웨어 개발팀이 시니어 몇 명 수준으로 축소될 수 있다고 내다봤다. ⓒ

www.ciokorea.com

 

반응형

+ Recent posts