logo
emoji
검색하기
어제 가장 많이 검색된 기술
emoji
가장 많이 읽은 글
logo
Digital assistant app, 간단히 만들어보기
디지털 어시스턴트 앱은 사용자의 음성 명령을 통해 디바이스와 자연스럽게 상호작용할 수 있도록 설계된 애플리케이션입니다.이 앱은 VoiceInteractionService를 기반으로 동작하며, 매니페스트 파일에 해당 서비스를 등록함으로써 구현을 시작할 수 있습니다.실행 중에는 현재 화면에서 텍스트나 이미지 등의 정보를 수집하여, 사용자에게 필요한 도움을 적시에 제공할 수 있습니다.또한, 시스템 서비스와 연동되어 동작하기 때문에 기본 애플리케이션만 활성 상태로 유지되며, 디바이스 리소스를 보다 효율적으로 사용할 수 있는 장점이 있습니다.• None 설정 방법: 설정 → 애플리케이션 → 기본 앱 선택 → 디지털 어시스턴트 앱 → 디바이스 도우미 앱• None 실행 방법: 대부분의 기기에서는 측면 버튼을 길게 눌렀을 때 활성화됩니다. 기기마다 다를 수 있으니 확인이 필요합니다.3. 어시스턴트 앱 라이프사이클디지털 어시스턴트 앱은 일반 앱과는 다른 라이프사이클을 가집니다.Android의 , , 세 컴포넌트가 각 역할을 나누어 수행하며,주요 흐름은 다음과 같습니다:• None• None 디바이스 부팅 시 가 바인딩되고 가 호출됩니다.• None 이 시점에서 시스템에 어시스턴트가 준비되었음을 알립니다.• None• None 사용자가 디바이스 버튼이나 기타 트리거를 통해 어시스턴트를 호출하면 의 이 호출됩니다.• None• None 에서 새로운 인스턴스를 생성하여 반환합니다.• None 해당 세션에서는 와 또는 가 호출되며, 어시스턴트 UI를 표시하거나 숨깁니다.• None• None 디바이스 종료, 사용자의 종료 요청 또는 다른 VIS가 선택되면 이 호출되어 서비스가 중단됩니다.• None 세션도 함께 를 통해 정리됩니다.sessionService : 어시스턴트를 호출할 때마다 새로운 세션을 생성하고 관리하는 서비스 클래스의 전체 경로를 지정합니다.settingsActivity : 어시스턴트 앱의 설정 화면을 담당하는 액티비티의 전체 경로를 지정합니다.supportsAssist : 현재 화면 컨텍스트 정보(텍스트, 뷰 구조 등)를 수집하여 어시스턴트에 제공할지 여부를 지정합니다.supportsLaunchFromKeyguard : 잠금 화면 상태에서도 어시스턴트를 실행할 수 있는지 여부를 지정합니다.VoiceInteractionService는 디지털 어시스턴트의 진입점 역할을 합니다. 시스템이 해당 서비스를 호출하면 onReady()가 실행되며, 어시스턴트 사용 준비가 완료되었음을 나타냅니다.여기서 로깅, 초기 설정, 또는 백그라운드 초기화 작업 등을 수행할 수 있습니다.VoiceInteractionSessionService는 어시스턴트 호출 시마다 VoiceInteractionSession을 생성하고 관리하는 역할을 합니다.onNewSession()에서는 새로운 CustomVoiceInteractionSession을 반환하고, onDestroy()에서는 세션을 해제하여 리소스를 정리합니다.세션은 일시적인 객체이므로 상태를 오래 유지하지 않도록 주의해야 합니다.VoiceInteractionSession은 사용자와의 직접적인 상호작용을 담당하는 세션 클래스입니다.onPrepareShow()는 UI 표시 직전에 호출되며, UI를 사용할지 여부를 설정합니다.onShow()는 어시스턴트가 활성화될 때 호출되며, 커스텀 Activity를 띄워 직접적인 인터페이스를 제공합니다.onHandleScreenshot()에서는 시스템이 전달하는 스크린샷을 받아 이미지 기반 분석을 수행할 수 있고,onHandleAssist()에서는 Assist 구조 정보(텍스트, 뷰 계층 등)를 활용하여 풍부한 컨텍스트를 기반으로 사용자 지원이 가능합니다.Voice Interaction Session이 시작되면 시스템은 뷰와 스크린샷을 캡처하고 이 정보를 세션에 전달할 수 있습니다.애플리케이션은 와 를 구현하여 추가 정보를 어시스턴트 앱으로 전달할 수 있습니다.앱 개발자는 자신의 앱이 어시스턴트와 효과적으로 상호작용할 수 있도록 다음과 같은 방법으로 최적화할 수 있습니다.를 통해 AssistStructure 인스턴스로 표시된 텍스트 및 뷰 계층 구조를 수신할 수 있습니다.이를 통해 현재 화면의 콘텐츠를 분석하고 컨텍스트에 맞는 응답을 제공할 수 있습니다.을 통해 스크린샷을 수신합니다.이 스크린샷을 분석하여 시각적 콘텐츠를 이해하고 추가 컨텍스트를 제공할 수 있습니다.디지털 어시스턴트 앱은 사용자의 음성 명령을 기반으로 디바이스와 상호작용할 수 있는 기능을 제공합니다.Android의 VoiceInteractionService를 활용하면 디지털 어시스턴트를 손쉽게 구현할 수 있으며, 이를 통해 사용자 경험을 크게 향상시킬 수 있습니다.또한, 화면 콘텐츠 분석, 스크린샷 처리, 구조화된 데이터 제공 등 다양한 기능을 통해 사용자에게 맞춤형 도움을 제공할 수 있습니다.
5/16/2025
logo
Digital assistant app, 간단히 만들어보기
디지털 어시스턴트 앱은 사용자의 음성 명령을 통해 디바이스와 자연스럽게 상호작용할 수 있도록 설계된 애플리케이션입니다.이 앱은 VoiceInteractionService를 기반으로 동작하며, 매니페스트 파일에 해당 서비스를 등록함으로써 구현을 시작할 수 있습니다.실행 중에는 현재 화면에서 텍스트나 이미지 등의 정보를 수집하여, 사용자에게 필요한 도움을 적시에 제공할 수 있습니다.또한, 시스템 서비스와 연동되어 동작하기 때문에 기본 애플리케이션만 활성 상태로 유지되며, 디바이스 리소스를 보다 효율적으로 사용할 수 있는 장점이 있습니다.• None 설정 방법: 설정 → 애플리케이션 → 기본 앱 선택 → 디지털 어시스턴트 앱 → 디바이스 도우미 앱• None 실행 방법: 대부분의 기기에서는 측면 버튼을 길게 눌렀을 때 활성화됩니다. 기기마다 다를 수 있으니 확인이 필요합니다.3. 어시스턴트 앱 라이프사이클디지털 어시스턴트 앱은 일반 앱과는 다른 라이프사이클을 가집니다.Android의 , , 세 컴포넌트가 각 역할을 나누어 수행하며,주요 흐름은 다음과 같습니다:• None• None 디바이스 부팅 시 가 바인딩되고 가 호출됩니다.• None 이 시점에서 시스템에 어시스턴트가 준비되었음을 알립니다.• None• None 사용자가 디바이스 버튼이나 기타 트리거를 통해 어시스턴트를 호출하면 의 이 호출됩니다.• None• None 에서 새로운 인스턴스를 생성하여 반환합니다.• None 해당 세션에서는 와 또는 가 호출되며, 어시스턴트 UI를 표시하거나 숨깁니다.• None• None 디바이스 종료, 사용자의 종료 요청 또는 다른 VIS가 선택되면 이 호출되어 서비스가 중단됩니다.• None 세션도 함께 를 통해 정리됩니다.sessionService : 어시스턴트를 호출할 때마다 새로운 세션을 생성하고 관리하는 서비스 클래스의 전체 경로를 지정합니다.settingsActivity : 어시스턴트 앱의 설정 화면을 담당하는 액티비티의 전체 경로를 지정합니다.supportsAssist : 현재 화면 컨텍스트 정보(텍스트, 뷰 구조 등)를 수집하여 어시스턴트에 제공할지 여부를 지정합니다.supportsLaunchFromKeyguard : 잠금 화면 상태에서도 어시스턴트를 실행할 수 있는지 여부를 지정합니다.VoiceInteractionService는 디지털 어시스턴트의 진입점 역할을 합니다. 시스템이 해당 서비스를 호출하면 onReady()가 실행되며, 어시스턴트 사용 준비가 완료되었음을 나타냅니다.여기서 로깅, 초기 설정, 또는 백그라운드 초기화 작업 등을 수행할 수 있습니다.VoiceInteractionSessionService는 어시스턴트 호출 시마다 VoiceInteractionSession을 생성하고 관리하는 역할을 합니다.onNewSession()에서는 새로운 CustomVoiceInteractionSession을 반환하고, onDestroy()에서는 세션을 해제하여 리소스를 정리합니다.세션은 일시적인 객체이므로 상태를 오래 유지하지 않도록 주의해야 합니다.VoiceInteractionSession은 사용자와의 직접적인 상호작용을 담당하는 세션 클래스입니다.onPrepareShow()는 UI 표시 직전에 호출되며, UI를 사용할지 여부를 설정합니다.onShow()는 어시스턴트가 활성화될 때 호출되며, 커스텀 Activity를 띄워 직접적인 인터페이스를 제공합니다.onHandleScreenshot()에서는 시스템이 전달하는 스크린샷을 받아 이미지 기반 분석을 수행할 수 있고,onHandleAssist()에서는 Assist 구조 정보(텍스트, 뷰 계층 등)를 활용하여 풍부한 컨텍스트를 기반으로 사용자 지원이 가능합니다.Voice Interaction Session이 시작되면 시스템은 뷰와 스크린샷을 캡처하고 이 정보를 세션에 전달할 수 있습니다.애플리케이션은 와 를 구현하여 추가 정보를 어시스턴트 앱으로 전달할 수 있습니다.앱 개발자는 자신의 앱이 어시스턴트와 효과적으로 상호작용할 수 있도록 다음과 같은 방법으로 최적화할 수 있습니다.를 통해 AssistStructure 인스턴스로 표시된 텍스트 및 뷰 계층 구조를 수신할 수 있습니다.이를 통해 현재 화면의 콘텐츠를 분석하고 컨텍스트에 맞는 응답을 제공할 수 있습니다.을 통해 스크린샷을 수신합니다.이 스크린샷을 분석하여 시각적 콘텐츠를 이해하고 추가 컨텍스트를 제공할 수 있습니다.디지털 어시스턴트 앱은 사용자의 음성 명령을 기반으로 디바이스와 상호작용할 수 있는 기능을 제공합니다.Android의 VoiceInteractionService를 활용하면 디지털 어시스턴트를 손쉽게 구현할 수 있으며, 이를 통해 사용자 경험을 크게 향상시킬 수 있습니다.또한, 화면 콘텐츠 분석, 스크린샷 처리, 구조화된 데이터 제공 등 다양한 기능을 통해 사용자에게 맞춤형 도움을 제공할 수 있습니다.
2025.05.16
emoji
좋아요
emoji
별로에요
logo
Python 통합 코드 품질 도구 Ruff : Flake8, isort, Black의 대안
Ruff는 Rust로 작성된 매우 빠른 Python linter 및 code formatter입니다. 기존의 도구들의 다양한 역할을 하나로 통합하여 코드에 대한 품질 검사와 포맷팅을 수행합니다.Rust로 작성되서 기존 도구 대비 10-100배 빠른 속도를 자랑하고 있습니다.이번 글에서는 Ruff가 Python 코드 품질 도구로 널리 알려진 Flake8, isort, Black을 어떻게 효과적으로 대체할 수 있는지,그 설치 및 구성 방법, 그리고 pre-commit을 통해 코드 베이스에 코드를 커밋하기 전에 미리 검사하고 수정할 수 있도록 하는 방법에 대해 다룹니다.Python 개발에서 코드 품질을 유지하기 위해 사용되는 다양한 도구들 중 가장 널리 사용되는 것들은 다음과 같습니다:• None Flake8: Python 코드의 문법 오류 및 코딩 스타일 위반을 검사하는 linter• None Black: Python 코드 스타일을 자동으로 포맷팅하는 도구기존 도구들은 각각 특정 기능에 초점을 맞추어 개발되었지만, 여러 도구를 함께 사용해야 하는 복잡성과 성능 이슈가 존재했습니다.코드베이스가 커짐에 따라 이러한 도구들의 실행 시간이 길어지면 개발 효율성을 저하시키는 문제가 있습니다.이러한 문제를 해결하기 위해 Rust로 작성된 Ruff가 등장했습니다.지금은 Apache Airflow, Superset, FastAPI, Hugging Face, Pandas, SciPy 등 메이저 오픈 소스에서 널리 사용되고 있으며 지원하는 빌트인 규칙이 800개 이상이며 플러그인 시스템을 통해 추가적인 규칙을 지원합니다.• None 속도: 기존 linter(Flake8)와 formatter(Black)보다 10-100배 빠름Ruff는 pip를 통해 쉽게 설치할 수 있습니다:설치 후 다음과 같이 사용할 수 있습니다:Ruff는 , 또는 파일을 통해 구성할 수 있습니다.기존 도구에서 Ruff로의 마이그레이션 전략대규모 코드베이스에서 Ruff로 마이그레이션하는 권장 전략은 다음과 같습니다:• None 1단계: Ruff를 코드베이스에 추가하고 규칙 없이 실행• None 2단계: 최소한의 Ruff 설정을 제공하고, 필요한 규칙을 하나씩 추가하며 호환성 확인• None 3단계: 규칙을 하나씩 또는 작은 배치로 활성화하고 코드를 수정기존 Flake8 설정을 Ruff 설정으로 변환하려면 도구를 사용할 수 있습니다:이 도구는 해당 파일을 분석하여 Ruff 호환 섹션을 생성합니다.pre-commit을 활성화해두면 커밋될때 마다 자동으로 코드 품질 검사와 포맷팅을 수행합니다.이를 통해 일관된 코드 스타일과 정적 문법 오류를 줄일 수 있습니다.기존의 경우 pre-commit 설정을 다음과 같이 Flake8, isort, Black으로 구성했습니다.Ruff를 사용하는 경우 다음과 같이 통합해서 설정 가능합니다.설정한 pre-commit 훅을 설치하고 모든 파일 검사 및 수정을 수행할 수 있습니다.Ruff를 사용하면 Flake8, isort, Black을 대체할 수 있을 뿐만 아니라 다음과 같은 효과를 얻을 수 있습니다:• None 코드 리뷰 프로세스 간소화: 일관된 코드 품질을 유지하고 리뷰 시간 단축• None CI/CD 파이프라인 통합: 자동화된 품질 체크를 통한 지속적인 코드 품질 관리• None Ruff는 Flake8, isort, Black의 기능을 하나로 통합한 초고속 Python 코드 품질 관리 도구입니다.• None 기존 도구들보다 10~100배 빠르며, 대부분의 규칙과 포맷팅 방식을 호환해 손쉽게 대체설치와 설정이 간편해 대규모 프로젝트에서도 효율적인 코드 품질 관리가 가능합니다.• None Pre-commit을 통해 커밋될때 마다 자동으로 코드 품질 검사와 포맷팅을 수행합니다.
python
5/16/2025
logo
Python 통합 코드 품질 도구 Ruff : Flake8, isort, Black의 대안
Ruff는 Rust로 작성된 매우 빠른 Python linter 및 code formatter입니다. 기존의 도구들의 다양한 역할을 하나로 통합하여 코드에 대한 품질 검사와 포맷팅을 수행합니다.Rust로 작성되서 기존 도구 대비 10-100배 빠른 속도를 자랑하고 있습니다.이번 글에서는 Ruff가 Python 코드 품질 도구로 널리 알려진 Flake8, isort, Black을 어떻게 효과적으로 대체할 수 있는지,그 설치 및 구성 방법, 그리고 pre-commit을 통해 코드 베이스에 코드를 커밋하기 전에 미리 검사하고 수정할 수 있도록 하는 방법에 대해 다룹니다.Python 개발에서 코드 품질을 유지하기 위해 사용되는 다양한 도구들 중 가장 널리 사용되는 것들은 다음과 같습니다:• None Flake8: Python 코드의 문법 오류 및 코딩 스타일 위반을 검사하는 linter• None Black: Python 코드 스타일을 자동으로 포맷팅하는 도구기존 도구들은 각각 특정 기능에 초점을 맞추어 개발되었지만, 여러 도구를 함께 사용해야 하는 복잡성과 성능 이슈가 존재했습니다.코드베이스가 커짐에 따라 이러한 도구들의 실행 시간이 길어지면 개발 효율성을 저하시키는 문제가 있습니다.이러한 문제를 해결하기 위해 Rust로 작성된 Ruff가 등장했습니다.지금은 Apache Airflow, Superset, FastAPI, Hugging Face, Pandas, SciPy 등 메이저 오픈 소스에서 널리 사용되고 있으며 지원하는 빌트인 규칙이 800개 이상이며 플러그인 시스템을 통해 추가적인 규칙을 지원합니다.• None 속도: 기존 linter(Flake8)와 formatter(Black)보다 10-100배 빠름Ruff는 pip를 통해 쉽게 설치할 수 있습니다:설치 후 다음과 같이 사용할 수 있습니다:Ruff는 , 또는 파일을 통해 구성할 수 있습니다.기존 도구에서 Ruff로의 마이그레이션 전략대규모 코드베이스에서 Ruff로 마이그레이션하는 권장 전략은 다음과 같습니다:• None 1단계: Ruff를 코드베이스에 추가하고 규칙 없이 실행• None 2단계: 최소한의 Ruff 설정을 제공하고, 필요한 규칙을 하나씩 추가하며 호환성 확인• None 3단계: 규칙을 하나씩 또는 작은 배치로 활성화하고 코드를 수정기존 Flake8 설정을 Ruff 설정으로 변환하려면 도구를 사용할 수 있습니다:이 도구는 해당 파일을 분석하여 Ruff 호환 섹션을 생성합니다.pre-commit을 활성화해두면 커밋될때 마다 자동으로 코드 품질 검사와 포맷팅을 수행합니다.이를 통해 일관된 코드 스타일과 정적 문법 오류를 줄일 수 있습니다.기존의 경우 pre-commit 설정을 다음과 같이 Flake8, isort, Black으로 구성했습니다.Ruff를 사용하는 경우 다음과 같이 통합해서 설정 가능합니다.설정한 pre-commit 훅을 설치하고 모든 파일 검사 및 수정을 수행할 수 있습니다.Ruff를 사용하면 Flake8, isort, Black을 대체할 수 있을 뿐만 아니라 다음과 같은 효과를 얻을 수 있습니다:• None 코드 리뷰 프로세스 간소화: 일관된 코드 품질을 유지하고 리뷰 시간 단축• None CI/CD 파이프라인 통합: 자동화된 품질 체크를 통한 지속적인 코드 품질 관리• None Ruff는 Flake8, isort, Black의 기능을 하나로 통합한 초고속 Python 코드 품질 관리 도구입니다.• None 기존 도구들보다 10~100배 빠르며, 대부분의 규칙과 포맷팅 방식을 호환해 손쉽게 대체설치와 설정이 간편해 대규모 프로젝트에서도 효율적인 코드 품질 관리가 가능합니다.• None Pre-commit을 통해 커밋될때 마다 자동으로 코드 품질 검사와 포맷팅을 수행합니다.
2025.05.16
python
emoji
좋아요
emoji
별로에요
logo
생성형 AI와 금융의 만남, 대출 음성 상담 챗봇 서비스
sunny.ryu AI 기반 대출 음성 상담 챗봇이라니? 굉장히 신선하고 유용할 것 같아요. 얼마나 많은 고민을 거듭하며 개발했는지, AI와 핀테크가 어떻게 어우러질 수 있는지 궁금한 분들에게 강력 추천드려요!안녕하세요, 카카오페이 크레딧클랜 PM 조엘입니다. 2025년 카카오페이와 AWS가 함께 주최한 해커톤에서 대출 서비스의 확장성과 AI를 활용한 금융 중개 서비스를 만들어보고자 크레딧클랜 팀원들과 함께 참여했는데요. 생성형 AI를 활용한 서비스 개발에 관심이 많고 AI를 금융 서비스에 접목시키고자 하는 분들이 참고하면 좋은 이야기들을 전해보고자 합니다. 기획 배경, 전체 데이터 플로우, 백엔드 구현 세부사항, AI Agent 파이프라인, 그리고 마지막으로 개발 과정에서의 트러블슈팅 사례를 소개할게요. 그럼 우선 저희가 AI 대출 음성 상담 챗봇 서비스를 기획하게 된 배경을 먼저 공유드리겠습니다.비대면 금융의 그림자, 그리고 개인화된 상담의 부재저희는 비대면 금융 서비스 이용은 꾸준히 증가하고 있지만, 여전히 많은 소비자들이 불확실성 때문에 직접 상담을 선호하는 경향이 있다는 점에 집중했습니다. 특히, 중요한 결정이 필요한 대출의 경우 이러한 경향은 더욱 두드러지는데요. 이때, 온라인 대출 중개서비스에서 진정으로 필요한 것은 온라인에서도 개인의 상황을 깊이 이해하는 맞춤형 상담이라고 생각했습니다.그렇게 탄생한 ‘당신의 목소리에 귀 기울이는, AI 대출 음성 상담 챗봇’해커톤에서 개발한 대출 음성 상담 챗봇은 마치 은행 창구에서 상담을 받는 것처럼, 사용자의 음성을 통해 고민을 듣고 대출 상품을 추천하는 서비스입니다. AI는 음성으로 주고받은 답변으로 사용자에게 가장 적합한 금리와 한도를 제공하는 금융사를 추천하죠. 추천 결과가 만족스럽지 않다면, 추가 상담을 통해 더 나은 조건이나 맞춤형 솔루션을 제공하여 고객 만족도를 높이는 것에도 집중했습니다.물론 텍스트로도 주고받을 수 있지만, ‘음성’으로 구현한 이유는 위에 언급한 문제점과 관련이 깊습니다. 일방향의 느낌보다는 쌍방향 소통처럼 은행 창구에서 대화하는 UX를 통해 소비자들의 불확실성을 낮추고, 대출 중개 플랫폼에서도 본인의 고민을 충분히 상담할 수 있는 경험을 선사하고 싶었습니다. 아직 존재하지 않은 시장이라 이번 해커톤을 통해 아이디어를 실현해보고 싶은 마음도 있었고요!AI 대출 음성 상담 챗봇의 핵심적인 기능은 다음과 같습니다.• 자연스러운 음성 인터페이스: 복잡한 텍스트 입력 없이, 음성을 통한 편리하고 직관적인 상담 경험을 제공합니다.• 개인 맞춤형 상품 추천: 음성 상담 과정에서 파악된 사용자의 상황과 니즈를 기반으로, 최적의 조건과 혜택을 제공하는 금융 기관을 지능적으로 연결합니다.• 데이터 기반 개선 제안: 사용자의 금융 데이터를 심층적으로 분석하고, 유사한 특성을 가진 다른 사용자와의 비교를 통해 개선 가능한 금융 관리 방안을 제시합니다. (더 좋은 신용 점수를 받을수록, 더 좋은 조건의 대출 상품이 나타나기 때문입니다)핵심 기능들을 보니, 어떻게 구현하였는지 궁금
5/16/2025
logo
생성형 AI와 금융의 만남, 대출 음성 상담 챗봇 서비스
sunny.ryu AI 기반 대출 음성 상담 챗봇이라니? 굉장히 신선하고 유용할 것 같아요. 얼마나 많은 고민을 거듭하며 개발했는지, AI와 핀테크가 어떻게 어우러질 수 있는지 궁금한 분들에게 강력 추천드려요!안녕하세요, 카카오페이 크레딧클랜 PM 조엘입니다. 2025년 카카오페이와 AWS가 함께 주최한 해커톤에서 대출 서비스의 확장성과 AI를 활용한 금융 중개 서비스를 만들어보고자 크레딧클랜 팀원들과 함께 참여했는데요. 생성형 AI를 활용한 서비스 개발에 관심이 많고 AI를 금융 서비스에 접목시키고자 하는 분들이 참고하면 좋은 이야기들을 전해보고자 합니다. 기획 배경, 전체 데이터 플로우, 백엔드 구현 세부사항, AI Agent 파이프라인, 그리고 마지막으로 개발 과정에서의 트러블슈팅 사례를 소개할게요. 그럼 우선 저희가 AI 대출 음성 상담 챗봇 서비스를 기획하게 된 배경을 먼저 공유드리겠습니다.비대면 금융의 그림자, 그리고 개인화된 상담의 부재저희는 비대면 금융 서비스 이용은 꾸준히 증가하고 있지만, 여전히 많은 소비자들이 불확실성 때문에 직접 상담을 선호하는 경향이 있다는 점에 집중했습니다. 특히, 중요한 결정이 필요한 대출의 경우 이러한 경향은 더욱 두드러지는데요. 이때, 온라인 대출 중개서비스에서 진정으로 필요한 것은 온라인에서도 개인의 상황을 깊이 이해하는 맞춤형 상담이라고 생각했습니다.그렇게 탄생한 ‘당신의 목소리에 귀 기울이는, AI 대출 음성 상담 챗봇’해커톤에서 개발한 대출 음성 상담 챗봇은 마치 은행 창구에서 상담을 받는 것처럼, 사용자의 음성을 통해 고민을 듣고 대출 상품을 추천하는 서비스입니다. AI는 음성으로 주고받은 답변으로 사용자에게 가장 적합한 금리와 한도를 제공하는 금융사를 추천하죠. 추천 결과가 만족스럽지 않다면, 추가 상담을 통해 더 나은 조건이나 맞춤형 솔루션을 제공하여 고객 만족도를 높이는 것에도 집중했습니다.물론 텍스트로도 주고받을 수 있지만, ‘음성’으로 구현한 이유는 위에 언급한 문제점과 관련이 깊습니다. 일방향의 느낌보다는 쌍방향 소통처럼 은행 창구에서 대화하는 UX를 통해 소비자들의 불확실성을 낮추고, 대출 중개 플랫폼에서도 본인의 고민을 충분히 상담할 수 있는 경험을 선사하고 싶었습니다. 아직 존재하지 않은 시장이라 이번 해커톤을 통해 아이디어를 실현해보고 싶은 마음도 있었고요!AI 대출 음성 상담 챗봇의 핵심적인 기능은 다음과 같습니다.• 자연스러운 음성 인터페이스: 복잡한 텍스트 입력 없이, 음성을 통한 편리하고 직관적인 상담 경험을 제공합니다.• 개인 맞춤형 상품 추천: 음성 상담 과정에서 파악된 사용자의 상황과 니즈를 기반으로, 최적의 조건과 혜택을 제공하는 금융 기관을 지능적으로 연결합니다.• 데이터 기반 개선 제안: 사용자의 금융 데이터를 심층적으로 분석하고, 유사한 특성을 가진 다른 사용자와의 비교를 통해 개선 가능한 금융 관리 방안을 제시합니다. (더 좋은 신용 점수를 받을수록, 더 좋은 조건의 대출 상품이 나타나기 때문입니다)핵심 기능들을 보니, 어떻게 구현하였는지 궁금
2025.05.16
emoji
좋아요
emoji
별로에요
logo
거래내역에 감성과 지능을 더하다: 이미지 캘린더와 자연어 검색으로 만드는 특별한 금융 경험
jimmy.im 카카오페이가 과거에 확보한 결제처를 사용자에게 사용하도록 유인하는 매우 효과적인 서비스 같아요!waiki.ki 내 소비 캘린더에 그림일기를 자동으로 생성해 주는 아이디어가 매력적인 서비스입니다. AI를 활용하여 일상을 기록해 주는 서비스를 어떻게 구현했는지 궁금하신 분들에게 이 글을 추천합니다~안녕하세요. 제 2회 카카오페이 해커톤에서 2등을 수상한 모즈(MOZ)팀입니다.저희는 사용자의 평범한 거래 내역을 좀 더 특별한 기억으로 변환하고, 자연어 기반 검색으로 쉽고 의미 있는 금융 관리를 돕는 서비스를 기획했습니다. 이 글을 통해, 어떤 기획 배경에서 아이디어가 시작되었으며, 이 서비스를 구현하기 위해 어떤 AI 및 클라우드 기술들을 사용했고, 왜 그 기술들을 선택하게 되었는지 저희의 경험과 고민을 나누고자 합니다.특히 최신 기술을 활용하여 사용자 문제를 해결하고 새로운 서비스를 만들어나가는 과정에 관심 있는 개발자, 기획자, 디자이너 및 관련 분야 학생분들께 저희의 이야기가 흥미로운 사례이자 작은 영감이 되기를 바랍니다. 함께 자세히 알아보시죠!기획 배경: 평범한 거래 내역에 특별함을 더하다카카오페이의 통합내역 서비스를 이용해 보셨나요? 통합내역 서비스는 연결된 자산의 거래내역들을 한 곳에 모아 편리하게 관리할 수 있는 서비스입니다.저희는 통합내역 서비스에 보이는 사용자들의 소중한 거래 내역 데이터를 풍성하게 기록하고 싶었습니다. 단순히 스쳐 지나가는 기록이 아닌, 그날의 의미와 추억을 담아 특별하게 만들고, 나아가 그 기록을 통해 하루를 되돌아볼 수 있다면 얼마나 좋을까 하는 상상에서 저희 서비스의 아이디어가 시작되었습니다.현재 통합내역 서비스에 보이는 거래 내역에는 기본적인 내용만 노출되고 있기 때문에 어디서, 누구와, 무엇을 하며 발생한 거래 내역인지에 대한 구체적인 맥락을 파악하기 어렵습니다. 이러한 아쉬움을 달래고자 메모 기능을 활용해야 했는데, 현재 제공되는 메모 기능은 문자열 입력으로만 제공되고 있어, 입력 과정이 귀찮고 허들이 높다고 생각했습니다.저희는 바로 이 지점에 주목했습니다. 메모 입력 과정을 쉽고 간편하게 개선하여 거래 내역에 풍부한 의미를 담고, 이 풍부한 메모 데이터를 기반으로 거래 내역을 특별하게 만들어 줄 뿐만 아니라, 더욱 편리한 검색 기능까지 제공하는 서비스를 기획하게 되었습니다.서비스 주요 기능: 쉽고 특별하고 편리하게저희가 해커톤을 통해 구현하고자 했던 핵심 기능은 다음과 같습니다.1️⃣ 쉽고 간편한 메모 기록: 거래 내역에 쉽고 빠르게 의미를 부여할 수 있는 기능 2️⃣ 특별한 요약: 기록된 메모를 기반으로 시각적인 재미를 더하고 추억을 떠올릴 수 있는 기능 3️⃣ 손쉬운 검색 및 조회: 풍부한 메모 데이터를 활용하여 원하는 거래 내역을 손쉽게 찾아볼 수 있는 기능저희는 사용자가 쉽고 직관적으로 거래 내역에 메모를 기록할 수 있도록 칩 선택 방식을 도입했습니다. ‘무엇을 했는지 (목적)’, ‘누구와 함께였는지 (인물)’, ‘그때 기분은 어땠는지 (감정)’ 등의 카테고리에서 간단한
5/15/2025
logo
거래내역에 감성과 지능을 더하다: 이미지 캘린더와 자연어 검색으로 만드는 특별한 금융 경험
jimmy.im 카카오페이가 과거에 확보한 결제처를 사용자에게 사용하도록 유인하는 매우 효과적인 서비스 같아요!waiki.ki 내 소비 캘린더에 그림일기를 자동으로 생성해 주는 아이디어가 매력적인 서비스입니다. AI를 활용하여 일상을 기록해 주는 서비스를 어떻게 구현했는지 궁금하신 분들에게 이 글을 추천합니다~안녕하세요. 제 2회 카카오페이 해커톤에서 2등을 수상한 모즈(MOZ)팀입니다.저희는 사용자의 평범한 거래 내역을 좀 더 특별한 기억으로 변환하고, 자연어 기반 검색으로 쉽고 의미 있는 금융 관리를 돕는 서비스를 기획했습니다. 이 글을 통해, 어떤 기획 배경에서 아이디어가 시작되었으며, 이 서비스를 구현하기 위해 어떤 AI 및 클라우드 기술들을 사용했고, 왜 그 기술들을 선택하게 되었는지 저희의 경험과 고민을 나누고자 합니다.특히 최신 기술을 활용하여 사용자 문제를 해결하고 새로운 서비스를 만들어나가는 과정에 관심 있는 개발자, 기획자, 디자이너 및 관련 분야 학생분들께 저희의 이야기가 흥미로운 사례이자 작은 영감이 되기를 바랍니다. 함께 자세히 알아보시죠!기획 배경: 평범한 거래 내역에 특별함을 더하다카카오페이의 통합내역 서비스를 이용해 보셨나요? 통합내역 서비스는 연결된 자산의 거래내역들을 한 곳에 모아 편리하게 관리할 수 있는 서비스입니다.저희는 통합내역 서비스에 보이는 사용자들의 소중한 거래 내역 데이터를 풍성하게 기록하고 싶었습니다. 단순히 스쳐 지나가는 기록이 아닌, 그날의 의미와 추억을 담아 특별하게 만들고, 나아가 그 기록을 통해 하루를 되돌아볼 수 있다면 얼마나 좋을까 하는 상상에서 저희 서비스의 아이디어가 시작되었습니다.현재 통합내역 서비스에 보이는 거래 내역에는 기본적인 내용만 노출되고 있기 때문에 어디서, 누구와, 무엇을 하며 발생한 거래 내역인지에 대한 구체적인 맥락을 파악하기 어렵습니다. 이러한 아쉬움을 달래고자 메모 기능을 활용해야 했는데, 현재 제공되는 메모 기능은 문자열 입력으로만 제공되고 있어, 입력 과정이 귀찮고 허들이 높다고 생각했습니다.저희는 바로 이 지점에 주목했습니다. 메모 입력 과정을 쉽고 간편하게 개선하여 거래 내역에 풍부한 의미를 담고, 이 풍부한 메모 데이터를 기반으로 거래 내역을 특별하게 만들어 줄 뿐만 아니라, 더욱 편리한 검색 기능까지 제공하는 서비스를 기획하게 되었습니다.서비스 주요 기능: 쉽고 특별하고 편리하게저희가 해커톤을 통해 구현하고자 했던 핵심 기능은 다음과 같습니다.1️⃣ 쉽고 간편한 메모 기록: 거래 내역에 쉽고 빠르게 의미를 부여할 수 있는 기능 2️⃣ 특별한 요약: 기록된 메모를 기반으로 시각적인 재미를 더하고 추억을 떠올릴 수 있는 기능 3️⃣ 손쉬운 검색 및 조회: 풍부한 메모 데이터를 활용하여 원하는 거래 내역을 손쉽게 찾아볼 수 있는 기능저희는 사용자가 쉽고 직관적으로 거래 내역에 메모를 기록할 수 있도록 칩 선택 방식을 도입했습니다. ‘무엇을 했는지 (목적)’, ‘누구와 함께였는지 (인물)’, ‘그때 기분은 어땠는지 (감정)’ 등의 카테고리에서 간단한
2025.05.15
emoji
좋아요
emoji
별로에요
logo
기억하는 AI : Agentic Memory 그리고 A-MEN
자율 에이전트(Autonomous Agent)에 대해 살펴본게 엊그제 같은데 이게 현실화 되는걸 눈으로 보는게 신기한 시대입니다.이게 가능했던 이유는 바로 추론(reasoning) 모델이 등장했기 때문입니다. 추론 모델(Reasoning Model)과 Autonomous Agent는 뇌(두뇌)와 몸(행동 주체)의 관계처럼, 서로 유기적으로 연결되어 있습니다.Autonomous Agent는 memory, planning, action, tools로 구성됩니다. 여기에서 Agentic Memory는 Long-term memory에 속합니다.추론 모델은 Chain-of-Thought, Tree-of-Thought, ReAct, Reflection-Rewrite 등을 통해 복잡한 문제를 해결하기 위해 생각의 흐름을 구성하고 실행 전략을 만듭니다.이렇게 만들어진 모델을 이용하여 Autonomous Agent는 검색, API 호출, DB 조회, 문서 생성 등 다양한 도구나 기능을 활용하여 외부 목표를 받아 스스로 계획하고, 판단하고, 실행합니다.• None• None Reflection: 자신이 낸 답을 다시 보고 수정• None Toolformer: 적절한 시점에 도구 사용 결정어시스턴트 app에서 autonouos agnet와 agent memory의 관계를 설명해 보겠습니다.용자 발화가 입력되면 autonomous agent 의 역할을 하는 executor가 추론 모델 (llm core, planner, reflector)과 agentic memory에서 사용자 발화에 대한 답변을 수행합니다.아래 시퀀스 다이어그램에서는 뭉치에 대해 물어보는 과정에 llm과 memory의 프로세스를 설명합니다. 메모리에는 이 사용자의 반려견 이름이 뭉치라는 것이 저장되어 있습니다.사용자 발화를 중심으로 Autonomous agent가 llm을 통해 agentic memory를 이용하여 개인화된 정보를 가져오는 과정을 설명해 보겠습니다.“뭉치는 물놀이 좋아해?”에이전트는 이 발화를 Autonomous agent를 통해 LLM에 전달하고, 내부적으로 Planner 모듈이 호출됩니다.Planner는 뭉치와 물놀이 관계에 대해 Agentic Memory에서 조회하지만 관련된 항목이 없는 상태입니다.이 결과는 LLM을 통해 자연어로 변환되어 사용자에게 전달되며, 에이전트는 다음과 같이 답변합니다:“기억에 없어요. 알려주세요!”이후 사용자가 정보를 제공합니다:“뭉치는 수영장에서 놀기를 좋아해요.”해당 입력은 Autonomous agent를 통해 Reflection 모듈로 전달되며, Reflection는 이 정보를 구조화하고 요약하여 Agentic Memory에 저장합니다.이 저장 과정은 향후 동일하거나 유사한 질문에 대해 정확한 정보를 반환하기 위한 학습 과정입니다. 시간이 지난 후에 사용자가 이후 동일한 질문을 반복해봅니다:“뭉치가 좋아하는 놀이 뭐였지?”Autonomous agent는 이전과 동일하게 Planner를 통해 memory를 조회하고, 이번에는 저장된 내용을 기반으로 응답을 생성합니다.Agentic Memory는 관련 정보를 반환하고, LLM은 이를 자연어로 표현하여 다음과 같은 응답을 출력합니다:“뭉치는 수영장에서 놀기를 좋아해요.”이로써 뭉치가 수영장에서 노는 것을 좋아하는 것이 memory에 저장되고 다음번에 유사한 질문을 하더라도 어시스턴트는 이를 근거로 답변을 하게 됩니다.A-MEM(Agentic Memory for LLM Agents)은 Rutgers University, Ant Group, Salesforce Research의 공동 연구로 개발된 차세대 AI 메모리 시스템입니다.이 시스템은 대형 언어 모델(LLM) 기반 에이전트가 장기적인 상호작용과 복잡한 추론을 수행할 수 있도록 지원합니다.A-MEM은 Zettelkasten 방식에서 영감을 받아, 각 상호작용을 ‘노트’로 저장합니다.각 노트는 다음과 같은 구조화된 속성을 포함합니다 Zettelkasten(체텔카스텐)은 “노트 카드 상자”를 뜻하는 단어로, 지식을 축적하고 연결해가는 지식 관리 시스템 또는 생각 정리법입니다.새로운 노트가 추가되면, A-MEM은 기존 메모리와의 의미론적 유사성을 분석하여 관련된 노트들과 자동으로 연결(link)을 생성합니다.이 과정은 단순한 키워드 매칭을 넘어서, LLM이 생성한 컨텍스트를 기반으로 하여 더 깊은 수준의 의미론적 연결을 형성합니다.A-MEM 아키텍처 다이어그램에이전트가 새로운 상호작용을 경험하면, A-MEM은 이를 구조화된 메모리 노트로 변환합니다. 각 노트는 다음과 같은 속성을 포함합니다:• None 태그 (Tags): 주제나 범주를 나타내는 분류 정보• None 컨텍스트 (Context): LLM이 생성한 의미론적 요약• None 임베딩 (Embedding): 노트의 의미를 벡터로 표현한 값이러한 구조화된 노트는 에이전트가 정보를 체계적으로 저장하고, 필요할 때 효과적으로 검색할 수 있도록 합니다.새로운 노트가 추가되면, A-MEM은 기존 메모리와의 의미론적 유사성을 분석하여 관련된 노트들과 자동으로 연결(link)을 생성합니다.이 과정은 단순한 키워드 매칭을 넘어서, LLM이 생성한 컨텍스트를 기반으로 하여 더 깊은 수준의 의미론적 연결을 형성합니다.새로운 노트가 추가되면, A-MEM은 기존 메모리의 컨텍스트와 태그를 업데이트하여 메모리 네트워크가 지속적으로 진화할 수 있도록 합니다.이러한 메모리 진화는 에이전트가 과거 경험을 바탕으로 새로운 상황에 적응하고, 더 정교한 추론을 수행할 수 있게 합니다.에이전트가 새로운 질문이나 작업을 수행할 때, A-MEM은 현재의 상호작용과 관련된 과거의 경험을 효과적으로 검색하여 활용합니다.이를 통해 에이전트는 현재의 상호작용과 관련된 과거의 경험을 효과적으로 활용할 수 있습니다.A-MEM은 ChromaDB와 같은 벡터 데이터베이스를 활용하여, 의미론적 유사성에 기반한 빠르고 정확한 메모리 검색을 지원합니다.이를 통해 에이전트는 현재의 상호작용과 관련된 과거의 경험을 효과적으로 활용할 수 있습니다.Agentic Memory의 가장 큰
5/14/2025
logo
기억하는 AI : Agentic Memory 그리고 A-MEN
자율 에이전트(Autonomous Agent)에 대해 살펴본게 엊그제 같은데 이게 현실화 되는걸 눈으로 보는게 신기한 시대입니다.이게 가능했던 이유는 바로 추론(reasoning) 모델이 등장했기 때문입니다. 추론 모델(Reasoning Model)과 Autonomous Agent는 뇌(두뇌)와 몸(행동 주체)의 관계처럼, 서로 유기적으로 연결되어 있습니다.Autonomous Agent는 memory, planning, action, tools로 구성됩니다. 여기에서 Agentic Memory는 Long-term memory에 속합니다.추론 모델은 Chain-of-Thought, Tree-of-Thought, ReAct, Reflection-Rewrite 등을 통해 복잡한 문제를 해결하기 위해 생각의 흐름을 구성하고 실행 전략을 만듭니다.이렇게 만들어진 모델을 이용하여 Autonomous Agent는 검색, API 호출, DB 조회, 문서 생성 등 다양한 도구나 기능을 활용하여 외부 목표를 받아 스스로 계획하고, 판단하고, 실행합니다.• None• None Reflection: 자신이 낸 답을 다시 보고 수정• None Toolformer: 적절한 시점에 도구 사용 결정어시스턴트 app에서 autonouos agnet와 agent memory의 관계를 설명해 보겠습니다.용자 발화가 입력되면 autonomous agent 의 역할을 하는 executor가 추론 모델 (llm core, planner, reflector)과 agentic memory에서 사용자 발화에 대한 답변을 수행합니다.아래 시퀀스 다이어그램에서는 뭉치에 대해 물어보는 과정에 llm과 memory의 프로세스를 설명합니다. 메모리에는 이 사용자의 반려견 이름이 뭉치라는 것이 저장되어 있습니다.사용자 발화를 중심으로 Autonomous agent가 llm을 통해 agentic memory를 이용하여 개인화된 정보를 가져오는 과정을 설명해 보겠습니다.“뭉치는 물놀이 좋아해?”에이전트는 이 발화를 Autonomous agent를 통해 LLM에 전달하고, 내부적으로 Planner 모듈이 호출됩니다.Planner는 뭉치와 물놀이 관계에 대해 Agentic Memory에서 조회하지만 관련된 항목이 없는 상태입니다.이 결과는 LLM을 통해 자연어로 변환되어 사용자에게 전달되며, 에이전트는 다음과 같이 답변합니다:“기억에 없어요. 알려주세요!”이후 사용자가 정보를 제공합니다:“뭉치는 수영장에서 놀기를 좋아해요.”해당 입력은 Autonomous agent를 통해 Reflection 모듈로 전달되며, Reflection는 이 정보를 구조화하고 요약하여 Agentic Memory에 저장합니다.이 저장 과정은 향후 동일하거나 유사한 질문에 대해 정확한 정보를 반환하기 위한 학습 과정입니다. 시간이 지난 후에 사용자가 이후 동일한 질문을 반복해봅니다:“뭉치가 좋아하는 놀이 뭐였지?”Autonomous agent는 이전과 동일하게 Planner를 통해 memory를 조회하고, 이번에는 저장된 내용을 기반으로 응답을 생성합니다.Agentic Memory는 관련 정보를 반환하고, LLM은 이를 자연어로 표현하여 다음과 같은 응답을 출력합니다:“뭉치는 수영장에서 놀기를 좋아해요.”이로써 뭉치가 수영장에서 노는 것을 좋아하는 것이 memory에 저장되고 다음번에 유사한 질문을 하더라도 어시스턴트는 이를 근거로 답변을 하게 됩니다.A-MEM(Agentic Memory for LLM Agents)은 Rutgers University, Ant Group, Salesforce Research의 공동 연구로 개발된 차세대 AI 메모리 시스템입니다.이 시스템은 대형 언어 모델(LLM) 기반 에이전트가 장기적인 상호작용과 복잡한 추론을 수행할 수 있도록 지원합니다.A-MEM은 Zettelkasten 방식에서 영감을 받아, 각 상호작용을 ‘노트’로 저장합니다.각 노트는 다음과 같은 구조화된 속성을 포함합니다 Zettelkasten(체텔카스텐)은 “노트 카드 상자”를 뜻하는 단어로, 지식을 축적하고 연결해가는 지식 관리 시스템 또는 생각 정리법입니다.새로운 노트가 추가되면, A-MEM은 기존 메모리와의 의미론적 유사성을 분석하여 관련된 노트들과 자동으로 연결(link)을 생성합니다.이 과정은 단순한 키워드 매칭을 넘어서, LLM이 생성한 컨텍스트를 기반으로 하여 더 깊은 수준의 의미론적 연결을 형성합니다.A-MEM 아키텍처 다이어그램에이전트가 새로운 상호작용을 경험하면, A-MEM은 이를 구조화된 메모리 노트로 변환합니다. 각 노트는 다음과 같은 속성을 포함합니다:• None 태그 (Tags): 주제나 범주를 나타내는 분류 정보• None 컨텍스트 (Context): LLM이 생성한 의미론적 요약• None 임베딩 (Embedding): 노트의 의미를 벡터로 표현한 값이러한 구조화된 노트는 에이전트가 정보를 체계적으로 저장하고, 필요할 때 효과적으로 검색할 수 있도록 합니다.새로운 노트가 추가되면, A-MEM은 기존 메모리와의 의미론적 유사성을 분석하여 관련된 노트들과 자동으로 연결(link)을 생성합니다.이 과정은 단순한 키워드 매칭을 넘어서, LLM이 생성한 컨텍스트를 기반으로 하여 더 깊은 수준의 의미론적 연결을 형성합니다.새로운 노트가 추가되면, A-MEM은 기존 메모리의 컨텍스트와 태그를 업데이트하여 메모리 네트워크가 지속적으로 진화할 수 있도록 합니다.이러한 메모리 진화는 에이전트가 과거 경험을 바탕으로 새로운 상황에 적응하고, 더 정교한 추론을 수행할 수 있게 합니다.에이전트가 새로운 질문이나 작업을 수행할 때, A-MEM은 현재의 상호작용과 관련된 과거의 경험을 효과적으로 검색하여 활용합니다.이를 통해 에이전트는 현재의 상호작용과 관련된 과거의 경험을 효과적으로 활용할 수 있습니다.A-MEM은 ChromaDB와 같은 벡터 데이터베이스를 활용하여, 의미론적 유사성에 기반한 빠르고 정확한 메모리 검색을 지원합니다.이를 통해 에이전트는 현재의 상호작용과 관련된 과거의 경험을 효과적으로 활용할 수 있습니다.Agentic Memory의 가장 큰
2025.05.14
emoji
좋아요
emoji
별로에요
logo
Kotlin과 JPA의 한계 극복: 빌링 시스템 고도화 과정
저희는 Kotlin + Spring Boot 기반으로 개발한 빌링 시스템을 수년간 운영하고 있습니다.시스템 개발 착수 당시 기준으로 비교적 최신 버전인 Kotlin, Spring Boot, Spring Data JPA, 그리고 QueryDSL 조합으로 서비스의 주요 기능을 개발해왔습니다.그러나 시간이 지나면서 기술적 부채가 쌓이고 시스템의 사용량이 늘어나면서 성능에 대한 문제도 발생하기 시작하여 이를 해결하기 위한 고도화를 진행하게 되었습니다.이 글에서는 그 배경과 과정, 그리고 저희가 선택한 기술적 판단들 중에 일부를 공유하고자 합니다.처음에 시스템 개발은 아래와 같은 기술 스택으로 진행했습니다.이러한 조합은 이미 Java 환경에서 널리 사용되는 검증된 방식이었고, Kotlin 환경에서도 큰 문제 없이 사용 가능할 것이라고 생각했습니다.하지만, 개발하고 시스템을 운영하는 과정에서 다음과 같은 문제들이 발생했습니다.Kotlin 의 data class 와 JPA의 궁합 문제Kotlin 의 data class 는 불변성과 copy 메서드, 구조 분해 등의 강력한 기능을 제공합니다.그러나 JPA 는 불변성을 고려하여 설계된 기술이 아니기 때문에 data class 를 엔티티 클래스로 사용할 수 없었습니다.따라서 아래와 같이 설계하게 되었는데요,프로퍼티가 다른 코드에 의해 변경될 수 있고 의도치 않은 데이터 변경이 일어날 수 있어서, 엔티티와 비슷한 모습의 불변 DTO 클래스를 추가로 작성하여 사용해야 했습니다.이런 구조는 초기 개발 당시 큰 문제로 느껴지지는 않았지만 시간이 흐르면서 DTO 가 중구난방으로 추가되는 문제가 발생하기 시작했습니다.그래서 이렇게 사용하면 참 좋겠다는 생각을 많이 하게 되었습니다.데이터의 양이 많아지면서 쿼리 성능에 문제가 발생하기 시작했고, SQL 을 새로 작성하거나 튜닝해야 했습니다.하지만 QueryDSL 이 지원하는 기능에는 한계가 있어서 원하는대로 작업할 수 없거나 복잡하게 개발을 해야했습니다.SQL 하나를 간략하게 예를 들어보자면 아래와 같은 sub query 를 실행하기 위해서이런 클래스를 작성해야 했습니다.결국 Native Query 를 사용하게 되면서 QueryDSL 을 통해 얻을 수 있는 타입 안전성이나 DB 의존성 회피 등 JPA 의 장점을 일부 포기하는 타협을 하게 되었습니다.게다가 현재 QueryDSL은 더 이상 원작자에 의해 공식적으로 유지보수되지 않고 있으며,현재는 OpenFeign 에 의해 fork 되어 이어지고 있는 상태로 장기적인 측면에서 봤을 때 지속성에 의구심이 들었습니다.문제 해결은 이렇게 하기로...일단 최신 언어의 기능과 성능 개선점을 도입하기 위해 전반적인 기술 스택 업그레이드 및 변경을 진행했습니다.이를 통해 Spring 의 최신 기능들과 Kotlin 의 K2 컴파일러, Java 의 Virtual Thread 등을 사용할 수 있게 되었습니다.jOOQ 는 QueryDSL 과 동일하게 타입에 안전한 코드를 작성할 수 있고, Native SQL 과 100% 호환되어 복잡한 쿼리를 작성하는데 문제가 없어 보였습니다.그리고 Kotlin 과도 궁합이 좋아서 동적 쿼리 작성 도구로 선택되었습니다.jOOQ 도 QueryDSL 과 마찬가지로 메타모델 클래스를 생성해야 한다는 불편함이 있지만, 타입 안전성을 위해서는 피할 수 없는 부분이고annotation processor 기반이었던 QueryDSL 과는 달리 jOOQ 는 SQL DSL 코드 생성 기반이라 좀 더 안정적이고 직관적인 개발이 가능했습니다.DDL 스크립트를 바탕으로 메타모델 클래스 생성을 위한 build.gradle.kts 예시솔루션 적용은 이런 순서로...빌링 시스템의 특성 상 영속성 프레임워크의 전면 교체는 위험 부담이 크기 때문에 다음과 같은 순서로 고도화하는 전략을 택했습니다:• None 복잡한 조회 쿼리를 중심으로 작성된 QueryDSL 기반 코드를 jOOQ 로 우선 전환하고• None 성능 개선 여부와 유지보수 용이성을 일정 기간동안 검증했습니다.JPA 으로 구현한 CRUD 기능을 서서히 변경• None 변경이 적은 엔티티부터 JPA에서 JDBC 기반 구현으로 서서히 교체하면서• None 도메인 모델은 불변 객체(immutable object)로 새로 작성했습니다.• None 데이터를 서비스 기능의 요구에 맞게 제공하기 위해 aggregation 클래스를 도입하여• None jOOQ 나 JDBC 로 가져온 엔티티를 조합해 응답 객체를 구성하며, 불필요해진 DTO 클래스를 제거했습니다.• None JPA, QueryDSL 의 한계를 벗어나 순수 SQL 과 같은 수준에서 자유로운 쿼리를 작성 가능해졌습니다.• None 서브쿼리, 윈도우 함수, DBMS 특화 기능 등을 코드로 명확하게 구현 할 수 있었습니다.• None 코드 수정량은 많았지만... 필요 없는 Lazy 로딩이나 N+1 이슈 등, 원하지 않았던 join 발생 등을 줄일 수 있었습니다.• None 원하는 대로 SQL 을 작성할 수 있다보니 튜닝으로 응답 시간 개선도 가능했습니다.• None Kotlin 의 장점을 살려 불변 모델로 작성함으로써 도메인의 안정성이 향상되었다고 생각되고• None Aggregation 클래스를 통해 비즈니스 요구에 맞는 응답 구조를 명확히 분리했습니다.• None 그리고 불필요한 클래스 파일을 제거하면서 다이어트 효과도 얻을 수 있었습니다.빌드 및 운영 환경에서의 안정성 향상• None QueryDSL 사용으로 인한 annotation processor 이슈, 버전 충돌 이슈 등을 제거함으로써 전체적인 기술 스택 업그레이드가 가능했고 개발 생산성도 향상되었다고 생각합니다.JPA 는 오랜 시간 널리 사용되어온 강력한 기술이지만, Kotlin 을 본격적으로 도입하면서 그 한계를 깊이 체감하게 되었습니다."잘 동작하는 시스템은 건드리지 말라"는 업계의 속설을 한 번쯤은 접해보셨을 듯 한데요저희는 더 나은 개발 환경과 미래의 저희를 위해 손을 대버렸고, 결과적으로는 잘한 선택이라고 생각합니다.사실 Kotlin Exposed 으로 도전해볼껄 하는 아쉬움이 조금은 남지만, 너
java
kotlin
spring
5/14/2025
logo
Kotlin과 JPA의 한계 극복: 빌링 시스템 고도화 과정
저희는 Kotlin + Spring Boot 기반으로 개발한 빌링 시스템을 수년간 운영하고 있습니다.시스템 개발 착수 당시 기준으로 비교적 최신 버전인 Kotlin, Spring Boot, Spring Data JPA, 그리고 QueryDSL 조합으로 서비스의 주요 기능을 개발해왔습니다.그러나 시간이 지나면서 기술적 부채가 쌓이고 시스템의 사용량이 늘어나면서 성능에 대한 문제도 발생하기 시작하여 이를 해결하기 위한 고도화를 진행하게 되었습니다.이 글에서는 그 배경과 과정, 그리고 저희가 선택한 기술적 판단들 중에 일부를 공유하고자 합니다.처음에 시스템 개발은 아래와 같은 기술 스택으로 진행했습니다.이러한 조합은 이미 Java 환경에서 널리 사용되는 검증된 방식이었고, Kotlin 환경에서도 큰 문제 없이 사용 가능할 것이라고 생각했습니다.하지만, 개발하고 시스템을 운영하는 과정에서 다음과 같은 문제들이 발생했습니다.Kotlin 의 data class 와 JPA의 궁합 문제Kotlin 의 data class 는 불변성과 copy 메서드, 구조 분해 등의 강력한 기능을 제공합니다.그러나 JPA 는 불변성을 고려하여 설계된 기술이 아니기 때문에 data class 를 엔티티 클래스로 사용할 수 없었습니다.따라서 아래와 같이 설계하게 되었는데요,프로퍼티가 다른 코드에 의해 변경될 수 있고 의도치 않은 데이터 변경이 일어날 수 있어서, 엔티티와 비슷한 모습의 불변 DTO 클래스를 추가로 작성하여 사용해야 했습니다.이런 구조는 초기 개발 당시 큰 문제로 느껴지지는 않았지만 시간이 흐르면서 DTO 가 중구난방으로 추가되는 문제가 발생하기 시작했습니다.그래서 이렇게 사용하면 참 좋겠다는 생각을 많이 하게 되었습니다.데이터의 양이 많아지면서 쿼리 성능에 문제가 발생하기 시작했고, SQL 을 새로 작성하거나 튜닝해야 했습니다.하지만 QueryDSL 이 지원하는 기능에는 한계가 있어서 원하는대로 작업할 수 없거나 복잡하게 개발을 해야했습니다.SQL 하나를 간략하게 예를 들어보자면 아래와 같은 sub query 를 실행하기 위해서이런 클래스를 작성해야 했습니다.결국 Native Query 를 사용하게 되면서 QueryDSL 을 통해 얻을 수 있는 타입 안전성이나 DB 의존성 회피 등 JPA 의 장점을 일부 포기하는 타협을 하게 되었습니다.게다가 현재 QueryDSL은 더 이상 원작자에 의해 공식적으로 유지보수되지 않고 있으며,현재는 OpenFeign 에 의해 fork 되어 이어지고 있는 상태로 장기적인 측면에서 봤을 때 지속성에 의구심이 들었습니다.문제 해결은 이렇게 하기로...일단 최신 언어의 기능과 성능 개선점을 도입하기 위해 전반적인 기술 스택 업그레이드 및 변경을 진행했습니다.이를 통해 Spring 의 최신 기능들과 Kotlin 의 K2 컴파일러, Java 의 Virtual Thread 등을 사용할 수 있게 되었습니다.jOOQ 는 QueryDSL 과 동일하게 타입에 안전한 코드를 작성할 수 있고, Native SQL 과 100% 호환되어 복잡한 쿼리를 작성하는데 문제가 없어 보였습니다.그리고 Kotlin 과도 궁합이 좋아서 동적 쿼리 작성 도구로 선택되었습니다.jOOQ 도 QueryDSL 과 마찬가지로 메타모델 클래스를 생성해야 한다는 불편함이 있지만, 타입 안전성을 위해서는 피할 수 없는 부분이고annotation processor 기반이었던 QueryDSL 과는 달리 jOOQ 는 SQL DSL 코드 생성 기반이라 좀 더 안정적이고 직관적인 개발이 가능했습니다.DDL 스크립트를 바탕으로 메타모델 클래스 생성을 위한 build.gradle.kts 예시솔루션 적용은 이런 순서로...빌링 시스템의 특성 상 영속성 프레임워크의 전면 교체는 위험 부담이 크기 때문에 다음과 같은 순서로 고도화하는 전략을 택했습니다:• None 복잡한 조회 쿼리를 중심으로 작성된 QueryDSL 기반 코드를 jOOQ 로 우선 전환하고• None 성능 개선 여부와 유지보수 용이성을 일정 기간동안 검증했습니다.JPA 으로 구현한 CRUD 기능을 서서히 변경• None 변경이 적은 엔티티부터 JPA에서 JDBC 기반 구현으로 서서히 교체하면서• None 도메인 모델은 불변 객체(immutable object)로 새로 작성했습니다.• None 데이터를 서비스 기능의 요구에 맞게 제공하기 위해 aggregation 클래스를 도입하여• None jOOQ 나 JDBC 로 가져온 엔티티를 조합해 응답 객체를 구성하며, 불필요해진 DTO 클래스를 제거했습니다.• None JPA, QueryDSL 의 한계를 벗어나 순수 SQL 과 같은 수준에서 자유로운 쿼리를 작성 가능해졌습니다.• None 서브쿼리, 윈도우 함수, DBMS 특화 기능 등을 코드로 명확하게 구현 할 수 있었습니다.• None 코드 수정량은 많았지만... 필요 없는 Lazy 로딩이나 N+1 이슈 등, 원하지 않았던 join 발생 등을 줄일 수 있었습니다.• None 원하는 대로 SQL 을 작성할 수 있다보니 튜닝으로 응답 시간 개선도 가능했습니다.• None Kotlin 의 장점을 살려 불변 모델로 작성함으로써 도메인의 안정성이 향상되었다고 생각되고• None Aggregation 클래스를 통해 비즈니스 요구에 맞는 응답 구조를 명확히 분리했습니다.• None 그리고 불필요한 클래스 파일을 제거하면서 다이어트 효과도 얻을 수 있었습니다.빌드 및 운영 환경에서의 안정성 향상• None QueryDSL 사용으로 인한 annotation processor 이슈, 버전 충돌 이슈 등을 제거함으로써 전체적인 기술 스택 업그레이드가 가능했고 개발 생산성도 향상되었다고 생각합니다.JPA 는 오랜 시간 널리 사용되어온 강력한 기술이지만, Kotlin 을 본격적으로 도입하면서 그 한계를 깊이 체감하게 되었습니다."잘 동작하는 시스템은 건드리지 말라"는 업계의 속설을 한 번쯤은 접해보셨을 듯 한데요저희는 더 나은 개발 환경과 미래의 저희를 위해 손을 대버렸고, 결과적으로는 잘한 선택이라고 생각합니다.사실 Kotlin Exposed 으로 도전해볼껄 하는 아쉬움이 조금은 남지만, 너
2025.05.14
java
kotlin
spring
emoji
좋아요
emoji
별로에요
logo
코드 품질 개선 기법 11편: 반복되는 호출에 함수도 지친다
안녕하세요. 커뮤니케이션 앱 LINE의 모바일 클라이언트를 개발하고 있는 Ishikawa입니다.저희 회사는 높은 개발 생산성을 유지하기 위해 코드 품질 및 개발 문화 개선에 힘쓰고 있습니다. 이를 위해 다양한 노력을 하고 있는데요. 그중 하나가 Review Committee 활동입니다.Review Committee에서는 머지된 코드를 다시 리뷰해 리뷰어와 작성자에게 피드백을 주고, 리뷰하면서 얻은 지식과 인사이트를 Weekly Report라는 이름으로 매주 공유하고 있습니다. 이 Weekly Report 중 일반적으로 널리 적용할 수 있는 주제를 골라 블로그에 코드 품질 개선 기법 시리즈를 연재하고 있습니다.이번에 블로그로 공유할 Weekly Report의 제목은 '반복되는 호출에 함수도 지친다'입니다.반복되는 호출에 함수도 지친다어떤 서비스에서 사용자끼리 '친구'가 되는 기능을 구현하려고 합니다. 현재 사용자 입장에서 다른 사용자가 친구인지 확인하거나 새로 친구를 추가하는 기능을 구현하기 위해 다음과 같은 클래스를 사용한다고 가정해 봅시다.호출자 측 코드는 다음과 같습니다.위 코드에 문제가 있을까요?호출자 측 코드의 구조를 추출하면 가 됩니다. 즉, '현재 수신 객체의 상태에 따라 수신 객체를 변경'하는 코드가 되는데요. 이렇게 '현재 수신 객체의 상태에 따라 수신 객체를 변경'하는 경우 상태를 변경하는 함수 자체에서 확인하도록 만드는 것이 더 좋은 경우가 많습니다.위 코드에서 의 경우 이미 를 충족하는 것으로 가정하는 것 같습니다. 만약 사용자가 이미 친구인 상태에서 를 호출하면 예외가 발생하는 등 를 꼭 확인해야 하는 경우에 확인이 누락된다면 버그가 발생할 것입니다. 이를 해결하려면 확인을 내부에서 수행하는 것이 좋습니다.이미 친구 상태일 때 가 아무것도 하지 않는 것은 자연스러운 동작으로 보이는 경우가 많습니다. 하지만 '아무것도 하지 않는다'는 것을 특별히 강조해야 한다면 함수 이름을 으로 바꾸거나 주석으로 조건을 설명해야 합니다.이렇게 수신 객체에게 자신의 상태를 확인하도록 하면 굳이 보여줄 필요가 없는 상태를 숨기고 겉으로 드러나는 상태 전이를 단순화할 수 있습니다.다음 코드를 리팩터링하는 것을 생각해 봅시다.위 코드를 다음과 같이 리팩터링하는 것은 부적절합니다.의 리팩터링이 부적절한 이유는 콜백으로 인해 불필요한 의존성 순환이 발생하기 때문입니다. 또한 언뜻 보기에는 가 동기식 콜백인지 비동기식 콜백인지 알 수 없다는 점도 문제입니다.이런 경우 를 고차 함수로 만드는 것보다 반환값으로 결과를 반환하는 것이 좋습니다. 현재 예시의 경우에는 진위값( )으로 충분합니다.이렇게 하면 이 언제 호출되는지 명확하게 알 수 있습니다. 다만 이렇게 함수 이름에서 반환값을 언급하지 않는 경우에는 문서에서 반환값을 설명해야 합니다(자세한 내용은 Code readability: Session 3 문서를 참고하세요). 또한 필요하다면 호출자가 반환값을 확인하도록 강제하세요(코드 품질 개선 기법 2편: 확인 여부를 확인했나요?의 첫 번째 방법 참고).
5/14/2025
logo
코드 품질 개선 기법 11편: 반복되는 호출에 함수도 지친다
안녕하세요. 커뮤니케이션 앱 LINE의 모바일 클라이언트를 개발하고 있는 Ishikawa입니다.저희 회사는 높은 개발 생산성을 유지하기 위해 코드 품질 및 개발 문화 개선에 힘쓰고 있습니다. 이를 위해 다양한 노력을 하고 있는데요. 그중 하나가 Review Committee 활동입니다.Review Committee에서는 머지된 코드를 다시 리뷰해 리뷰어와 작성자에게 피드백을 주고, 리뷰하면서 얻은 지식과 인사이트를 Weekly Report라는 이름으로 매주 공유하고 있습니다. 이 Weekly Report 중 일반적으로 널리 적용할 수 있는 주제를 골라 블로그에 코드 품질 개선 기법 시리즈를 연재하고 있습니다.이번에 블로그로 공유할 Weekly Report의 제목은 '반복되는 호출에 함수도 지친다'입니다.반복되는 호출에 함수도 지친다어떤 서비스에서 사용자끼리 '친구'가 되는 기능을 구현하려고 합니다. 현재 사용자 입장에서 다른 사용자가 친구인지 확인하거나 새로 친구를 추가하는 기능을 구현하기 위해 다음과 같은 클래스를 사용한다고 가정해 봅시다.호출자 측 코드는 다음과 같습니다.위 코드에 문제가 있을까요?호출자 측 코드의 구조를 추출하면 가 됩니다. 즉, '현재 수신 객체의 상태에 따라 수신 객체를 변경'하는 코드가 되는데요. 이렇게 '현재 수신 객체의 상태에 따라 수신 객체를 변경'하는 경우 상태를 변경하는 함수 자체에서 확인하도록 만드는 것이 더 좋은 경우가 많습니다.위 코드에서 의 경우 이미 를 충족하는 것으로 가정하는 것 같습니다. 만약 사용자가 이미 친구인 상태에서 를 호출하면 예외가 발생하는 등 를 꼭 확인해야 하는 경우에 확인이 누락된다면 버그가 발생할 것입니다. 이를 해결하려면 확인을 내부에서 수행하는 것이 좋습니다.이미 친구 상태일 때 가 아무것도 하지 않는 것은 자연스러운 동작으로 보이는 경우가 많습니다. 하지만 '아무것도 하지 않는다'는 것을 특별히 강조해야 한다면 함수 이름을 으로 바꾸거나 주석으로 조건을 설명해야 합니다.이렇게 수신 객체에게 자신의 상태를 확인하도록 하면 굳이 보여줄 필요가 없는 상태를 숨기고 겉으로 드러나는 상태 전이를 단순화할 수 있습니다.다음 코드를 리팩터링하는 것을 생각해 봅시다.위 코드를 다음과 같이 리팩터링하는 것은 부적절합니다.의 리팩터링이 부적절한 이유는 콜백으로 인해 불필요한 의존성 순환이 발생하기 때문입니다. 또한 언뜻 보기에는 가 동기식 콜백인지 비동기식 콜백인지 알 수 없다는 점도 문제입니다.이런 경우 를 고차 함수로 만드는 것보다 반환값으로 결과를 반환하는 것이 좋습니다. 현재 예시의 경우에는 진위값( )으로 충분합니다.이렇게 하면 이 언제 호출되는지 명확하게 알 수 있습니다. 다만 이렇게 함수 이름에서 반환값을 언급하지 않는 경우에는 문서에서 반환값을 설명해야 합니다(자세한 내용은 Code readability: Session 3 문서를 참고하세요). 또한 필요하다면 호출자가 반환값을 확인하도록 강제하세요(코드 품질 개선 기법 2편: 확인 여부를 확인했나요?의 첫 번째 방법 참고).
2025.05.14
emoji
좋아요
emoji
별로에요
logo
MySQL ALTER DDL 수행 방식에 대한 이해
MySQL은 2000년대부터 웹서비스를 많이 사용하는 개발자들에 의해 많이 사용되었습니다. 오픈 소스로서 사용이 쉬웠을 뿐 아니라 개발자들이 다루기 쉽고 이해하기 쉬운 관계형 데이터베이스이기 때문에 빠르고 가볍게 개발할 수 있는 웹서비스에 최적의 데이터베이스였습니다.하지만, MySQL은 서비스가 잘되고 사용자가 늘어날수록 운영하기 쉽지 않았습니다. 여러 가지 문제가 있었지만, 그 중 하나가 서비스가 운영 중인 상황에서 Online DDL을 수행하기 어렵다는 점이었습니다.이 문제를 해결하기 위해, MySQL은 Ver 5.6부터 기존 COPY 알고리즘을 개선한 In-Place 알고리즘을 추가했습니다. In-Place 알고리즘을 통해 테이블 가용성을 높일 수 있었지만 사용이 편한 것은 아니었습니다. COPY 알고리즘 보다 개선되기는 했지만 DDL 작업의 시작과 종료 시점에 메타 락을 획득해야하고, 작업 종류에 따라서는 Copy 알고리즘과 마찬가지로 임시 테이블 생성 및 데이터 복제 과정도 필요하기 때문입니다. 이 때문에 MySQL Ver. 8.0 부터는 Instant 알고리즘을 추가해 테이블 사이즈와 상관없이 간단한 DDL 작업을 수행할 수 있도록 개선했습니다.MySQL은 현재 이렇게 세 가지 ALTER DDL 알고리즘을 제공합니다. 그래서, 이 문서에서는 MySQL의 ALTER DDL에 관한 주요 함수와 알고리즘, 알고리즘간 Meta Lock 동작을 비교해보며 내부 동작 과정을 자세히 살펴보고자 합니다. 이를 통해 MySQL을 사용하는 서비스 운영에 도움이 되기를 바랍니다.먼저, MySQL이 ALTER DDL을 크게 어떤 단계로 수행하는지 알아보겠습니다.MySQL은 DDL 수행 알고리즘과 무관하게 크게 3단계로 작업을 진행합니다. 단, 후술할 상세 로직 및 함수들은 In-Place/Instant 알고리즘 위주로 작성되어 있습니다.해당 ALTER DDL 문 실행에 사용할 알고리즘과 Lock 유형을 선택하는 단계입니다.작업 순서는 다음과 같습니다.• 사용자가 명시한 알고리즘으로 DDL문을 수행할 수 있는지 확인합니다. ⇒ 컬럼 이름의 중복이나 존재하지 않는 컬럼을 수정하려는 등 테이블 메타 데이터 조회로 바로 확인이 가능한 문제들을 체크합니다.• handler::check_if_supported_inplace_alter() 함수로 ALTER TABLE의 실행에 필요한 Lock 모드를 확인합니다. ⇒ 함수가 반환한 Lock 모드와 사용자가 지정한 Lock 모드를 비교합니다. 둘 사이에 충돌이 발생한다면 오류를 발생하고 작업을 중지합니다. ex) HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE 인데 LOCK=none 설정을 한 경우에 해당합니다.실제 DDL 작업을 수행하는 단계입니다. 앞단계에서 선택한 알고리즘과 Lock 모드를 실제 수행합니다.상세 작업 순서는 다음과 같습니다.• 앞서 선택한 Lock 모드에 필요한 Metadata Lock을 획득합니다. 이 단계에서, MDL_SHARED_UPGRADABLE Metadata Lock을 획득합니다.• In-Place 알고리즘을 선택했다면, Metadata Lock을 MDL_EXCLUSIVE로 승격하여 다른 세션에서 Metadata Lock을 획득하는 것을 차단합니다.• handler:ha_prepare_inplace_alter_table()을 호출해 제약사항을 체크하고, 인덱스와 외래키의 Metadata를 업데이트합니다. Instant 알고리즘의 경우 이 단계를 수행하지 않습니다.• In-Place 알고리즘을 선택했다면, 2번 단계에서 승격했던 Lock 모드를 다시 강등합니다.• DDL 수행 도중 DML이 차단되어야 한다면 Metadata Lock을 MDL_SHARED_NO_WRITE로 강등합니다.• 그렇지 않다면, MDL_SHARED_UPGRADABLE로 강등합니다.• ALTER TABLE에 의해 요청된 변경사항을 실행하기 위해 handler::ha_inplace_alter_table()을 호출합니다. Instant 알고리즘의 경우 이 단계를 수행하지 않습니다.• 작업을 수행하는 테이블에 대한 Metadata Lock을 MDL_EXCLUSIVE로 승격합니다. ⇒ 승격 후, handler::ha_commit_inplace_alter_table()을 호출하여 테이블의 Metadata를 변경합니다.ALTER 작업이 모두 마무리 된 후 정리하는 단계입니다. 지금까지의 변경 내역을 기반으로 Data Dictionary를 업데이트하고 커밋합니다. 스토리지 엔진의 atomic DDL지원 여부에 따라 다음과 같이 마무리 작업을 진행합니다.• Atomic DDL을 지원하는 스토리지 엔진의 경우: ⇒ Old_Table과 New_Table간의 테이블 이름을 변경하는 작업을 먼저 수행하고 Data Dictionary를 업데이트, 커밋합니다.• Atomic DDL을 지원하지 않는 스토리지 엔진의 경우: ⇒ Data Dictionary를 업데이트 하고, Old_Table과 New_Table의 테이블 이름을 변경하는 작업을 수행합니다.마지막으로 지금까지 사용한 객체와 메모리를 정리하고, MDL_SHARED_READ Lock을 획득해 변경된 테이블의 Metadata를 최종 확인하며 마무리합니다.ALTER DDL문이 수행될 때 즉, Execution 단계에서 사용되는 주요 함수는 다음과 같습니다.위 함수들에 대해 간단히 알아보도록 하겠습니다.ALTER DDL과 현재 테이블 명세를 비교합니다. 테이블의 제약사항을 체크하고, 인덱스나 외래키에 대한 Metadata를 업데이트하는 역할을 합니다.여기에서 확인하는 제약사항은 다음과 같습니다.이 단계는 모든 알고리즘에서 수행되는 단계는 아닙니다. Instant 알고리즘을 사용하겠다고 한 ALTER DDL문이라면 이 단계에서 아무 작업도 수행하지 않고 바로 빠져나옵니다.소스 코드 상에서 다음과 같이 확인이 가능합니다.이 함수안에서 실제 ALTER 작업이 수행됩니다. 다음과 같은 작업들이 이 함수 안에서 수행됩니다.Instant 알고리즘을 사용하거나, 또는 In-Place 알고리즘을 사용하지만
mysql
5/14/2025
logo
MySQL ALTER DDL 수행 방식에 대한 이해
MySQL은 2000년대부터 웹서비스를 많이 사용하는 개발자들에 의해 많이 사용되었습니다. 오픈 소스로서 사용이 쉬웠을 뿐 아니라 개발자들이 다루기 쉽고 이해하기 쉬운 관계형 데이터베이스이기 때문에 빠르고 가볍게 개발할 수 있는 웹서비스에 최적의 데이터베이스였습니다.하지만, MySQL은 서비스가 잘되고 사용자가 늘어날수록 운영하기 쉽지 않았습니다. 여러 가지 문제가 있었지만, 그 중 하나가 서비스가 운영 중인 상황에서 Online DDL을 수행하기 어렵다는 점이었습니다.이 문제를 해결하기 위해, MySQL은 Ver 5.6부터 기존 COPY 알고리즘을 개선한 In-Place 알고리즘을 추가했습니다. In-Place 알고리즘을 통해 테이블 가용성을 높일 수 있었지만 사용이 편한 것은 아니었습니다. COPY 알고리즘 보다 개선되기는 했지만 DDL 작업의 시작과 종료 시점에 메타 락을 획득해야하고, 작업 종류에 따라서는 Copy 알고리즘과 마찬가지로 임시 테이블 생성 및 데이터 복제 과정도 필요하기 때문입니다. 이 때문에 MySQL Ver. 8.0 부터는 Instant 알고리즘을 추가해 테이블 사이즈와 상관없이 간단한 DDL 작업을 수행할 수 있도록 개선했습니다.MySQL은 현재 이렇게 세 가지 ALTER DDL 알고리즘을 제공합니다. 그래서, 이 문서에서는 MySQL의 ALTER DDL에 관한 주요 함수와 알고리즘, 알고리즘간 Meta Lock 동작을 비교해보며 내부 동작 과정을 자세히 살펴보고자 합니다. 이를 통해 MySQL을 사용하는 서비스 운영에 도움이 되기를 바랍니다.먼저, MySQL이 ALTER DDL을 크게 어떤 단계로 수행하는지 알아보겠습니다.MySQL은 DDL 수행 알고리즘과 무관하게 크게 3단계로 작업을 진행합니다. 단, 후술할 상세 로직 및 함수들은 In-Place/Instant 알고리즘 위주로 작성되어 있습니다.해당 ALTER DDL 문 실행에 사용할 알고리즘과 Lock 유형을 선택하는 단계입니다.작업 순서는 다음과 같습니다.• 사용자가 명시한 알고리즘으로 DDL문을 수행할 수 있는지 확인합니다. ⇒ 컬럼 이름의 중복이나 존재하지 않는 컬럼을 수정하려는 등 테이블 메타 데이터 조회로 바로 확인이 가능한 문제들을 체크합니다.• handler::check_if_supported_inplace_alter() 함수로 ALTER TABLE의 실행에 필요한 Lock 모드를 확인합니다. ⇒ 함수가 반환한 Lock 모드와 사용자가 지정한 Lock 모드를 비교합니다. 둘 사이에 충돌이 발생한다면 오류를 발생하고 작업을 중지합니다. ex) HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE 인데 LOCK=none 설정을 한 경우에 해당합니다.실제 DDL 작업을 수행하는 단계입니다. 앞단계에서 선택한 알고리즘과 Lock 모드를 실제 수행합니다.상세 작업 순서는 다음과 같습니다.• 앞서 선택한 Lock 모드에 필요한 Metadata Lock을 획득합니다. 이 단계에서, MDL_SHARED_UPGRADABLE Metadata Lock을 획득합니다.• In-Place 알고리즘을 선택했다면, Metadata Lock을 MDL_EXCLUSIVE로 승격하여 다른 세션에서 Metadata Lock을 획득하는 것을 차단합니다.• handler:ha_prepare_inplace_alter_table()을 호출해 제약사항을 체크하고, 인덱스와 외래키의 Metadata를 업데이트합니다. Instant 알고리즘의 경우 이 단계를 수행하지 않습니다.• In-Place 알고리즘을 선택했다면, 2번 단계에서 승격했던 Lock 모드를 다시 강등합니다.• DDL 수행 도중 DML이 차단되어야 한다면 Metadata Lock을 MDL_SHARED_NO_WRITE로 강등합니다.• 그렇지 않다면, MDL_SHARED_UPGRADABLE로 강등합니다.• ALTER TABLE에 의해 요청된 변경사항을 실행하기 위해 handler::ha_inplace_alter_table()을 호출합니다. Instant 알고리즘의 경우 이 단계를 수행하지 않습니다.• 작업을 수행하는 테이블에 대한 Metadata Lock을 MDL_EXCLUSIVE로 승격합니다. ⇒ 승격 후, handler::ha_commit_inplace_alter_table()을 호출하여 테이블의 Metadata를 변경합니다.ALTER 작업이 모두 마무리 된 후 정리하는 단계입니다. 지금까지의 변경 내역을 기반으로 Data Dictionary를 업데이트하고 커밋합니다. 스토리지 엔진의 atomic DDL지원 여부에 따라 다음과 같이 마무리 작업을 진행합니다.• Atomic DDL을 지원하는 스토리지 엔진의 경우: ⇒ Old_Table과 New_Table간의 테이블 이름을 변경하는 작업을 먼저 수행하고 Data Dictionary를 업데이트, 커밋합니다.• Atomic DDL을 지원하지 않는 스토리지 엔진의 경우: ⇒ Data Dictionary를 업데이트 하고, Old_Table과 New_Table의 테이블 이름을 변경하는 작업을 수행합니다.마지막으로 지금까지 사용한 객체와 메모리를 정리하고, MDL_SHARED_READ Lock을 획득해 변경된 테이블의 Metadata를 최종 확인하며 마무리합니다.ALTER DDL문이 수행될 때 즉, Execution 단계에서 사용되는 주요 함수는 다음과 같습니다.위 함수들에 대해 간단히 알아보도록 하겠습니다.ALTER DDL과 현재 테이블 명세를 비교합니다. 테이블의 제약사항을 체크하고, 인덱스나 외래키에 대한 Metadata를 업데이트하는 역할을 합니다.여기에서 확인하는 제약사항은 다음과 같습니다.이 단계는 모든 알고리즘에서 수행되는 단계는 아닙니다. Instant 알고리즘을 사용하겠다고 한 ALTER DDL문이라면 이 단계에서 아무 작업도 수행하지 않고 바로 빠져나옵니다.소스 코드 상에서 다음과 같이 확인이 가능합니다.이 함수안에서 실제 ALTER 작업이 수행됩니다. 다음과 같은 작업들이 이 함수 안에서 수행됩니다.Instant 알고리즘을 사용하거나, 또는 In-Place 알고리즘을 사용하지만
2025.05.14
mysql
emoji
좋아요
emoji
별로에요
logo
왓챠파티@무비랜드: 콘텐츠에 진심
〈오피스〉와 〈러브레터〉에 담은 진심, 왓챠팀의 덕업일치 프로젝트 Part 1매달 셋째 주 수요일은 왓챠파티@무비랜드!2025년 2월 19일 수요일, 열한 번째 테마를 마지막으로 왓챠파티@무비랜드의 여정이 막을 내렸습니다.2024년 초, 왓챠는 성수동에 오픈을 앞둔 무비랜드에서 1년간 오프라인 왓챠파티를 진행하기로 결심합니다. 무비랜드는 30석 규모의 소극장으로, 매달 다른 큐레이터가 선정한 영화를 상영하며 이야기를 이어가는 공간이고, 왓챠파티는 왓챠 구독자라면 누구나 참여할 수 있는 다중 동시 감상 서비스로, 영화를 감상하며 실시간 채팅으로 이야기를 나눌 수 있는 기능인데요. 각자의 방법으로 ‘이야기’에 주목하는 무비랜드와 왓챠파티가 만나면 뭔가 흥미로운 일이 일어나지 않을까? 왓챠는 그렇게 첫 장기 오프라인 프로젝트를 통해 사용자와 조금 더 가까이, 더 길게 호흡할 수 있는 기회를 만들기로 합니다.이 회고는 지난 1년 동안 왓챠파티@무비랜드를 기획하고 준비하며 경험한, 현장 사진으로는 남기기 어려웠던 비하인드 스토리를 중심으로 구성되었습니다. 왓챠 무비랜드TF 구성원의 시점에서 전하는 이 이야기의 첫 편은, 콘텐츠를 향한 진심이 고스란히 담긴 테마들을 소개하는 것으로 시작합니다. 깨물면 안 아픈 손가락은 없지만, 열한 개의 테마 중 특히 애정이 깊었던 〈오피스〉와 〈러브레터〉를 중심으로 전해드립니다.-직장인이라면 5월의 시작은 살짝 더 즐겁다. 근로자의 날, 근로자의 노고를 위로하고 근무의욕을 높이기 위한 제정된 휴일로 시작되기 때문. 역시 회사는 안 가는 편이 더 좋지 않나? 그런데, 여기 출근을 더 좋아할 것 같은 사람들이 있다. 이런 직장이 있다고? 이런 동료가 존재한다고? 오피스 속 던더 미플린 스크랜턴점은 얼핏 회사보다 놀이터에 가깝다. — 〈오피스〉 테마 소개 중5월, 노동절! 오피스화창했던 5월의 셋째 주 수요일, 상영작은 〈The Office〉였습니다. 오프라인 왓챠파티 기획 초기부터 만장일치로 정해졌던 ‘확신의 테마’로 마치 정규음반의 타이틀곡처럼, 세 번째 트랙으로 준비하게 되었습니다. 콘텐츠를 향한 우리의 진심을 보여줄 차례라며, 유난히 의욕에 넘쳤던 순간들이 떠오릅니다.흥분한 덕후들의 잘 해보자 슬랙 캡쳐“상영되게 하라” — 시리즈 에피소드 엮기시리즈물의 극장 상영을 현실로 만들기 위해서는 고민이 필요했습니다. 2005년부터 2013년까지, 무려 8년의 세월에 걸쳐 방영된 아홉 개의 시즌, 총 186개의 에피소드로 이뤄진 미드 〈오피스〉를 어떻게 상영할 것인가?1회차 상영에는 몇 편을 엮을까? 어떤 에피소드를 선정해야 할까? 어떤 주제로 묶어야 팬들이 공감하는 파티를 할 수 있을까? 한 달 간격으로 새로운 테마의 상영 이벤트를 준비하는 건 매번 어렵고 시간에 쫓기는 일이었습니다. 특히나 극장 상영을 한 적 없는 오피스의 경우, 그 이상의 촘촘한 계획과 노력 그리고 확인 절차가 필요했어요.팀 내 〈오피스〉 덕후를 자처한 3명 — 알리아, 마일즈, 제인 — 을 중축으로 3시간에 가까운 첫 회의를 가졌습니다. 이야기를
5/13/2025
logo
왓챠파티@무비랜드: 콘텐츠에 진심
〈오피스〉와 〈러브레터〉에 담은 진심, 왓챠팀의 덕업일치 프로젝트 Part 1매달 셋째 주 수요일은 왓챠파티@무비랜드!2025년 2월 19일 수요일, 열한 번째 테마를 마지막으로 왓챠파티@무비랜드의 여정이 막을 내렸습니다.2024년 초, 왓챠는 성수동에 오픈을 앞둔 무비랜드에서 1년간 오프라인 왓챠파티를 진행하기로 결심합니다. 무비랜드는 30석 규모의 소극장으로, 매달 다른 큐레이터가 선정한 영화를 상영하며 이야기를 이어가는 공간이고, 왓챠파티는 왓챠 구독자라면 누구나 참여할 수 있는 다중 동시 감상 서비스로, 영화를 감상하며 실시간 채팅으로 이야기를 나눌 수 있는 기능인데요. 각자의 방법으로 ‘이야기’에 주목하는 무비랜드와 왓챠파티가 만나면 뭔가 흥미로운 일이 일어나지 않을까? 왓챠는 그렇게 첫 장기 오프라인 프로젝트를 통해 사용자와 조금 더 가까이, 더 길게 호흡할 수 있는 기회를 만들기로 합니다.이 회고는 지난 1년 동안 왓챠파티@무비랜드를 기획하고 준비하며 경험한, 현장 사진으로는 남기기 어려웠던 비하인드 스토리를 중심으로 구성되었습니다. 왓챠 무비랜드TF 구성원의 시점에서 전하는 이 이야기의 첫 편은, 콘텐츠를 향한 진심이 고스란히 담긴 테마들을 소개하는 것으로 시작합니다. 깨물면 안 아픈 손가락은 없지만, 열한 개의 테마 중 특히 애정이 깊었던 〈오피스〉와 〈러브레터〉를 중심으로 전해드립니다.-직장인이라면 5월의 시작은 살짝 더 즐겁다. 근로자의 날, 근로자의 노고를 위로하고 근무의욕을 높이기 위한 제정된 휴일로 시작되기 때문. 역시 회사는 안 가는 편이 더 좋지 않나? 그런데, 여기 출근을 더 좋아할 것 같은 사람들이 있다. 이런 직장이 있다고? 이런 동료가 존재한다고? 오피스 속 던더 미플린 스크랜턴점은 얼핏 회사보다 놀이터에 가깝다. — 〈오피스〉 테마 소개 중5월, 노동절! 오피스화창했던 5월의 셋째 주 수요일, 상영작은 〈The Office〉였습니다. 오프라인 왓챠파티 기획 초기부터 만장일치로 정해졌던 ‘확신의 테마’로 마치 정규음반의 타이틀곡처럼, 세 번째 트랙으로 준비하게 되었습니다. 콘텐츠를 향한 우리의 진심을 보여줄 차례라며, 유난히 의욕에 넘쳤던 순간들이 떠오릅니다.흥분한 덕후들의 잘 해보자 슬랙 캡쳐“상영되게 하라” — 시리즈 에피소드 엮기시리즈물의 극장 상영을 현실로 만들기 위해서는 고민이 필요했습니다. 2005년부터 2013년까지, 무려 8년의 세월에 걸쳐 방영된 아홉 개의 시즌, 총 186개의 에피소드로 이뤄진 미드 〈오피스〉를 어떻게 상영할 것인가?1회차 상영에는 몇 편을 엮을까? 어떤 에피소드를 선정해야 할까? 어떤 주제로 묶어야 팬들이 공감하는 파티를 할 수 있을까? 한 달 간격으로 새로운 테마의 상영 이벤트를 준비하는 건 매번 어렵고 시간에 쫓기는 일이었습니다. 특히나 극장 상영을 한 적 없는 오피스의 경우, 그 이상의 촘촘한 계획과 노력 그리고 확인 절차가 필요했어요.팀 내 〈오피스〉 덕후를 자처한 3명 — 알리아, 마일즈, 제인 — 을 중축으로 3시간에 가까운 첫 회의를 가졌습니다. 이야기를
2025.05.13
emoji
좋아요
emoji
별로에요
logo
테스트를 부탁해 - Firebase App Testing Agent 체험기
Firebase가 최근 UI 테스트 자동화를 위한 신규 기능 App Testing Agent를 공개했습니다.에이닷 클라이언트 개발팀에서도 UI 테스트를 활발히 진행하고 있던 터라 자연스럽게 눈길이 끌렸습니다.궁금증을 못 참고 바로 몇 가지 시나리오를 실행해 보며 기능을 체험했고 동시에 백그라운드에서 무슨 일이 벌어지는지도 슬쩍 들여다봤습니다.이 글에서는 그 과정에서 얻은 실제 테스트 결과와 내부 로직을 추측해 본 이야기를 가볍게 풀어 보려 합니다.Firebase App Testing Agent는 Gemini in Firebase가 구동하는 AI 기반 UI 테스트 자동화 에이전트입니다.“로그인 플로우를 검증해 줘”처럼 자연어로 목표만 입력하면 에이전트가 앱 화면을 해석하고 버튼, 제스처 등 사용자 행동을 시뮬레이션해 테스트 시나리오를 생성하고 실행합니다.완료 후에는 각 단계의 스크린샷과 로그가 포함된 리포트를 제공해 문제 지점을 한눈에 파악할 수 있도록 돕습니다.두 가지의 테스트 실행 방식을 제공하며 이 글에서는 'AI 가이드 테스트'에 초점을 맞춰 보려고 합니다.• None 에이전트는 자연어로 작성한 테스트 목표를 해석해 앱의 UI 트리를 탐색하고, 실제 사용자 동작을 모사해 시나리오를 자동 실행합니다.• None 테스트는 단계별 시퀀스로 구성되며, 각 단계마다 목표(Goal), 힌트(Hint), 성공 판정 기준(Success Criteria)을 가이드할 수 있습니다.• None 이 글을 작성하는 2025년 4월 25일 현재, 테스트 실행에는 Gemini-2.0-Flash-001 모델이 사용되고 있습니다.현재 에이닷 클라이언트 팀에서 진행하고 있는 것과 동일한 수준의 테스트 시나리오를 작성하고 실행해보면서 App Testing Agent의 가능성과 한계에 대해서 알아보겠습니다.로그인 후 대화방에 진입했을 때 임의의 새 메시지가 정상적으로 노출되는지를 확인하는 간단한 테스트 케이스를 작성하고,이를 실행한 뒤 결과를 확인해보겠습니다.Firebase Console의 App Distribution 메뉴에서 ‘테스트 사례’ 탭으로 이동하면, 테스트를 생성하거나 실행할 수 있는 화면에 진입하게 됩니다.화면에 진입한 뒤 '새 테스트 사례' 버튼을 클릭하면 새로운 테스트 항목을 직접 등록할 수 있습니다.테스트 제목을 지정할 수 있으며 목표가 하나인 경우 비워두면 목표가 테스트 제목으로 사용됩니다.에이전트로 수행할 작업은 가급적 한 문장 이내로 간단히 작성하는 것이 좋습니다. 복잡한 동작일 경우 단계를 나누어 작성하면 오작동 가능성을 줄일 수 있습니다.Gemini가 앱을 이해하고 탐색하는 데 도움이 되는 추가 정보를 제공합니다.예를 들면, '온보딩 화면을 지나 이동합니다. 팝업을 모두 닫습니다. 로그인하지 않습니다.'와 같은 정보입니다.테스트 목표를 달성하는 데 필요한 예상 동작 또는 앱 상태를 설명합니다.예를 들면, '기본 앱 홈 페이지가 화면에 표시되고 모든 이미지가 로드되었으며 오류가 표시되지 않습니다.'와 같은 내용입니다.인트로 화면에서 '바로 시작하기' 버튼을 클릭해서 로그인 선택 화면으로 진입할 수 있도록 목표를 설정했습니다.T ID로 로그인 화면으로 진입하도록 목표를 설정했습니다. Step2에서는 목표를 통해 버튼을 누르도록 지시하지 않고 의도한 행동을 할 수 있도록 힌트를 제공했습니다.아이디랑 비밀번호 입력 후, 로그인 버튼을 누르도록 했습니다.버튼의 일부분만 보이는 경우 클릭을 하지 않는 경우가 있어서 버튼 전체가 보일 때까지 스크롤을 하도록 힌트를 제공했습니다.대화방 진입 후 임의의 메시지가 출력되는지 확인하도록 목표를 설정 했습니다.테스트 사례 화면에서 '테스트 실행' 버튼을 누르면, 테스트 실행에 필요한 설정을 진행할 수 있는 화면으로 전환됩니다.테스트 실행 시 제공되는 두 가지 유형인 'AI 가이드 테스트'와 '무작위 크롤링 테스트' 중 하나를 선택해 테스트를 수행할 수 있습니다.테스트 실행 시 사용할 기기를 선택할 수 있으며, 약 80개의 실제 기기와 에뮬레이터가 준비되어 있어 다양한 환경에서 테스트가 가능합니다.로그인이 필요한 앱이라면 테스트 실행 시 사용할 아이디와 비밀번호를 사전에 입력해둘 수 있습니다.테스트를 실행한 뒤에는 App Distribution의 해당 릴리스 버전에서 ‘앱 테스트 에이전트’ 탭을 통해 테스트 진행 상황과 결과를 실시간으로 확인할 수 있습니다.App Testing Agent는 목표대로 인트로 화면에서 ‘바로 시작하기’ 버튼을 클릭한 후 로딩 완료를 위해 10초 동안 대기했습니다.App Testing Agent는 로그인 선택 화면에서 ‘T ID로 로그인하기’ 버튼을 클릭해 T ID 로그인 화면으로 이동했으며, 해당 화면 진입 여부를 기준으로 테스트 결과를 Pass로 판단했습니다.App Testing Agent는 테스트 시작 시 설정한 아이디와 비밀번호를 입력해 로그인을 진행했습니다.이후, 에이닷 타이틀이 표시된 메인 화면에 정상적으로 진입한 것을 확인하고 이를 성공 기준으로 판단하여 테스트 결과를 Pass로 처리했습니다.다소 인상적이었던 점은 사전에 존재 여부를 명시하지 않았던 권한 팝업이 표시되었음에도 불구하고App Testing Agent가 이를 자동으로 인식하고 확인 버튼을 눌러 정상적으로 목표를 달성했다는 점입니다. 🤩일반적인 UI 테스트에서는 예상되지 않은 팝업이나 UI 변화로 인해 다음 단계로 진행하지 못하고 테스트가 실패하는 경우가 많습니다.임의의 메시지가 출력될 때까지 10초간 대기하도록 가이드했기 때문에 App Testing Agent는 해당 시간 동안 대기합니다.테스트 중 예상치 못한 돌발 상황으로 위치 서비스 관련 시스템 팝업이 노출되었지만 App Testing Agent는 ‘아니오’ 버튼을 스스로 인식하고 클릭하여 팝업을 정상적으로 닫았습니다.테스트 목표였던 임의의 메시지 출력을 감지하고 그 텍스트 내용을 정확히 확인한 후 Pass로 처리하는 과정을 보면, App Testing Agent의 UI 분석 능력이 상당히 정교하다는 점을 알 수 있습니다.‘에이전트 뷰 표시’를 켜면 테스트 중 에이전트가 접근성 정보를
5/13/2025
logo
테스트를 부탁해 - Firebase App Testing Agent 체험기
Firebase가 최근 UI 테스트 자동화를 위한 신규 기능 App Testing Agent를 공개했습니다.에이닷 클라이언트 개발팀에서도 UI 테스트를 활발히 진행하고 있던 터라 자연스럽게 눈길이 끌렸습니다.궁금증을 못 참고 바로 몇 가지 시나리오를 실행해 보며 기능을 체험했고 동시에 백그라운드에서 무슨 일이 벌어지는지도 슬쩍 들여다봤습니다.이 글에서는 그 과정에서 얻은 실제 테스트 결과와 내부 로직을 추측해 본 이야기를 가볍게 풀어 보려 합니다.Firebase App Testing Agent는 Gemini in Firebase가 구동하는 AI 기반 UI 테스트 자동화 에이전트입니다.“로그인 플로우를 검증해 줘”처럼 자연어로 목표만 입력하면 에이전트가 앱 화면을 해석하고 버튼, 제스처 등 사용자 행동을 시뮬레이션해 테스트 시나리오를 생성하고 실행합니다.완료 후에는 각 단계의 스크린샷과 로그가 포함된 리포트를 제공해 문제 지점을 한눈에 파악할 수 있도록 돕습니다.두 가지의 테스트 실행 방식을 제공하며 이 글에서는 'AI 가이드 테스트'에 초점을 맞춰 보려고 합니다.• None 에이전트는 자연어로 작성한 테스트 목표를 해석해 앱의 UI 트리를 탐색하고, 실제 사용자 동작을 모사해 시나리오를 자동 실행합니다.• None 테스트는 단계별 시퀀스로 구성되며, 각 단계마다 목표(Goal), 힌트(Hint), 성공 판정 기준(Success Criteria)을 가이드할 수 있습니다.• None 이 글을 작성하는 2025년 4월 25일 현재, 테스트 실행에는 Gemini-2.0-Flash-001 모델이 사용되고 있습니다.현재 에이닷 클라이언트 팀에서 진행하고 있는 것과 동일한 수준의 테스트 시나리오를 작성하고 실행해보면서 App Testing Agent의 가능성과 한계에 대해서 알아보겠습니다.로그인 후 대화방에 진입했을 때 임의의 새 메시지가 정상적으로 노출되는지를 확인하는 간단한 테스트 케이스를 작성하고,이를 실행한 뒤 결과를 확인해보겠습니다.Firebase Console의 App Distribution 메뉴에서 ‘테스트 사례’ 탭으로 이동하면, 테스트를 생성하거나 실행할 수 있는 화면에 진입하게 됩니다.화면에 진입한 뒤 '새 테스트 사례' 버튼을 클릭하면 새로운 테스트 항목을 직접 등록할 수 있습니다.테스트 제목을 지정할 수 있으며 목표가 하나인 경우 비워두면 목표가 테스트 제목으로 사용됩니다.에이전트로 수행할 작업은 가급적 한 문장 이내로 간단히 작성하는 것이 좋습니다. 복잡한 동작일 경우 단계를 나누어 작성하면 오작동 가능성을 줄일 수 있습니다.Gemini가 앱을 이해하고 탐색하는 데 도움이 되는 추가 정보를 제공합니다.예를 들면, '온보딩 화면을 지나 이동합니다. 팝업을 모두 닫습니다. 로그인하지 않습니다.'와 같은 정보입니다.테스트 목표를 달성하는 데 필요한 예상 동작 또는 앱 상태를 설명합니다.예를 들면, '기본 앱 홈 페이지가 화면에 표시되고 모든 이미지가 로드되었으며 오류가 표시되지 않습니다.'와 같은 내용입니다.인트로 화면에서 '바로 시작하기' 버튼을 클릭해서 로그인 선택 화면으로 진입할 수 있도록 목표를 설정했습니다.T ID로 로그인 화면으로 진입하도록 목표를 설정했습니다. Step2에서는 목표를 통해 버튼을 누르도록 지시하지 않고 의도한 행동을 할 수 있도록 힌트를 제공했습니다.아이디랑 비밀번호 입력 후, 로그인 버튼을 누르도록 했습니다.버튼의 일부분만 보이는 경우 클릭을 하지 않는 경우가 있어서 버튼 전체가 보일 때까지 스크롤을 하도록 힌트를 제공했습니다.대화방 진입 후 임의의 메시지가 출력되는지 확인하도록 목표를 설정 했습니다.테스트 사례 화면에서 '테스트 실행' 버튼을 누르면, 테스트 실행에 필요한 설정을 진행할 수 있는 화면으로 전환됩니다.테스트 실행 시 제공되는 두 가지 유형인 'AI 가이드 테스트'와 '무작위 크롤링 테스트' 중 하나를 선택해 테스트를 수행할 수 있습니다.테스트 실행 시 사용할 기기를 선택할 수 있으며, 약 80개의 실제 기기와 에뮬레이터가 준비되어 있어 다양한 환경에서 테스트가 가능합니다.로그인이 필요한 앱이라면 테스트 실행 시 사용할 아이디와 비밀번호를 사전에 입력해둘 수 있습니다.테스트를 실행한 뒤에는 App Distribution의 해당 릴리스 버전에서 ‘앱 테스트 에이전트’ 탭을 통해 테스트 진행 상황과 결과를 실시간으로 확인할 수 있습니다.App Testing Agent는 목표대로 인트로 화면에서 ‘바로 시작하기’ 버튼을 클릭한 후 로딩 완료를 위해 10초 동안 대기했습니다.App Testing Agent는 로그인 선택 화면에서 ‘T ID로 로그인하기’ 버튼을 클릭해 T ID 로그인 화면으로 이동했으며, 해당 화면 진입 여부를 기준으로 테스트 결과를 Pass로 판단했습니다.App Testing Agent는 테스트 시작 시 설정한 아이디와 비밀번호를 입력해 로그인을 진행했습니다.이후, 에이닷 타이틀이 표시된 메인 화면에 정상적으로 진입한 것을 확인하고 이를 성공 기준으로 판단하여 테스트 결과를 Pass로 처리했습니다.다소 인상적이었던 점은 사전에 존재 여부를 명시하지 않았던 권한 팝업이 표시되었음에도 불구하고App Testing Agent가 이를 자동으로 인식하고 확인 버튼을 눌러 정상적으로 목표를 달성했다는 점입니다. 🤩일반적인 UI 테스트에서는 예상되지 않은 팝업이나 UI 변화로 인해 다음 단계로 진행하지 못하고 테스트가 실패하는 경우가 많습니다.임의의 메시지가 출력될 때까지 10초간 대기하도록 가이드했기 때문에 App Testing Agent는 해당 시간 동안 대기합니다.테스트 중 예상치 못한 돌발 상황으로 위치 서비스 관련 시스템 팝업이 노출되었지만 App Testing Agent는 ‘아니오’ 버튼을 스스로 인식하고 클릭하여 팝업을 정상적으로 닫았습니다.테스트 목표였던 임의의 메시지 출력을 감지하고 그 텍스트 내용을 정확히 확인한 후 Pass로 처리하는 과정을 보면, App Testing Agent의 UI 분석 능력이 상당히 정교하다는 점을 알 수 있습니다.‘에이전트 뷰 표시’를 켜면 테스트 중 에이전트가 접근성 정보를
2025.05.13
emoji
좋아요
emoji
별로에요
Copyright © 2025. Codenary All Rights Reserved.