전체 글 47

기본적인 리팩터링 (2)

함수 선언 바꾸기 (Change Function Declaration)배경함수 선언은 코드의 연결부함수 선언은 단순히 이름과 매개변수를 정하는 게 아니다.이건 소프트웨어의 연결부를 어떻게 설계할 것인지에 대한 결정이다.그리고 그 연결부에서 가장 중요한 건 함수의 이름이다.이름은 생각보다 큰 영향을 미친다. 코드를 읽다 보면 의미가 잘 와닿지 않는 함수 이름을 만나기도 한다.그럴 때 많은 사람들이 "일단 넘어가자"는 유혹에 빠지기 쉽다. 하지만 파울러는 말한다.“더 나은 이름이 떠오르면, 즉시 바꿔라.” 그래야 나중에 또 고민할 필요가 없다.매개변수는 더 어렵다함수 이름보다 더 골치 아픈 게 바로 매개변수 설계다.매개변수는 단순히 데이터를 넘기는 수단이 아니라, 어떤 수준에서 기능을 연결할지 결정하는 중요..

기본적인 리팩터링 (1)

6장에서는 리팩터링의 기본이자 가장 자주 사용되는 기법들을 다룬다. 그만큼 중요하고, 먼저 익혀야 할 리팩터링이라는 의미다.마틴 파울러가 실무에서 가장 자주 사용하는 리팩터링은 함수 추출하기(Extract Function)와 변수 추출하기(Extract Variable).반대로, 함수 인라인하기(Inline Function)와 변수 인라인하기(Inline Variable)도 자주 등장한다.기능을 쪼개고 다시 단순하게 합치는 것. 리팩터링은 결국 이 반복이다.함수 추출하기 (Extract Function)배경코드를 언제 함수로 분리해야 할지는 논쟁이 많다. 파울러는 “목적과 구현을 분리하는 기준”을 가장 합리적으로 본다.예를 들어, 코드의 목적을 파악하는 데 시간이 걸린다면, 그 부분을 함수로 뽑아내고 그..

테스트 구축하기

마틴 파울러의 리팩터링(2판)에서는 코드 구조를 개선하는 리팩터링 기법을 다루지만, 리팩터링을 제대로 수행하려면 반드시 테스트가 필요하다. 이번 글에서는 책에서 다룬 ‘테스트 구축하기’ 챕터를 중심으로 테스트 코드 작성의 핵심 개념을 정리해보았다. 리팩터링과 테스트의 관계리팩터링의 궁극적인 목표는 코드를 더 개선하는 것이지만, 코드의 동작을 보장할 수 없다면 리팩터링 자체가 위험해진다. 이때 필요한 것이 바로 테스트 코드다. 리팩터링을 하기 전에 테스트를 구축하면 코드 변경으로 인한 의도치 않은 동작을 사전에 방지할 수 있다.테스트 코드가 없다면 리팩터링 과정에서 기존 기능이 망가졌는지 확인하기 어렵다. 따라서 리팩터링을 수행하기 전, 반드시 신뢰할 수 있는 테스트를 작성해야 한다. 실패하는 테스트를 직..

코드에서 나는 악취

마틴 파울러는 "언제 리팩터링을 해야하는가"에 대한 대답으로 코드에서 "냄새"가 나는 시점이라고 말하다. ( 정확히는 켄트벡의 표현을 빌린 것이다 ) 이들은 많은 코드를 봐왔고, 대체로 리팩토링이 필요한 코드들은 일정한 패턴을 가지고 있다고 한다.  본 장에서는 그 악취나는 패턴들에 대한 소개와 간단한 해결방법을 언급한다. 자세한 해결방법은 뒷장에 자세히 서술되어 있기에, 어떤 패턴이 악취인지에 조금 더 중점을 두고 내용을 정리해보았다. 1. 기이한 이름함수, 모듈, 변수, 클래스 등은 이름만 보고도 각각이 무슨 일을 하고 어떻게 사용해야 하는지 명확히 알 수 있게 이름을 지어야 한다.마땅한 이름이 떠오르지 않는다면 설계에 더 근본적인 문제가 숨어 있을 가능성이 높다. 2. 중복코드코드가 중복되면, 중복..

리팩터링: 첫 번째 예시

리팩터링 (2판) 1장에서는 앞으로 배울 리팩터링 기법을 한 데 모은 예시에 대해 소개한다. 다양한 공연을 외주 받아서 운영하는 극단의 충성도 프로그램이 소개된다. 이 프로그램에서는 연극의 장르와 관객의 규모에 따라 비용을 책정하는 비즈니스 로직이 존재하며, 이를 리팩터링하는 것이 이 장의 핵심 내용이다.  코드의 변화 과정을 훑으면서, 여기서 어떤 기법을 통해 바꾸었는지를 확인해보면 된다. 읽으면서 기억에 남는 부분들을 몇 가지 기록해보고자 한다. 나는 수백 줄 짜리 코드를 수정할 때면 먼저 프로그램의 작동 방식을 더 쉽게 파악할 수있도록 코드를 여러 함수와 프로그램 요소로 재구성한다.프로그램의 구조가 빈약하다면 대체로 구조부터 바로잡은 뒤에 기능을 수정하는 편이 작업하기 훨씬 수월하다. 프로그램이 새..

인간은 누구나 실수를 한다.

어느 순간부터 유튜브에서 "죄송합니다"라는 제목의 영상이 일상처럼 등장하기 시작했다.모든 사건과 논란의 진상을 속속들이 알고 있는 것은 아니지만, 몇 가지 사례를 조사해본 결과 어떤 이는 분명 중대한 잘못을 저지른 듯 보이는 반면, 어떤 경우에는 과연 이렇게까지 질타받아야 할 일인가 의문이 들 때도 있다.이를테면 빽햄 사건으로 거센 비판을 받고 있는 백종원, 자폐 자녀를 둔 부모로서 교사의 발언을 녹음했던 주호민 등이 그러하다.나는 그들의 해명 영상을 처음부터 끝까지 시청했다. 개인적인 호불호를 떠나, 논리적으로 납득할 만한 해명이었다. 물론, 그들의 입장이 완벽할 수는 없으며, 논란의 일부는 분명 그들의 실책에서 비롯된 것도 사실이다. 하지만 그렇다고 해서 이토록 가혹한 비난을 받아야 하는가?그들의 S..

Etc/Thought 2025.02.24

리팩터링 2판 공부를 시작하며

실무를 하다보면, 좋은 설계의 중요성을 알면서도 지키지 못할 때가 생긴다. 정말 촉박하게 개발을 해야하는 상황이거나, 긴급히 수정이 필요한 경우라면 더욱 그렇다. 비단, 이 경우들이 아니더라도 앞으로 새롭게 추가될 기능의 방향성을 미리 예측하고 이를 모두 고려한 설계를 하는 것이란 쉽지 않다. 때로는 그런 설계가 오버 엔지니어링 취급을 받기도 한다. 설령 내가 좋은 설계를 할 수 있는 개발자더라도, 좋은 설계가 된 코드만을 마주하리라는 법도 없다. 중요한 것은 주어진 코드를 "현재 상황"에 맞게 코드를 재설계하고 구조화할 수 있는 능력이 아닐까 싶다. 그런 의미에서 "리팩터링"은 나에게 좋은 방향성을 제시하는 교안이 되지 않을까 싶다.  앞으로의 학습 방향성에 대해 생각해보면.. 그간 여러 개발 서적을 ..

사회는 내가 배웠던 물리와 많이 닮아 있다

나는 물리학과를 졸업했다. 물리학은 수학이라는 도구로, 세상의 이치를 해석하는 학문이다.  물론 모든 문제를 완벽히 풀 수는 없다.대표적으로, "삼체문제"라는 것이 있다. 물체 세 개간에 중력에 의한 상호 작용을 완벽히 예측할 수 없다는 문제이다. 물체 두 개를 다루는 "이체문제"의 경우, 수학적인 해를 구할 수 있는데도, 물체 하나가 더 늘어나면 그것이 어려운 것이다.사회 활동도 이와 많이 닮아있다. N 명의 사람이, 수학적으로 정의할 수 없는 의사 소통을 하며 가변적인 경제 상황 속에서 수행하는 활동인 셈이다. 나는 약 4년간 회사를 다니며 다양한 사람들을 만나고, 여러 조직과 리더를 경험해왔다. 그 과정에서 가끔은 "좋은 리더란 어떤 사람일까?" 라는 질문이 떠오르곤 한다.좋은 리더의 기준을 정의하..

Etc/Thought 2025.02.08

LCEL 에 관하여

1. LCEL (LangChain Expression Language) 란? 랭체인 서버를 만들다보면, 다양한 예제에서 아래와 같이 | 연산자를 활용하는 모습을 볼 수 있다. 이는 LCEL이라는 코드 작성 방식이다. return prompt | llm | output_parser LCEL (LangChain Expression Language)은 랭체인에서 코드를 작성하는 새로운 방법이다. LCEL은 프롬프트와 LLM을 | 연산자로 연결하여 작성하여 체인을 구현한다.  2. LCEL의 기본 사용법 가장 간단한 형태로, prompt와 model을 연결해보자.  from dotenv import load_dotenvfrom langchain_openai import ChatOpenAIfrom langchai..

랭체인 에이전트

AI 에이전트는 LLM의 응용 분야로 각광받고 있는 분야 중 하나이다. 기존의 Chain이 고정된 흐름을 처리한다면, 어떤 처리를 할 것인지 LLM이 선택해서 움직여주기를 원하는 경우가 있을 수 있다. 가령, 사용자의 질의에 대해 필요에 따라 사내 문서를 Vector Store 에서 검색하여 답변하거나 웹 상의 정보를 바탕으로 답변해준다는 등으로 작동하면 LLM의 활용 범위는 크게 늘어날 수 있다. 이를 가능케 하는 것이 랭체인의 Agent 다.  에이전트 사용 예시 랭체인에는 다양한 종류의 Agents가 구현되어있다. 그 중, ReAct 라는 Agent를 사용하는 예시를 살펴보자. from langchain import hubfrom langchain.agents import AgentExecutor,..

랭체인 활용 - Data Connection

Data connection은 LLM과 외부의 데이터를 연결하기 위한 기능이다.  RAG (Retrieval Argumented Generation) GPT가 미처 학습하지 못한 정보( 가령, 최근에 발생한 이벤트나 사내 정보 등 )를 사용하게 싶은 경우가 있다. 이 경우, 프롬프트에 컨텍스트(context)를 넣은 방법을 떠올릴 수 있다.  # 프롬프트문맥을 고려하여 한 문장으로 질문에 답해 주세요. 문맥: """"""질문: A회사에서 야근하면, 받을 수 있는 수당은 얼마인가요? 물론 LLM은 토큰 수 제한이 있기에, 모든 데이터를 컨텍스트로 담을 수는 없다. 그래서 "관련이 있는 데이터"만 컨텍스트로 담는 과정이 필요하고, 이를 위한 기법이 바로 RAG (Retrieval Argumented Gene..

랭체인 기초

- 랭체인은 LLM을 이용한 애플리케이션 개발 프레임워크이다. - 랭체인의 모듈은 크게 6가지로 나뉜다.   - Model I/O   - Data Connection  - Chains  - Agents  - Memory  - Callbacks 각 모듈의 역할은 아래와 같다. Language Models- Language models는 랭체인에서 언어 모델을 사용하는 방법을 제공하는 모듈이다. - 다양한 언어 모델을 공통된 인터페이스로 사용할 수 있다.- Language models를 크게 'LLMs'와 'Chat models'로 분류할 수 있다. LLMs- 하나의 텍스트 입력에 대해 하나의 텍스트 출력을 반환하는 전형적인 대규모 언어 모델을 다루는 모듈이다.  from langchain_openai im..

저장소와 검색 (2)

트랜잭션 처리와 분산 일반적인 온라인 어플리케이션에서는 여러 종류의 데이터가 사용자 입력을 기반으로 삽입되거나 갱신된다. 이는 클라이언트와 서버 간의 대화식이기에, 이 접근 패턴을 온라인 트랜잭션 처리( online transaction processing, OLTP )라고 한다. OLTP는 이익을 산출하는 비즈니스에 맞닿아 있기에 대부분의 데이터 베이스는 OLTP 에 맞추어 설계되고 발전되었다.  하지만 시간이 지남에 따라 사람들은 데이터 베이스를 "데이터 분석 ( data analytic )" 목적으로도 많이 사용하기 시작했다. 데이터 분석은 기존 트랜잭션과 접근 패턴이 매우 다르다. 분석에 사용되는 쿼리는 사용자에게 원시 데이터만을 반환하지 않고, 많은 수의 레코드에 대한 집계 통계를 계산해야 했기..

저장소와 검색 (1)

이 장에서는 데이터베이스가 저장과 검색을 내부적으로 어떻게 처리하는지에 대해 다룬다. JPA나 Typeorm 과 같은 ORM을 사용하는 애플리케이션 개발자들이 이를 알아야하는 이유는 처음부터 자신의 저장소 엔진을 구현하기 위해서라기 보다는 여러 저장소 엔진 중에 애플리케이션에 가장 적합한 엔진을 선택하기 위함이다. 관계형 데이터베이스와 NoSQL 데이터베이스의 저장소 엔진, 그리고 로그 구조 계열 저장소 엔진과 (B-Tree와 같은) 페이지 지향 계열 저장소 엔진을 검토해보도록 하자.  데이터베이스를 강력하게 만드는 데이터 구조 아래와 같은 아주 간단한 데이터베이스를 가정해보자. #!/bin/bashdb_set () { echo "$1,$2" >> database}db_get () { grep "^$1,..

데이터 모델과 질의 언어

내 언어의 한계는 내 세계의 한계를 의미한다.- 루트비히 비트겐슈타인, 논리-철학 논고(1922) 요즘 개발 커뮤니티에서 "요즘 어플리케이션들이 AI Wrapper 다"라는 이야기를 심심치 않게 들을 수 있다. 이곳 저곳에 생성형 AI 관련 기능을 넣으면서 나온 이야기인듯 한데.. 결국 기존 어플리케이션도 Database Wrapper가 아니냐는 이야기로 귀결된다. 그만큼 현재 데이터 베이스 모델들은 각종 ORM 혹은 데이터 베이스 콘솔이나 CLI 등으로 잘 추상화가 되어 있어서 개발자들은 이들을 사용하는데 불편함을 느끼지 못한다. 데이터 모델은 다양한 유형을 갖고 있고, 각 유형마다 어떤 연산은 빠르게 어떤 연산은 매우 느리게 동작하기도 한다.이 장에서는 다양한 데이터 모델 및 그들의 질의 언어 ( Q..

신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 애플리케이션 (2)

확장성 부하 기술하기 성능 저하를 유발하는 흔한 이유 중 하나는 부하 증가다. 확장성은 증가한 부하에 대처하는 시스템 능력을 설명하는 데 사용하는 용어지만 시스템에 부여하는 일차원적인 표식은 아니다. 단순은 "~은 확장 가능하다" 와 같은 말은 의미가 없다. 오히려 확장성을 논한다는 것은 "시스템이 특정 방식으로 커지면 이를 대처하기 위한 좋은 조치는 무엇일까", "추가 부하를 다루기 위해 계산 자원을 어떻게 투입할까" 같은 질문을 고려한다는 의미다. 저자는 트위터의 트윗 처리 방식을 대표적인 예시로 말한다.  트위터의 주요 동작은 크게 두 가지, (1) 트윗 작성과 (2) 홈 타임라인 조회이다. 트윗 작성은 초당 46,000번 발생하고, 홈 타임라인 조회는 초당 300,000번 발생한다. 사실 이 정도..

신뢰할 수 있고 확장 가능하며 유지보수하기 쉬운 애플리케이션 (1)

오늘날 많은 애플리케이션은 계산 중심보다는 데이터 중심적이다. 고도의 계산으로 인해 CPU의 성능이 중요하기보다는 많고 복잡하며 변화하는 데이터를 잘 다루는 데에 애플리케이션의 방점이 찍혀있다.  이 책은 데이터 시스템의 원칙과 실용성, 그리고 이를 활용한 데이터 중심 애플리케이션을 개발하는 방법을 모두 담고 있다. 책에서 소개된 다양한 도구가 공통으로 지닌 것은 무엇이고 서로 구별되는 것은 무엇인지, 그리고 어떻게 그러한 특성을 구현해냈는지 알아보도록 한다. 데이터 시스템에 대한 생각 일반적으로 데이터 시스템은 데이터베이스, 큐, 캐시 등 다른 범주의 도구들을 모두 포괄하는 용어이다. 그런 포괄적인 용어를 사용하는 데에는 두 가지 이유가 있다. 1. 최근에 등장한 도구들은 다양한 사용 사례(use-ca..

단위 테스트란 무엇인가

단위 테스트의 정의 단위 테스트의 가장 중요한 세 가지 속성은 아래와 같다. 1. 작은 코드 조각을 검증하고, 2. 빠르게 수행하고, 3. 격리된 방식으로 처리하는 자동화된 테스트 처음 두 가지 속성은 대체로 논란의 여지가 없지만, 마지막 속성인 '격리 문제'는 단위 테스트의 고전파와 런던파를 구분하는 근원이 된다. 격리 문제에 대한 런던파의 접근 런던파에서는 '테스트의 격리 방식'을 '테스트 대상 시스템을 협력자 ( collaborator )에게서 격리하는 것'으로 규정한다. 즉, 하나의 클래스가 다른 클래스들에 의존하면 모든 의존성을 테스트 대역 ( test double )로 대체해야한다. 이 방법의 이점 중 하나는 테스트가 실패하면 코드베이스의 어느 부분이 고장 났는지 확실히 알 수 있다는 것이다...

MySQL 복제 (2)

복제 Failover 복제는 고가용성의 초석이다. 데이터 복사본을 다른 위치에서 지속적으로 업데이트하면 백업으로 이동하는 것보다 재해로부터 복구하는 것이 훨씬 쉽다. 여기에서는 레플리카를 원본 노드로 승격하는 올바른 방법에 대해 설명한다. "레플리카 승격"과 "Failover"가 동의어임에 유의하자. 두 가지 모두 쓰기를 수행하지 못하도록 소스를 강등시키고 레플리카를 소스 역할로 승격시키는 작업을 의미한다. 계획된 승격 일반적으로 승격은 유지 관리 이벤트( 보안 패치, 커널 업데이트, 재시작을 해야하는 몇 가지 구성 옵션으로 인한 재시작 등 )로 인해 수행된다. 이러한 유형의 승격을 계획된 승격이라고 한다. 이 승격을 성공적으로 처리하기 위해 다음 단계를 수행한다. 1. 승격할 레플리카를 결정한다. 대개..

MySQL 복제 (1)

개요 MySQL 의 복제 기능은 소위 "스케일 아웃"이라는 아키텍처를 사용하는 고성능 애플리케이션의 기반이 된다. 복제를 통해 하나 이상의 서버를 다른 서버의 레플리카로 구성하여 데이터를 소스 복사본과 동기화할 수 있다. 이는 고성능 애플리케이션에 유용할 뿐만 아니라 고가용성, 확장성, 재해 복구, 백업, 분석, 데이터 웨어하우징 등 여러 작업을 위한 초석이 되기도 한다. 복제는 대략적인 과정은 다음과 같다. 소스 서버의 로그에 데이터 또는 데이터 구조를 수정하는 이벤트를 기록한다. 그러면 레플리카 서버는 소스의 로그에서 이벤트를 읽고 재생할 수 있다. 당연히 이렇게 되면 실시간과 레플리카에 표시된 시간 사이의 지연 ( 레플리카 지연 )이 발생하고, 이는 쿼리의 규모에 따라 몇 초, 몇 분 또는 몇 시간..